COMP3161/9164 Concepts of Programming Languages
Term 3, 2025

Completed Parser

This is the completed parser implementation.


-- Import character-related functions from the standard library.
import Data.Char


-- The goal is to lex and parse a string like this
example_string :: String
example_string = "(3 + (4 * 5))"


-- The token type
data Token = Lit Int
  | LParen | RParen
  | Plus | Times
  deriving Show

-- The expression type
data Arith_Expr = Num Int
    | PlusE Arith_Expr Arith_Expr
    | TimesE Arith_Expr Arith_Expr
  deriving Show


-- A lexer, on the same scheme as last time.
lexer :: String -> [Token]
lexer ('(' : cs) = LParen : lexer cs
lexer (')' : cs) = RParen : lexer cs
lexer ('+' : cs) = Plus : lexer cs
lexer ('*' : cs) = Times : lexer cs
lexer [] = []
lexer (c : cs) = if isSpace c then lexer cs
  else if isDigit c
  then let (int_string, rest) = break (not . isDigit) (c : cs)
       in (Lit (read int_string) : lexer rest)
  else error ("couldn't lex this: " ++ show (c : cs))


-- If we look at our rules, we see that all the rules for parsing an
-- S-sum-expression begin by parsing a P-product-expression. Then they either
-- continue the sum with a plus token or just promote the P expression.
parser_sexpr :: [Token] -> (Arith_Expr, [Token])
parser_sexpr toks =
  let (expr, toks2) = parser_pexpr toks
  in case toks2 of
    Plus : toks3 ->
      let (expr2, toks4) = parser_sexpr toks3
      in (PlusE expr expr2, toks4)
    _ -> (expr, toks2)


-- Likewise P-product-expressions start with an atom, and then optionally
-- add a times token and another argument after it.
parser_pexpr :: [Token] -> (Arith_Expr, [Token])
parser_pexpr toks =
  let (expr, toks2) = parser_atom toks
  in case toks2 of
    Times : toks3 ->
      let (expr2, toks4) = parser_pexpr toks3
      in (TimesE expr expr2, toks4)
    _ -> (expr, toks2)

-- Finally, atoms are either literals, and just that, or they are an open
-- parenthesis followed by a valid expression followed by a close parenthesis.
parser_atom :: [Token] -> (Arith_Expr, [Token])
parser_atom (Lit i : toks) = (Num i, toks)
parser_atom (LParen : toks) =
    let (expr, toks2) = parser_sexpr toks
    in case toks2 of
      (RParen : toks3) -> (expr, toks3)
      _ -> error ("parser_atom: expecting ')', got: " ++ show toks2)
parser_atom toks = error ("parser_atom: got: " ++ show toks)




2025-12-05 Fri 11:50

Announcements RSS