git @ Cat's Eye Technologies Iphigeneia / master src / Parser.hs
master

Tree @master (Download .tar.gz)

Parser.hs @masterraw · history · blame

--
-- Copyright (c)2007 Chris Pressey, Cat's Eye Technologies.
-- All rights reserved.
--
-- Redistribution and use in source and binary forms, with or without
-- modification, are permitted provided that the following conditions
-- are met:
--
--   1. Redistributions of source code must retain the above copyright
--      notices, this list of conditions and the following disclaimer.
--   2. Redistributions in binary form must reproduce the above copyright
--      notices, this list of conditions, and the following disclaimer in
--      the documentation and/or other materials provided with the
--      distribution.
--   3. Neither the names of the copyright holders nor the names of their
--      contributors may be used to endorse or promote products derived
--      from this software without specific prior written permission. 
--
-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-- ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES INCLUDING, BUT NOT
-- LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
-- FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
-- COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
-- INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
-- BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-- LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
-- CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
-- LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
-- ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-- POSSIBILITY OF SUCH DAMAGE.
--

-----------------------------------------------------------------------
-- ============================== Parser =========================== --
-----------------------------------------------------------------------

module Parser where

import Scanner
import Primitive
import AST

--
-- Utility
--

expect [] l = l
expect (x:xs) (y:ys)
    | x == y =
        expect xs ys

--
-- Statement ::= "if" BoolExpr "then" Statement "else" Statement
--             | "while" BoolExpr "do" Statement
--             | "begin" Statement {";" Statement} "end"
--             | "var" VarName "in" Statement
--             | "print" NumExpr
--             | VarName ":=" NumExpr
--

parseStatement (IfToken:tokens) =
    let
        (tokens2, be) = parseBoolExpr tokens
        tokens3 = expect [ThenToken] tokens2
        (tokens4, s1) = parseStatement tokens3
        tokens5 = expect [ElseToken] tokens4
        (tokens6, s2) = parseStatement tokens5
    in
        (tokens6, IfStmt be s1 s2)

parseStatement (VarToken:tokens) =
    let
        ((Ident ident):tokens2) = tokens
        v = VarName ident
        tokens3 = expect [InToken] tokens2
        (tokens4, s) = parseStatement tokens3
    in
        (tokens4, Var v s)

parseStatement (WhileToken:tokens) =
    let
        (tokens2, be) = parseBoolExpr tokens
        tokens3 = expect [DoToken] tokens2
        (tokens4, s) = parseStatement tokens3
    in
        (tokens4, While be s)

parseStatement (PrintToken:tokens) =
    let
        (tokens2, ne) = parseNumExpr tokens
    in
        (tokens2, Print ne)

parseStatement ((Ident s):tokens) =
    let
        v = VarName s
        tokens2 = expect [BecomesToken] tokens
        (tokens3, ne) = parseNumExpr tokens2
    in
        (tokens3, Assign v ne)

parseStatement (BeginToken:tokens) =
    let
        (tokens2, stmtList) = parseStmtList tokens []
    in
        (tokens2, Block (reverse stmtList))

parseStmtList tokens acc =
    let
        (tokens2, s) = parseStatement tokens
    in
        case tokens2 of
            (StmtSepToken:rest) ->
                parseStmtList rest (s : acc)
            (EndToken:rest) ->
                (rest, (s:acc))

--
-- NumExpr ::= AddExpr.
--

parseNumExpr tokens = parseAddExpr tokens

--
-- AddExpr ::= MulExpr {("+" | "-") MulExpr}.
--

parseAddExpr tokens =
    let
        (tokens2, lhs) = parseMulExpr tokens
    in
        parseAddExprTail tokens2 lhs

parseAddExprTail (AddToken:tokens) lhs =
    let
        (tokens2, rhs) = parseMulExpr tokens
        newLhs = NumOp Add lhs rhs
    in
        parseAddExprTail tokens2 newLhs

parseAddExprTail (SubtractToken:tokens) lhs =
    let
        (tokens2, rhs) = parseMulExpr tokens
        newLhs = NumOp Subtract lhs rhs
    in
        parseAddExprTail tokens2 newLhs

parseAddExprTail tokens e = (tokens, e)

--
-- MulExpr ::= Primitive {("*" | "/") Primitive}.
--

parseMulExpr tokens =
    let
        (tokens2, lhs) = parsePrimitive tokens
    in
        parseMulExprTail tokens2 lhs

parseMulExprTail (MultiplyToken:tokens) lhs =
    let
        (tokens2, rhs) = parsePrimitive tokens
        newLhs = NumOp Multiply lhs rhs
    in
        parseMulExprTail tokens2 newLhs

parseMulExprTail (DivideToken:tokens) lhs =
    let
        (tokens2, rhs) = parsePrimitive tokens
        newLhs = NumOp Divide lhs rhs
    in
        parseMulExprTail tokens2 newLhs

parseMulExprTail tokens e = (tokens, e)

--
-- Primitive ::= "(" NumExpr ")"
--             | "if" BoolExpr "then" NumExpr "else" NumExpr
--             | "let" VarName "=" NumExpr "in" NumExpr
--             | "valueof" VarName "in" Statement
--             | "loop" NumExpr
--             | "repeat"
--             | "input" VarName "in" NumExpr
--             | VarName
--             | NumConst.
--

parsePrimitive (OpenParenToken:tokens) =
    let
        (tokens2, ne) = parseNumExpr tokens
        tokens3 = expect [CloseParenToken] tokens2
    in
        (tokens3, ne)

parsePrimitive (IfToken:tokens) =
    let
        (tokens2, be) = parseBoolExpr tokens
        tokens3 = expect [ThenToken] tokens2
        (tokens4, e1) = parseNumExpr tokens3
        tokens5 = expect [ElseToken] tokens4
        (tokens6, e2) = parseNumExpr tokens5
    in
        (tokens6, IfExpr be e1 e2)

parsePrimitive (LetToken:tokens) =
    let
        ((Ident ident):tokens2) = tokens
        v = VarName ident
        tokens3 = expect [EqualToken] tokens2
        (tokens4, e1) = parseNumExpr tokens3
        tokens5 = expect [InToken] tokens4
        (tokens6, e2) = parseNumExpr tokens5
    in
        (tokens6, Let v e1 e2)

parsePrimitive (ValueOfToken:tokens) =
    let
        ((Ident ident):tokens2) = tokens
        v = VarName ident
        tokens3 = expect [InToken] tokens2
        (tokens4, s) = parseStatement tokens3
    in
        (tokens4, ValueOf v s)

parsePrimitive (LoopToken:tokens) =
    let
        (tokens2, e) = parseNumExpr tokens
    in
        (tokens2, Loop e)

parsePrimitive (RepeatToken:tokens) = (tokens, Repeat)

parsePrimitive (InputToken:tokens) =
    let
        ((Ident ident):tokens2) = tokens
        v = VarName ident
        tokens3 = expect [InToken] tokens2
        (tokens4, ne) = parseNumExpr tokens3
    in
        (tokens4, Input v ne)

parsePrimitive ((IntLit i):tokens) = (tokens, NumConst i)

parsePrimitive ((Ident s):tokens) = (tokens, (VarRef (VarName s)))

--
-- BoolExpr ::= RelExpr {("&" | "|") RelExpr}
--            | "not" BoolExpr
--            | "(" BoolExpr ")".
--

parseBoolExpr (NotToken:tokens) =
    let
        (tokens2, be) = parseBoolExpr tokens
    in
        (tokens2, Not be)

parseBoolExpr (OpenParenToken:tokens) =
    let
        (tokens2, be) = parseBoolExpr tokens
        tokens3 = expect [CloseParenToken] tokens2
    in
        (tokens3, be)

parseBoolExpr tokens =
    let
        (tokens2, lhs) = parseRelExpr tokens
    in
        parseBoolExprTail tokens2 lhs

parseBoolExprTail (AndToken:tokens) lhs =
    let
        (tokens2, rhs) = parseRelExpr tokens
        newLhs = BoolOp And lhs rhs
    in
        parseBoolExprTail tokens2 newLhs

parseBoolExprTail (OrToken:tokens) lhs =
    let
        (tokens2, rhs) = parseRelExpr tokens
        newLhs = BoolOp Or lhs rhs
    in
        parseBoolExprTail tokens2 newLhs

parseBoolExprTail tokens be = (tokens, be)

--
-- RelExpr ::= NumExpr (">" | "<" | ">=" | "<=" | "=" | "/=") NumExpr.
--

parseRelExpr tokens =
    let
        (tokens2, lhs) = parseNumExpr tokens
        (tokens3, relOp) = relOpForSym tokens2
        (tokens4, rhs) = parseNumExpr tokens3
    in
        (tokens4, RelOp relOp lhs rhs)

relOpForSym (GreaterThanToken:tokens)        = (tokens, GreaterThan)
relOpForSym (GreaterThanOrEqualToken:tokens) = (tokens, GreaterThanOrEqual)
relOpForSym (EqualToken:tokens)              = (tokens, Equal)
relOpForSym (NotEqualToken:tokens)           = (tokens, NotEqual)
relOpForSym (LessThanToken:tokens)           = (tokens, LessThan)
relOpForSym (LessThanOrEqualToken:tokens)    = (tokens, LessThanOrEqual)

--
-- Driver
--

parse string = parseStatement (tokenize string)