Search code examples
haskellparsec

Using statement parsers recursively in Parsec


I have an ifelse parser than should be able to parse embedded ifelse statements in a
java-like language, but it is not recognizing the inner ifelse. Also, if someone could show me a better way to handle the whitespace in the ifelseParser I would appreciate it.

if (~(position > 16)) { 
                 if (~((value & mask) = 0)) { 
                       do Memory.poke(8000 + position, 1); 
                 } else { 
                       do Memory.poke(8000 + position, 0); 
                 } 
} else { let loop = false; } 

The ifelseParser is not picking up whole expression, missing inner if-else statement.

 Right (IfElse "if" (ExprOpTerm (Unary "~" (ExprOpTerm (SimpleExpr (ExprOpTerm 
(VarTerm "position") [(">",IntConst 16)])) [])) []) [Let "let" "loop" 
(ExprOpTerm (KeywordTerm "false") [])] "else" [Let "let" "loop" 
(ExprOpTerm (KeywordTerm "false") [])])  


data Statement = Let Keyword VarName Expr                                                                                                                                                                                                     
               | SubLet Keyword VarName Expr Expr                                                                                                                                                                                             
               | If Keyword Expr [Statement]                                                                                                                                                                                                  
               | IfElse Keyword Expr [Statement] Keyword [Statement]                                                                                                                                                                          
               | While Keyword Expr [Statement]                                                                                                                                                                                               
               | Do Keyword SubCall                                                                                                                                                                                                           
               | ReturnExp Keyword Expr                                                                                                                                                                                                       
               | NoReturn                                                                                                                                                                                                                     
               | Return Keyword deriving (Show)   

ifelseParser :: Parser Statement   
ifelseParser = do                                                                                                                                                                                                                             
  whiteSpace                                                                                                                                                                                                                                  
  iff <- reserved' "if"                                                                                                                                                                                                                       
  whiteSpace                                                                                                                                                                                                                                  
  char '('                                                                                                                                                                                                                                    
  whiteSpace                                                                                                                                                                                                                                  
  expr <- getExprParser                                                                                                                                                                                                                       
  whiteSpace                                                                                                                                                                                                                                  
  char ')'                                                                                                                                                                                                                                    
  whiteSpace                                                                                                                                                                                                                                  
  char '{'                                                                                                                                                                                                                                    
  whiteSpace                                                                                                                                                                                                                                  
  stmt <- many1 statementsParser                                                                                                                                                                                                              
  whiteSpace                                                                                                                                                                                                                                  
  char '}'                                                                                                                                                                                                                                    
  whiteSpace                                                                                                                                                                                                                                  
  el <- reserved' "else"                                                                                                                                                                                                                      
  whiteSpace                                                                                                                                                                                                                                  
  char '{'                                                                                                                                                                                                                                    
  whiteSpace                                                                                                                                                                                                                                  
  stmts <- many1 statementsParser                                                                                                                                                                                                              
  whiteSpace                                                                                                                                                                                                                                  
  char '}'                                                                                                                                                                                                                                    
  whiteSpace                                                                                                                                                                                                                                  
  return $ IfElse iff expr stmt el stmts         

statementsParser :: Parser Statement                                                                                                                                                                                                          
statementsParser = do                                                                                                                                                                                                                         
  try subLetParser <|>  try letParser <|> try whileParser <|>                                                                                                                                                                                 
    try ifelseParser <|> try ifParser <|>                                                                                                                                                                                                     
    try doParser <|> (try returnExpParser <|> try returnParser)                                                                                                                                                                               


subRoutineParser :: Parser Term                                                                                                                                                                                                               
subRoutineParser = do                                                                                                                                                                                                                         
  whiteSpace                                                                                                                                                                                                                                  
  sub <- subCallParser                                                                                                                                                                                                                        
  return $ Subroutine sub                                                                                                                                                                                                                     

getExprParser :: Parser Expr                                                                                                                                                                                                                  
getExprParser = do                                                                                                                                                                                                                            
  whiteSpace                                                                                                                                                                                                                                  
  term <- (try subRoutineParser <|>                                                                                                                                                                                                           
                 try intVal <|>                                                                                                                                                                                                               
                 try stringVal <|>                                                                                                                                                                                                            
                 try keyWordVal <|>                                                                                                                                                                                                           
                 try varExpParser <|>                                                                                                                                                                                                         
                 try varVal <|>                                                                                                                                                                                                               
                 try simpleExpr <|>                                                                                                                                                                                                           
                 try unaryOpExpr)                                                                                                                                                                                                             
  op <- many getExpP                                                                                                                                                                                                                          
  return $ ExprOpTerm term op                                                                                                                                                                                                                 

getExpP :: Parser (String,Term)                                                                                                                                                                                                               
getExpP = do                                                                                                                                                                                                                                  
  whiteSpace                                                                                                                                                                                                                                  
  op <- choice $ map string ops                                                                                                                                                                                                               
  term <- (try subRoutineParser <|>                                                                                                                                                                                                           
          try intVal <|>                                                                                                                                                                                                                      
          try stringVal <|>                                                                                                                                                                                                                   
          try keyWordVal <|>                                                                                                                                                                                                                  
          try varExpParser <|>                                                                                                                                                                                                                
          try varVal <|>                                                                                                                                                                                                                      
          try simpleExpr <|>                                                                                                                                                                                                                  
          try unaryOpExpr)                                                                                                                                                                                                                    
  return $ (op,term)

Solution

  • You are using the variable stmt to hold both the "if" statements and the "else" statements. So when you do this:

     return $ IfElse iff expr stmt el stmt           
    

    ... I would guess that stmt only contains the most recently assigned value, which is from the "else" portion.