def parse_imp(input): # parse a string into an element of the abstract representation # Grammar: # # <expr> ::= <integer> # true # false # <identifier> # ( if <expr> <expr> <expr> ) # ( function ( <name ... ) <expr> ) # ( <expr> <expr> ... ) # # <decl> ::= var name = expr ; # # <stmt> ::= if <expr> <stmt> else <stmt> # while <expr> <stmt> # name <- <expr> ; # print <expr> ; # <block> # # <block> ::= { <decl> ... <stmt> ... } # # <toplevel> ::= <decl> # <stmt> # idChars = alphas + "_+*-?!=<>+" QUOTE = Literal('"') INTERNAL_QUOTE = QUOTE.copy().leaveWhitespace() pIDENTIFIER = Word(idChars, idChars + "0123456789") #### NOTE THE DIFFERENCE pIDENTIFIER.setParseAction( lambda result: EPrimCall(oper_deref, [EId(result[0])])) # A name is like an identifier but it does not return an EId... pNAME = Word(idChars, idChars + "0123456789") #| Keyword("&\"") | Keyword("&\'") pNAMES = ZeroOrMore(pNAME) pNAMES.setParseAction(lambda result: [result]) pINTEGER = Word("0123456789") pINTEGER.setParseAction(lambda result: EValue(VInteger(int(result[0])))) QUOTE = Literal("&\"") | Literal("&\'") pSTRING = Literal('"') + ZeroOrMore( Combine(Word(idChars + "0123456789'" + " ") | QUOTE)) + Literal('"') pSTRING.setParseAction(lambda result: EValue(VString(str(result[1:-1])))) pBOOLEAN = Keyword("true") | Keyword("false") pBOOLEAN.setParseAction( lambda result: EValue(VBoolean(result[0] == "true"))) pEXPR = Forward() pEXPRS = ZeroOrMore(pEXPR) pEXPRS.setParseAction(lambda result: [result]) pIF = "(" + Keyword("if") + pEXPR + pEXPR + pEXPR + ")" pIF.setParseAction(lambda result: EIf(result[2], result[3], result[4])) def mkFunBody(params, body): bindings = [(p, ERefCell(EId(p))) for p in params] return ELet(bindings, body) def letToFun(result): func = result[5] binds = result[3] params = [] vals = [] for p, v in binds: params.append(p) vals.append(v) return ECall(EFunction(params, func), vals) pFUN = "(" + Keyword("function") + "(" + pNAMES + ")" + pEXPR + ")" pFUN.setParseAction( lambda result: EFunction(result[3], mkFunBody(result[3], result[5]))) pBINDING = "(" + pNAME + pEXPR + ")" pBINDING.setParseAction(lambda result: (result[1], result[2])) pBINDINGS = OneOrMore(pBINDING) pBINDINGS.setParseAction(lambda result: [result]) pLET = "(" + Keyword("let") + "(" + pBINDINGS + ")" + pEXPR + ")" pLET.setParseAction(letToFun) pCALL = "(" + pEXPR + pEXPRS + ")" pCALL.setParseAction(lambda result: ECall(result[1], result[2])) pARRAY = "(" + Keyword("new-array") + pEXPR + ")" pARRAY.setParseAction(lambda result: EArray(result[2])) pINDEX = Keyword("index") + pINTEGER pCALL.setParseAction(lambda result: ECall(result[1], result[2])) pWITH = "(" + Keyword("with") + pEXPR + pEXPR + ")" pWITH.setParseAction(lambda result: EWithObj(result[2], result[3])) pEXPR << (pINTEGER | pARRAY | pSTRING | pWITH | pBOOLEAN | pIDENTIFIER | pIF | pLET | pFUN | pCALL) pDECL_VAR = "var" + pNAME + "=" + pEXPR + ";" pDECL_VAR.setParseAction(lambda result: (result[1], result[3])) pSTMT = Forward() pDECL_PROCEDURE = "procedure" + pNAME + "(" + pNAMES + ")" + pSTMT pDECL_PROCEDURE.setParseAction(lambda result: (result[ 1], EProcedure(result[3], mkFunBody(result[3], result[5])))) # hack to get pDECL to match only PDECL_VAR (but still leave room # to add to pDECL later) pDECL = (pDECL_VAR | pDECL_PROCEDURE | NoMatch() | ";") pDECLS = ZeroOrMore(pDECL) pDECLS.setParseAction(lambda result: [result]) pSTMT_IF_1 = "if" + pEXPR + pSTMT + "else" + pSTMT pSTMT_IF_1.setParseAction( lambda result: EIf(result[1], result[2], result[4])) pSTMT_IF_2 = "if" + pEXPR + pSTMT pSTMT_IF_2.setParseAction( lambda result: EIf(result[1], result[2], EValue(VBoolean(True)))) pSTMT_WHILE = "while" + pEXPR + pSTMT pSTMT_WHILE.setParseAction(lambda result: EWhile(result[1], result[2])) pSTMT_FOR = "for" + pDECLS + pEXPR + ";" + pSTMT + pSTMT pSTMT_FOR.setParseAction( lambda result: EFor(result[1], result[2], result[4], result[5])) pSTMT_PRINT = "print" + pEXPR + ";" pSTMT_PRINT.setParseAction( lambda result: EPrimCall(oper_print, [result[1]])) pSTMT_UPDATE_ARR = pNAME + "[" + pINTEGER + "]" + "<-" + pEXPR + ";" pSTMT_UPDATE_ARR.setParseAction(lambda result: EPrimCall( oper_update_arr, [EId(result[0]), result[2], result[5]])) pSTMT_UPDATE = pNAME + "<-" + pEXPR + ";" pSTMT_UPDATE.setParseAction( lambda result: EPrimCall(oper_update, [EId(result[0]), result[2]])) pSTMT_PROCEDURE = pEXPR + "(" + pEXPRS + ")" + ";" pSTMT_PROCEDURE.setParseAction(lambda result: ECall(result[0], result[2])) pSTMTS = ZeroOrMore(pSTMT) pSTMTS.setParseAction(lambda result: [result]) def mkBlock(decls, stmts): bindings = [(n, ERefCell(expr)) for (n, expr) in decls] return ELet(bindings, EDo(stmts)) pSTMT_BLOCK = "{" + pDECLS + pSTMTS + "}" pSTMT_BLOCK.setParseAction(lambda result: mkBlock(result[1], result[2])) pSTMT << (pSTMT_IF_1 | pSTMT_IF_2 | pWITH | pSTMT_WHILE | pSTMT_FOR | pSTMT_PRINT | pSTMT_UPDATE_ARR | pSTMT_UPDATE | pSTMT_PROCEDURE | pSTMT_BLOCK) # can't attach a parse action to pSTMT because of recursion, so let's duplicate the parser pTOP_STMT = pSTMT.copy() pTOP_STMT.setParseAction(lambda result: { "result": "statement", "stmt": result[0] }) pTOP_DECL = pDECL.copy() pTOP_DECL.setParseAction(lambda result: { "result": "declaration", "decl": result[0] }) pABSTRACT = "#abs" + pSTMT pABSTRACT.setParseAction(lambda result: { "result": "abstract", "stmt": result[1] }) pQUIT = Keyword("#quit") pQUIT.setParseAction(lambda result: {"result": "quit"}) pTOP = (pQUIT | pABSTRACT | pTOP_DECL | pTOP_STMT) result = pTOP.parseString(input)[0] return result # the first element of the result is the expression
def parse_imp (input): # parse a string into an element of the abstract representation # Grammar: # # <expr> ::= <integer> # true # false # <identifier> # ( if <expr> <expr> <expr> ) # ( function ( <name ... ) <expr> ) # ( <expr> <expr> ... ) # # <decl> ::= var name = expr ; # # <stmt> ::= if <expr> <stmt> else <stmt> # while <expr> <stmt> # name <- <expr> ; # print <expr> ; # <block> # # <block> ::= { <decl> ... <stmt> ... } # # <toplevel> ::= <decl> # <stmt> # idChars = alphas+"_+*-?!=<>+" QUOTE = Literal('"') INTERNAL_QUOTE = QUOTE.copy().leaveWhitespace() pIDENTIFIER = Word(idChars, idChars+"0123456789") #### NOTE THE DIFFERENCE pIDENTIFIER.setParseAction(lambda result: EPrimCall(oper_deref,[EId(result[0])])) # A name is like an identifier but it does not return an EId... pNAME = Word(idChars,idChars+"0123456789") #| Keyword("&\"") | Keyword("&\'") pNAMECON = "," + pNAME pNAMECON.setParseAction(lambda result: result[1]) pNAMES = pNAME + ZeroOrMore(pNAMECON) | ZeroOrMore(pNAME) pNAMES.setParseAction(lambda result: [result]) pINTEGER = Word("0123456789") pINTEGER.setParseAction(lambda result: EValue(VInteger(int(result[0])))) QUOTE = Literal("&\"") | Literal("&\'") pSTRINGSTART = Literal('"') + ZeroOrMore(Word(" ")).leaveWhitespace() pSTRINGSTART.setParseAction(lambda result: result[1:]) pSTRING = pSTRINGSTART + ZeroOrMore(Combine( Word(idChars+"0123456789'"+" ") | QUOTE)) + Literal('"') pSTRING.setParseAction(lambda result: EValue(VString(str(result[:-1])))) pBOOLEAN = Keyword("true") | Keyword("false") pBOOLEAN.setParseAction(lambda result: EValue(VBoolean(result[0]=="true"))) pEXPR = Forward() pEXPR2 = Forward() pSTMT_BLOCK = Forward() pSTMT = Forward() pEXPRS = ZeroOrMore(pEXPR2) pEXPRS.setParseAction(lambda result: [result]) pIF = pEXPR + Keyword("?") + pEXPR + Keyword(':') + pEXPR pIF.setParseAction(lambda result: EIf(result[0], result[2], result[4])) def mkFunBody (params,body): bindings = [ (p,ERefCell(EId(p))) for p in params ] return ELet(bindings,body) def mkLetBody (bindings,body): bindings = [ (p[0],ERefCell(p[1])) for p in bindings ] return ELet(bindings,body) def multiCallHelper(result, start, i, length): if i < length: start = ECall(result[1][i][0], [result[1][i][1], start]) multiCallHelper(result, start, i + 1, length) return start def multiCall(result): start = ECall(result[1][0][0], [result[0], result[1][0][1]]) return multiCallHelper(result, start, 1, len(result[1])) def eFunHelper(variables, expression): if len(variables) == 1: return EFunction(variables[0], expression) else: return EFunction(variables[0], eFunHelper(variables[1:], expression)) def eFunName(result): varName = result[1] variables = result[3] expression = result[-1] print variables, expression return EFunction(variables, expression, varName) pFUN = Keyword("fun") + "(" + pNAMES + ")" + pSTMT pFUN.setParseAction(lambda result: EFunction(result[2],mkFunBody(result[2],result[4]))) pFUNR = Keyword("fun") + pNAME + "(" + pNAMES + ")" + pSTMT # pFUNR.setParseAction(eFunName) pFUNR.setParseAction(lambda result: EFunction(result[3],mkFunBody(result[3],result[5]), result[1])) pEXPR2CAR = "," + pEXPR2 pEXPR2CAR.setParseAction(lambda result: result[1]) pEXPR2MULTIALL = pEXPR2 + ZeroOrMore(pEXPR2CAR) | ZeroOrMore(pEXPR2) pEXPR2MULTIALL.setParseAction(lambda result: [result]) pFUNCALL = pEXPR + "(" + pEXPR2MULTIALL + ")" pFUNCALL.setParseAction(lambda result: ECall(result[0], result[2])) pBINDINGCAR = "," + pNAME + "=" + pEXPR2 pBINDINGCAR.setParseAction(lambda result: (result[1], result[3])) pBINDINGCON = pNAME + "=" + pEXPR2 pBINDINGCON.setParseAction(lambda result: (result[0], result[2])) pBINDINGS = pBINDINGCON + ZeroOrMore(pBINDINGCAR) pBINDINGS.setParseAction(lambda result: [result]) pLET = Keyword("let") + "(" + pBINDINGS + ")" + pEXPR2 pLET.setParseAction(lambda result: mkLetBody(result[2], result[4])) pCALLG = pIDENTIFIER + pEXPR2 pCALLG.setParseAction(lambda result: (result[0], result[1])) pCALL1S = OneOrMore(pCALLG) pCALL1S.setParseAction(lambda result: [ result ]) pCALL = pEXPR + pCALL1S pCALL.setParseAction(multiCall) pCALL1 = pIDENTIFIER + pEXPR2 pCALL1.setParseAction(lambda result: ECall(result[0], [result[1]])) pNOT = "not" + pEXPR2 pNOT.setParseAction(lambda result: EPrimCall(oper_not, [result[1]])) pARRAYITEM = "," + pEXPR2 pARRAYITEM.setParseAction(lambda result: (result[1])) pARRAYITEMS = ZeroOrMore(pARRAYITEM) pARRAYITEMS.setParseAction(lambda result: [result]) pARRAY = "[" + ZeroOrMore(pEXPR2) + pARRAYITEMS + "]" pARRAY.setParseAction(lambda result: EArray(result[1],result[2])) pDICTPAIR = pNAME + ":" + pEXPR pDICTPAIR.setParseAction(lambda result: (result[0],result[2])) pDICTPAIRWITHCOMMA = "," + pNAME + ":" + pEXPR pDICTPAIRWITHCOMMA.setParseAction(lambda result: (result[1],result[3])) pDICTS = ZeroOrMore(pDICTPAIRWITHCOMMA) pDICTS.setParseAction(lambda result: [ result ]) pDICT = "{" + pDICTPAIR + pDICTS + "}" pDICT.setParseAction(lambda result:EDict(result[1],result[2])) pEXPR2P = "(" + pEXPR2 + ")" pEXPR2P.setParseAction(lambda result: result[1]) pACCESS = pNAME + "[" + pEXPR + "]" pACCESS.setParseAction(lambda result: EPrimCall(oper_access_arr,[EId(result[0]),result[2]])) pLEN = Keyword("len") + "(" + pNAME + ")" pLEN.setParseAction(lambda result: EPrimCall(oper_len,[EId(result[2])])) pEXPR << ( pEXPR2P | pINTEGER | pNOT | pARRAY | pACCESS | pDICT | pSTRING | pBOOLEAN | pIDENTIFIER | pCALL1 | pLEN ) pEXPR2 << ( pLET | pFUN | pFUNR | pFUNCALL | pIF | pCALL | pEXPR ) pDECL_VAR_E = "var" + pNAME + ";" pDECL_VAR_E.setParseAction(lambda result: (result[1], EValue(VNone))) pDECL_VAR = "var" + pNAME + "=" + pEXPR2 + ";" pDECL_VAR.setParseAction(lambda result: (result[1],result[3])) pDECL_PROCEDURE = "def" + pNAME + "(" + pNAMES + ")" + pSTMT pDECL_PROCEDURE.setParseAction(lambda result: (result[1], EProcedure(result[3], mkFunBody(result[3], result[5])))) # hack to get pDECL to match only PDECL_VAR (but still leave room # to add to pDECL later) pDECL = ( pDECL_VAR_E | pDECL_VAR | pDECL_PROCEDURE | NoMatch() | ";" ) pDECLS = ZeroOrMore(pDECL) pDECLS.setParseAction(lambda result: [result]) pSTMT_IF_1 = "if (" + pEXPR2 + ")" + pSTMT + "else" + pSTMT pSTMT_IF_1.setParseAction(lambda result: EIf(result[1],result[3],result[5])) pSTMT_IF_2 = "if (" + pEXPR2 + ")" + pSTMT pSTMT_IF_2.setParseAction(lambda result: EIf(result[1],result[3],EValue(VBoolean(True)))) pSTMT_WHILE = "while (" + pEXPR2 + ")" + pSTMT pSTMT_WHILE.setParseAction(lambda result: EWhile(result[1],result[3])) pSTMT_FOR = "for (" + pNAME + "in" + pEXPR2 + ")" + pSTMT pSTMT_FOR.setParseAction(lambda result: EFor(result[1], result[3], result[5])) pSTMT_PRINT_STMS = "," + pEXPR2 pSTMT_PRINT_STMS.setParseAction(lambda result: [ result[1] ]) pSTMT_PRINT_ZERO = ZeroOrMore(pSTMT_PRINT_STMS) pSTMT_PRINT_ZERO.setParseAction(lambda result: [ result ]) def printStmEval(result): newArray = [] newArray.append(result[1]) for i in result[2]: newArray.append(i) return EPrimCall(oper_print,newArray) pSTMT_PRINT = "print" + pEXPR2 + pSTMT_PRINT_ZERO + ";" pSTMT_PRINT.setParseAction(printStmEval) pSTMT_UPDATE_ARR = pNAME + "[" + pEXPR +"]" + "=" + pEXPR + ";" pSTMT_UPDATE_ARR.setParseAction(lambda result: EPrimCall(oper_update_arr,[EId(result[0]),result[2],result[5]])) pSTMT_UPDATE = pNAME + "=" + pEXPR2 + ";" pSTMT_UPDATE.setParseAction(lambda result: EPrimCall(oper_update,[EId(result[0]),result[2]])) pSTMTS = ZeroOrMore(pSTMT) pSTMTS.setParseAction(lambda result: [result]) def mkBlock (decls,stmts): bindings = [ (n,ERefCell(expr)) for (n,expr) in decls ] return ELet(bindings,EDo(stmts)) pSTMT_BLOCK = "{" + pDECLS + pSTMTS + "}" pSTMT_BLOCK.setParseAction(lambda result: mkBlock(result[1],result[2])) pSTMT_pEXPR2 = pEXPR2 + ";" pSTMT_pEXPR2.setParseAction(lambda result: result[0]) pSTMT << ( pSTMT_IF_1 | pSTMT_IF_2 | pSTMT_WHILE | pSTMT_FOR | pSTMT_PRINT | pSTMT_UPDATE_ARR | pSTMT_UPDATE | pSTMT_BLOCK | pSTMT_pEXPR2 | pEXPR2 ) # can't attach a parse action to pSTMT because of recursion, so let's duplicate the parser pTOP_STMT = pSTMT.copy() pTOP_STMT.setParseAction(lambda result: {"result":"statement", "stmt":result[0]}) pTOP_DECL = pDECL.copy() pTOP_DECL.setParseAction(lambda result: {"result":"declaration", "decl":result[0]}) pABSTRACT = "#abs" + pSTMT pABSTRACT.setParseAction(lambda result: {"result":"abstract", "stmt":result[1]}) pQUIT = Keyword("#quit") pQUIT.setParseAction(lambda result: {"result":"quit"}) pTOP = ZeroOrMore(pTOP_DECL) + ZeroOrMore(pTOP_STMT) return pTOP.parseString(input)