def test_duplicate_precedence(self): pg = ParserGenerator([], precedence=[ ("left", ["term", "term"]) ]) with py.test.raises(ParserGeneratorError): pg.build()
def test_invalid_associativity(self): pg = ParserGenerator([], precedence=[ ("to-the-left", ["term"]), ]) with py.test.raises(ParserGeneratorError): pg.build()
def test_production_terminal_overlap(self): pg = ParserGenerator(["VALUE"]) @pg.production("VALUE :") def x(p): pass with py.test.raises(ParserGeneratorError): pg.build()
def test_nonexistant_precedence(self): pg = ParserGenerator(["VALUE"]) @pg.production("main : VALUE", precedence="abc") def main(p): pass with py.test.raises(ParserGeneratorError): pg.build()
def test_unused_tokens(self): pg = ParserGenerator(["VALUE", "OTHER"]) @pg.production("main : VALUE") def main(p): return p[0] with self.assert_warns(ParserGeneratorWarning, "Token 'OTHER' is unused"): pg.build()
def test_error_symbol(self): pg = ParserGenerator(["VALUE"]) @pg.production("main : VALUE") def main(p): pass @pg.production("main : error") def main_error(p): pass pg.build()
def test_unused_production(self): pg = ParserGenerator(["VALUE", "OTHER"]) @pg.production("main : VALUE") def main(p): return p[0] @pg.production("unused : OTHER") def unused(p): pass with self.assert_warns(ParserGeneratorWarning, "Production 'unused' is not reachable"): pg.build()
def test_simple_caching(self): pg = ParserGenerator(["VALUE"], cache_id="simple") @pg.production("main : VALUE") def main(p): return p[0] pg.build() parser = pg.build() assert parser.parse(iter([ Token("VALUE", "3") ])) == Token("VALUE", "3")
def test_simple_caching(self): # Generate a random cache_id so that every test run does both the cache # write and read paths. pg = ParserGenerator(["VALUE"], cache_id=str(uuid.uuid4())) @pg.production("main : VALUE") def main(p): return p[0] pg.build() parser = pg.build() assert parser.parse(iter([ Token("VALUE", "3") ])) == Token("VALUE", "3")
def test_arithmetic(self): pg = ParserGenerator(["NUMBER", "PLUS"]) @pg.production("main : expr") def main(p): return p[0] @pg.production("expr : expr PLUS expr") def expr_op(p): return BoxInt(p[0].getint() + p[2].getint()) @pg.production("expr : NUMBER") def expr_num(p): return BoxInt(int(p[0].getstr())) with self.assert_warns( ParserGeneratorWarning, "1 shift/reduce conflict" ): parser = pg.build() assert parser.parse(iter([ Token("NUMBER", "1"), Token("PLUS", "+"), Token("NUMBER", "4") ])) == BoxInt(5)
def test_precedence(self): pg = ParserGenerator(["NUMBER", "PLUS", "TIMES"], precedence=[ ("left", ["PLUS"]), ("left", ["TIMES"]), ]) @pg.production("main : expr") def main(p): return p[0] @pg.production("expr : expr PLUS expr") @pg.production("expr : expr TIMES expr") def expr_binop(p): return BoxInt({ "+": operator.add, "*": operator.mul }[p[1].getstr()](p[0].getint(), p[2].getint())) @pg.production("expr : NUMBER") def expr_num(p): return BoxInt(int(p[0].getstr())) parser = pg.build() assert parser.parse(iter([ Token("NUMBER", "3"), Token("TIMES", "*"), Token("NUMBER", "4"), Token("PLUS", "+"), Token("NUMBER", "5") ])) == BoxInt(17)
def test_state(self): pg = ParserGenerator(["NUMBER", "PLUS"], precedence=[ ("left", ["PLUS"]), ]) @pg.production("main : expression") def main(state, p): state.count += 1 return p[0] @pg.production("expression : expression PLUS expression") def expression_plus(state, p): state.count += 1 return BoxInt(p[0].getint() + p[2].getint()) @pg.production("expression : NUMBER") def expression_number(state, p): state.count += 1 return BoxInt(int(p[0].getstr())) parser = pg.build() state = ParserState() assert parser.parse(iter([ Token("NUMBER", "10"), Token("PLUS", "+"), Token("NUMBER", "12"), Token("PLUS", "+"), Token("NUMBER", "-2"), ]), state=state) == BoxInt(20) assert state.count == 6
def test_basic_parser(self): pg = ParserGenerator(["NUMBER", "PLUS"]) @pg.production("main : expr") def main(p): return p[0] @pg.production("expr : expr PLUS expr") def expr_op(p): return BoxInt(p[0].getint() + p[2].getint()) @pg.production("expr : NUMBER") def expr_num(p): return BoxInt(int(p[0].getstr())) with self.assert_warns( ParserGeneratorWarning, "1 shift/reduce conflict" ): parser = pg.build() def f(n): return parser.parse(iter([ Token("NUMBER", str(n)), Token("PLUS", "+"), Token("NUMBER", str(n)) ])).getint() assert self.run(f, [12]) == 24
def test_arithmetic(self): lg = LexerGenerator() lg.add("NUMBER", r"\d+") lg.add("PLUS", r"\+") lg.add("TIMES", r"\*") pg = ParserGenerator(["NUMBER", "PLUS", "TIMES"], precedence=[ ("left", ["PLUS"]), ("left", ["TIMES"]), ]) @pg.production("main : expr") def main(p): return p[0] @pg.production("expr : expr PLUS expr") @pg.production("expr : expr TIMES expr") def expr_binop(p): return BoxInt({ "+": operator.add, "*": operator.mul }[p[1].getstr()](p[0].getint(), p[2].getint())) @pg.production("expr : NUMBER") def expr_num(p): return BoxInt(int(p[0].getstr())) lexer = lg.build() parser = pg.build() assert parser.parse(lexer.lex("3*4+5"))
def test_null_production(self): pg = ParserGenerator(["VALUE", "SPACE"]) @pg.production("main : values") def main(p): return p[0] @pg.production("values : none") def values_empty(p): return [] @pg.production("values : VALUE") def values_value(p): return [p[0].getstr()] @pg.production("values : values SPACE VALUE") def values_values(p): return p[0] + [p[2].getstr()] @pg.production("none :") def none(p): return None parser = pg.build() assert parser.parse(iter([ Token("VALUE", "abc"), Token("SPACE", " "), Token("VALUE", "def"), Token("SPACE", " "), Token("VALUE", "ghi"), ])) == ["abc", "def", "ghi"] assert parser.parse(iter([])) == []
def test_per_rule_precedence(self): pg = ParserGenerator(["NUMBER", "MINUS"], precedence=[ ("right", ["UMINUS"]), ]) @pg.production("main : expr") def main_expr(p): return p[0] @pg.production("expr : expr MINUS expr") def expr_minus(p): return BoxInt(p[0].getint() - p[2].getint()) @pg.production("expr : MINUS expr", precedence="UMINUS") def expr_uminus(p): return BoxInt(-p[1].getint()) @pg.production("expr : NUMBER") def expr_number(p): return BoxInt(int(p[0].getstr())) with self.assert_warns( ParserGeneratorWarning, "1 shift/reduce conflict" ): parser = pg.build() assert parser.parse(iter([ Token("MINUS", "-"), Token("NUMBER", "4"), Token("MINUS", "-"), Token("NUMBER", "5"), ])) == BoxInt(-9)
def test_reduce_reduce(self): pg = ParserGenerator(["NAME", "EQUALS", "NUMBER"]) @pg.production("main : assign") def main(p): pass @pg.production("assign : NAME EQUALS expression") @pg.production("assign : NAME EQUALS NUMBER") def assign(p): pass @pg.production("expression : NUMBER") def expression(p): pass with self.assert_warns(ParserGeneratorWarning, "1 reduce/reduce conflict"): pg.build()
def test_simple(self): pg = ParserGenerator(["VALUE"]) @pg.production("main : VALUE") def main(p): return p[0] parser = pg.build() assert parser.parse(iter([Token("VALUE", "abc")])) == Token("VALUE", "abc")
def build(): pg = ParserGenerator(TOKENS, cache_id="sql_parser") for prod, cls in gen_productions(select_bnf, node_classes): pg.production(prod)(cls.production) # print prod @pg.error def error_handler(token): raise ValueError("Ran into a %s(%s) where it wasn't expected" % (token.gettokentype(), token.getstr())) return pg.build()
def test_shift_reduce(self): pg = ParserGenerator([ "NAME", "NUMBER", "EQUALS", "PLUS", "MINUS", "TIMES", "DIVIDE", "LPAREN", "RPAREN" ]) @pg.production("statement : NAME EQUALS expression") def statement_assign(p): pass @pg.production("statement : expression") def statement_expression(p): pass @pg.production("expression : expression PLUS expression") @pg.production("expression : expression MINUS expression") @pg.production("expression : expression TIMES expression") @pg.production("expression : expression DIVIDE expression") def expression_binop(p): pass @pg.production("expression : MINUS expression") def expression_uminus(p): pass @pg.production("expression : LPAREN expression RPAREN") def expression_group(p): pass @pg.production("expression : NUMBER") def expression_number(p): pass @pg.production("expression : NAME") def expression_name(p): pass with self.assert_warns( ParserGeneratorWarning, "20 shift/reduce conflicts" ): pg.build()
def test_parse_error(self): pg = ParserGenerator(["VALUE"]) @pg.production("main : VALUE") def main(p): return p[0] parser = pg.build() with py.test.raises(ParsingError) as exc_info: parser.parse(FakeLexer([Token("VALUE", "hello"), Token("VALUE", "world", SourcePosition(5, 10, 2))])) assert exc_info.value.getsourcepos().lineno == 10
def test_simple(self): pg = ParserGenerator(["VALUE"]) @pg.production("main : VALUE") def main(p): return p[0] parser = pg.build() assert parser.lr_table.lr_action == { 0: {"VALUE": 2}, 1: {"$end": 0}, 2: {"$end": -1}, }
def test_default_reductions(self): pg = ParserGenerator( ["INTEGER_START", "INTEGER_VALUE", "COMPARE"], precedence=[ ("nonassoc", ["COMPARE"]) ] ) record = [] @pg.production("main : expr") def main(p): record.append("main") return p[0] @pg.production("expr : expr COMPARE expr") def expr_compare(p): record.append("expr:compare") return BoxInt(p[0].getint() - p[2].getint()) @pg.production("expr : INTEGER_START INTEGER_VALUE") def expr_int(p): record.append("expr:int") return BoxInt(int(p[1].getstr())) parser = pg.build() assert parser.parse(RecordingLexer(record, [ Token("INTEGER_START", ""), Token("INTEGER_VALUE", "10"), Token("COMPARE", "-"), Token("INTEGER_START", ""), Token("INTEGER_VALUE", "5") ])) == BoxInt(5) assert record == [ "token:INTEGER_START", "token:INTEGER_VALUE", "expr:int", "token:COMPARE", "token:INTEGER_START", "token:INTEGER_VALUE", "expr:int", "expr:compare", "token:None", "main", ]
def parser_from_lexer(lexer, mapping): pg = ParserGenerator( [rule.name for rule in lexer.rules], cache_id="cache", # NOTE: This is pretty arbitrary at the moment precedence=[ ('right', ['NOT']), ('left', ['PARENT', 'CHILD', 'OR']), ('left', ['AND', 'TYPE']), ('left', ['L_PAREN', 'R_PAREN', 'EQUAL']), ]) @pg.production("expr : L_PAREN expr R_PAREN") def expr(p): return p[1] @pg.production("expr : expr AND expr") @pg.production("expr : expr OR expr") @pg.production("expr : expr CHILD expr") @pg.production("expr : expr PARENT expr") def binary_operation(p): return [p[1], p[0], p[2]] @pg.production("expr : expr EQUAL DATA") @pg.production("expr : expr TYPE DATA") def equal(p): p[2].value = p[2].value.strip("/") return p @pg.production("expr : expr NOT CHILD expr") @pg.production("expr : expr NOT PARENT expr") def not_expr(p): # This is a hack op = p[2] op.name = "NOT_" + op.name op.value = "!" + op.value return [op, p[0], p[3]] for kind in mapping.keys(): @pg.production("expr : " + kind) def kind(p): return mapping[p[0].name] parser = pg.build() return parser
def test_parse_error_handler(self): pg = ParserGenerator(["VALUE"]) @pg.production("main : VALUE") def main(p): return p[0] @pg.error def error_handler(token): raise ValueError(token) parser = pg.build() token = Token("VALUE", "world") with py.test.raises(ValueError) as exc_info: parser.parse(FakeLexer([Token("VALUE", "hello"), token])) assert exc_info.value.args[0] is token
def test_error_handler_state(self): pg = ParserGenerator([]) @pg.production("main :") def main(state, p): pass @pg.error def error(state, token): raise ValueError(state, token) parser = pg.build() state = ParserState() token = Token("VALUE", "") with py.test.raises(ValueError) as exc_info: parser.parse(iter([token]), state=state) assert exc_info.value.args[0] is state assert exc_info.value.args[1] is token
def test_empty_production(self): pg = ParserGenerator(["VALUE"]) @pg.production("main : values") def main(p): return p[0] @pg.production("values : VALUE values") def values_value(p): return [p[0]] + p[1] @pg.production("values :") def values_empty(p): return [] parser = pg.build() assert parser.lr_table.lr_action == { 0: {"$end": -3, "VALUE": 3}, 1: {"$end": 0}, 2: {"$end": -1}, 3: {"$end": -3, "VALUE": 3}, 4: {"$end": -2}, }
class Parser: def __init__(self): self.pg = ParserGenerator( # A list of all token names accepted by the parser. [ 'ADDVV', 'ADDVS', 'SUBVV', 'SUBVS', 'SUBSV', 'MULVV', 'MULVS', 'DIVVV', 'DIVVS', 'DIVSV', 'LV', 'LVWS', 'SV', 'SVWS', 'CVI', 'SLEVV', 'SLEVS', 'SREVV', 'SREVS', 'XOREVV', 'XOREVS', 'OWNEP', 'SLDVV', 'SLDVS', 'SRDVV', 'SRDVS', 'XORDVV', 'XORDVS', 'OWNDP', 'COLON', 'SEMI_COLON', 'OPEN_PAREN', 'CLOSE_PAREN', 'NUMBER', 'VEC1', 'VEC2', 'VEC3', 'S0', 'S1', 'S2', 'S3', 'S4', 'S5', 'S6', 'S7', 'S8', 'S9', 'S10', 'S11', 'S12', 'S13', 'S14', 'S15', ]) def parse(self): @self.pg.production( 'expression : ADDVV VEC1 COLON VEC2 COLON VEC3 SEMI_COLON') @self.pg.production( 'expression : ADDVV VEC1 COLON VEC3 COLON VEC2 SEMI_COLON') @self.pg.production( 'expression : ADDVV VEC2 COLON VEC1 COLON VEC3 SEMI_COLON') @self.pg.production( 'expression : ADDVV VEC2 COLON VEC3 COLON VEC1 SEMI_COLON') @self.pg.production( 'expression : ADDVV VEC3 COLON VEC1 COLON VEC2 SEMI_COLON') @self.pg.production( 'expression : ADDVV VEC3 COLON VEC2 COLON VEC1 SEMI_COLON') def expression(p): print("ADDVV 1") return 0 @self.pg.error def error_handle(token): raise ValueError(token) def get_parser(self): return self.pg.build()
class Parser: def __init__(self): self.pg = ParserGenerator([ 'NUMBER', 'PRINT', 'OPEN_PAREN', 'CLOSE_PAREN', 'SEMI_COLON', 'SUM', 'SUB', 'MULT', 'DIV', 'POT', 'RESTO' ], precedence=[ ('left', ['SUM', 'SUB']), ('left', ['MULT', 'DIV', 'RESTO']), ('left', ['POT']), ]) self.file = open("codigo.asm", "w") self.file.write(".data\n") self.file.write(".text\n") self.file.write(".global main\n") self.file.write("main:\n") print("\"codigo\" compilado com sucesso para \"./".__add__( self.file.name).__add__("\"")) def parse(self): @self.pg.production( 'program : PRINT OPEN_PAREN expression CLOSE_PAREN SEMI_COLON') def program(p): self.file.write("\tmove $a0, $t1\n") self.file.write("\tli $v0, 1\n") self.file.write("\tsyscall\n") self.file.write("\tli $v0, 10\n") self.file.write("\tsyscall\n") self.file.write(".end main") @self.pg.production('expression : expression SUM expression') @self.pg.production('expression : expression SUB expression') @self.pg.production('expression : expression MULT expression') @self.pg.production('expression : expression DIV expression') @self.pg.production('expression : expression POT expression') @self.pg.production('expression : expression RESTO expression') def expression(p): left = p[0] right = p[2] operator = p[1] if operator.gettokentype() == 'SUM': flag = 0 if left: if right: self.file.write("\tli $t1, ".__add__( str(left)).__add__("\n")) self.file.write("\tli $t2, ".__add__( str(right)).__add__("\n")) flag = 1 if flag == 0: if left: self.file.write("\tli $t2, ".__add__( str(left)).__add__("\n")) if right: self.file.write("\tli $t2, ".__add__( str(right)).__add__("\n")) self.file.write("\tadd $t1, $t1, $t2\n") elif operator.gettokentype() == 'SUB': flag = 0 if left: if right: self.file.write("\tli $t1, ".__add__( str(left)).__add__("\n")) self.file.write("\tli $t2, ".__add__( str(right)).__add__("\n")) flag = 1 if flag == 0: if left: self.file.write("\tli $t2, ".__add__( str(left)).__add__("\n")) if right: self.file.write("\tli $t2, ".__add__( str(right)).__add__("\n")) self.file.write("\tsub $t1, $t1, $t2\n") elif operator.gettokentype() == 'MULT': flag = 0 if left: if right: self.file.write("\tli $t1, ".__add__( str(left)).__add__("\n")) self.file.write("\tli $t2, ".__add__( str(right)).__add__("\n")) flag = 1 if flag == 0: if left: self.file.write("\tli $t2, ".__add__( str(left)).__add__("\n")) if right: self.file.write("\tli $t2, ".__add__( str(right)).__add__("\n")) self.file.write("\tmul $t1, $t1, $t2\n") elif operator.gettokentype() == 'DIV': flag = 0 if left: if right: self.file.write("\tli $t1, ".__add__( str(left)).__add__("\n")) self.file.write("\tli $t2, ".__add__( str(right)).__add__("\n")) flag = 1 if flag == 0: if left: self.file.write("\tli $t2, ".__add__( str(left)).__add__("\n")) if right: self.file.write("\tli $t2, ".__add__( str(right)).__add__("\n")) self.file.write("\tdiv $t1, $t1, $t2\n") elif operator.gettokentype() == 'POT': # Not finished aux_x = left aux_y = int(right) - 1 while aux_y > 0: self.file.write("\tli $t2, ".__add__( str(aux_x)).__add__("\n")) self.file.write("\tmul $t1, $t2, $t2\n") aux_y = aux_y - 1 elif operator.gettokentype() == 'RESTO': flag = 0 interator = 1 if left: if right: self.file.write("\tli $t1, ".__add__( str(left)).__add__("\n")) self.file.write("\tli $t2, ".__add__( str(right)).__add__("\n")) flag = 1 if flag == 0: if left: self.file.write("\tli $t2, ".__add__( str(left)).__add__("\n")) if right: self.file.write("\tli $t2, ".__add__( str(right)).__add__("\n")) self.file.write("\tmove $t3, $t1 \n") self.file.write("\tmove $t4, $t2\n") self.file.write("\tli $t5, 0\n") self.file.write("\tloop:\n") self.file.write("\t\tli $t6, 1\n") self.file.write( "\t\tadd $t5, $t5, $t6\n") # incrementando contador self.file.write("\t\tsub $t3, $t3, $t4\n") self.file.write("\t\tbgt $t3, $t4, loop\n") self.file.write("\tmul $t3, $t5, $t2\n") self.file.write("\tsub $t1, $t1, $t3\n") @self.pg.production('expression : NUMBER') def number(p): return p[0].value @self.pg.error def error_handle(token): raise ValueError(token) def get_parser(self): return self.pg.build()
@pg.production("hashtags : hashtags HASHTAG") @pg.production("hashtags : HASHTAG") def hashtags(p): if len(p) == 1: return p else: return list(flattened(p)) @pg.production("topics : FOR hashtags") @pg.production("topics : ") def topics(p): if len(p) == 0: return { u'topics': [] } else: topics = [tok.value.strip('#') for tok in p[1]] return { u'topics': topics } @pg.error def error_handler(token): pos = token.getsourcepos() if pos: offset = "offset {}".format(pos.idx) else: offset = u"end of stream" raise ValueError("Ran into a {0} where it wasn't expected at {1}".format(token.gettokentype(), offset)) TweetLexer = lex.build() TweetParser = pg.build()
class Parser: def __init__(self, tokens): self.pg = ParserGenerator( tokens, precedence=[('left', ['NEWLINE']), ('left', ['EGAL']), ('left', ['AND', 'OR', 'NOT']), ('left', ['IS', 'LESS', 'MORE', 'LESSE', 'MOREE']), ('left', ['SUMAFF', 'SUBAFF']), ('left', ['MULAFF', 'DIVAFF', 'DIVEUAFF', 'MODAFF']), ('left', ['POWAFF']), ('left', ['SUM', 'SUB']), ('left', ['MUL', 'DIV', 'DIVEU', 'MOD']), ('left', ['POW'])]) self.var = Variables() def parse(self): @self.pg.production('program : statementlist') def program(p): return p[0].eval() @self.pg.production('statementlist : statementlist NEWLINE statement') @self.pg.production( 'statementlist : statementlist NEWLINE loop_statement') @self.pg.production( 'statementlist : statementlist NEWLINE if_statement') def statementlistexp(p): return StatementList(p[2], p[0]) @self.pg.production('statementlist : statement') @self.pg.production('statementlist : loop_statement') @self.pg.production('statementlist : if_statement') @self.pg.production('statementlist : statementlist NEWLINE') def statementlist(p): if p[0].gettokentype() == 'statement': return StatementList(p[0]) else: return StatementList(None, p[0]) @self.pg.production( 'loop_statement : LOOP INTEGER OPEN_CRO NEWLINE statementlist NEWLINE CLOSE_CRO' ) def loop(p): return Loop(int(p[1].value), p[4]) @self.pg.production( 'loop_statement : LOOP INTEGER NEWLINE OPEN_CRO NEWLINE statementlist NEWLINE CLOSE_CRO' ) def loop2(p): return Loop(int(p[1].value), p[5]) @self.pg.production( 'loop_statement : WHILE expression OPEN_CRO NEWLINE statementlist NEWLINE CLOSE_CRO' ) def whileexp(p): return While(p[1], p[4]) @self.pg.production( 'loop_statement : WHILE expression NEWLINE OPEN_CRO NEWLINE statementlist NEWLINE ' 'CLOSE_CRO') def whileexp2(p): return While(p[1], p[5]) @self.pg.production( 'if_statement : IF expression OPEN_CRO NEWLINE statementlist NEWLINE CLOSE_CRO' ) def ifexp(p): return If(p[1], p[4]) @self.pg.production( 'if_statement : IF expression NEWLINE OPEN_CRO NEWLINE statementlist NEWLINE CLOSE_CRO' ) def ifexp2(p): return If(p[1], p[5]) @self.pg.production( 'else_statement : ELSE OPEN_CRO NEWLINE statementlist NEWLINE CLOSE_CRO' ) def elseexp(p): return Else(p[3]) @self.pg.production( 'else_statement : ELSE NEWLINE OPEN_CRO NEWLINE statementlist NEWLINE CLOSE_CRO' ) def elseexp2(p): return Else(p[4]) @self.pg.production( 'elseif_statement : ELSEIF expression OPEN_CRO NEWLINE statementlist NEWLINE ' 'CLOSE_CRO') def elseif(p): return ElseIfs(ElseIf(p[1], p[4])) @self.pg.production( 'elseif_statement : ELSEIF expression NEWLINE OPEN_CRO NEWLINE statementlist NEWLINE ' 'CLOSE_CRO') def elseif2(p): return ElseIfs(ElseIf(p[1], p[5])) @self.pg.production( 'elseif_statement : elseif_statement elseif_statement') def elseif3(p): return p[0].add(p[1]) @self.pg.production('if_statement : if_statement else_statement') def ifelse(p): if type(p[0]) == IfElse: error(errors.UNEXPECTEDSYNTAX, "Alone Else", {"type": ""}) sys.exit(1) elif type(p[0]) == IfElseIf: return IfElseIfElse(If(p[0].ifcondition, p[0].ifstatementlist), p[0].elseifs, p[1]) else: return IfElse(p[0], p[1]) @self.pg.production('if_statement : if_statement elseif_statement') def ifelseif(p): if type(p[0]) == IfElse: error(errors.UNEXPECTEDSYNTAX, "Alone ElseIf", {"type": ""}) sys.exit(1) return IfElseIf(p[0], p[1]) @self.pg.production('statement : expression COMMENT') @self.pg.production('statement : expression') def statement(p): return Statement(p[0]) @self.pg.production('statement : COMMENT') def statement(p): return Nothing() @self.pg.production('expression : IDENTIFIER EGAL expression') def programvar(p): if type(p[2]) == List: error(errors.EXPECTEDSYNTAX, "Expected hook around List.", { "type": "token", "token": p[0] }) sys.exit(1) var = self.var.get(p[0].value) if var is not None: if type(var) == ListVar: error(errors.INVALIDTYPE, "Cannot have basic type.", { "type": "token", "token": p[0] }) sys.exit(1) return AffectionVar(var, p[2]) else: var = Variable(p[0].value, p[2]) self.var.add(var) return var @self.pg.production('expression : IDENTIFIER EGAL CRO_OPEN CRO_CLOSE') def programvar2(p): var = self.var.get(p[0].value) if var is not None: if type(var) == Variable: error(errors.INVALIDTYPE, "Cannot have complex type.", { "type": "token", "token": p[0] }) sys.exit(1) return AffectionVar(var, List()) else: var = ListVar(p[0].value, List()) self.var.add(var) return var @self.pg.production( 'expression : IDENTIFIER EGAL CRO_OPEN expression CRO_CLOSE') def programvar3(p): var = self.var.get(p[0].value) if var is not None: if type(var) == Variable: error(errors.INVALIDTYPE, "Cannot have complex type.", { "type": "token", "token": p[0] }) sys.exit(1) return AffectionVar(var, List(p[3])) else: var = ListVar(p[0].value, List(p[3])) self.var.add(var) return var @self.pg.production( 'expression : IDENTIFIER POINT IDENTIFIER OPEN_PAREN CLOSE_PAREN') def membervar(p): var = self.var.get(p[0].value) if var is not None: return MemberType(p[2].value, var) else: error(errors.NOTDECLARED, "Variable is not declared.", { "type": "token", "token": p[0] }) sys.exit(1) @self.pg.production( 'expression : IDENTIFIER POINT IDENTIFIER OPEN_PAREN expression CLOSE_PAREN' ) def membervar2(p): var = self.var.get(p[0].value) if var is not None: return MemberType(p[2].value, var, [p[4]]) else: error(errors.NOTDECLARED, "Variable is not declared.", { "type": "token", "token": p[0] }) sys.exit(1) @self.pg.production('expression : expression VIRGULE expression') def list(p): return List(p[0], p[2]) @self.pg.production( 'expression : CANBE OPEN_PAREN expression VIRGULE STRING CLOSE_PAREN' ) def programfunc2(p): func = p[0] exp = p[2] if func.gettokentype() == 'CANBE': return CanBe(exp, p[4].value[1:-1]) @self.pg.production( 'expression : INT OPEN_PAREN expression CLOSE_PAREN') @self.pg.production( 'expression : FLOATF OPEN_PAREN expression CLOSE_PAREN') @self.pg.production( 'expression : BOOL OPEN_PAREN expression CLOSE_PAREN') @self.pg.production( 'expression : STR OPEN_PAREN expression CLOSE_PAREN') @self.pg.production( 'expression : TYPE OPEN_PAREN expression CLOSE_PAREN') @self.pg.production( 'expression : PRINT OPEN_PAREN expression CLOSE_PAREN') @self.pg.production('expression : ENTER OPEN_PAREN STRING CLOSE_PAREN') def programfunc1(p): func = p[0] exp = p[2] if func.gettokentype() == "INT": return Int(exp) elif func.gettokentype() == "FLOATF": return Float(exp) elif func.gettokentype() == "BOOL": return Boolean(exp) elif func.gettokentype() == "STR": return Str(exp) elif func.gettokentype() == "TYPE": return Type(exp) elif func.gettokentype() == "PRINT": return Print(exp) else: return Input(exp.value) @self.pg.production('expression : EXIT OPEN_PAREN CLOSE_PAREN') @self.pg.production('expression : ENTER OPEN_PAREN CLOSE_PAREN') @self.pg.production('expression : PRINT OPEN_PAREN CLOSE_PAREN') def programfunc0(p): func = p[0] if func.gettokentype() == "EXIT": sys.exit(0) elif func.gettokentype() == "ENTER": return Input() else: return Print() @self.pg.production('expression : OPEN_PAREN expression CLOSE_PAREN') def expressionparen(p): return p[1] @self.pg.production('expression : IDENTIFIER INCREMENT') @self.pg.production('expression : IDENTIFIER DECREMENT') def uniqueop(p): var = self.var.get(p[0].value) if var is not None: if p[1].gettokentype() == "INCREMENT": return Increment(var) else: return Decrement(var) else: error(errors.NOTDECLARED, "Variable is not declared.", { "type": "token", "token": p[0] }) sys.exit(1) @self.pg.production('expression : IDENTIFIER SUMAFF expression') @self.pg.production('expression : IDENTIFIER SUBAFF expression') @self.pg.production('expression : IDENTIFIER MULAFF expression') @self.pg.production('expression : IDENTIFIER DIVAFF expression') @self.pg.production('expression : IDENTIFIER MODAFF expression') @self.pg.production('expression : IDENTIFIER POWAFF expression') @self.pg.production('expression : IDENTIFIER DIVEUAFF expression') def affectionop(p): var = self.var.get(p[0].value) op = p[1] if var is not None: if op.gettokentype() == 'SUMAFF': return SumAffector(var, p[2]) elif op.gettokentype() == 'SUBAFF': return SubAffector(var, p[2]) elif op.gettokentype() == 'MULAFF': return MulAffector(var, p[2]) elif op.gettokentype() == 'MODAFF': return ModAffector(var, p[2]) elif op.gettokentype() == 'POWAFF': return PowAffector(var, p[2]) elif op.gettokentype() == 'DIVEUAFF': return DivEuAffector(var, p[2]) else: return DivAffector(var, p[2]) else: error(errors.NOTDECLARED, "Variable is not declared.", { "type": "token", "token": p[0] }) sys.exit(1) @self.pg.production('expression : expression SUM expression') @self.pg.production('expression : expression SUB expression') @self.pg.production('expression : expression MUL expression') @self.pg.production('expression : expression DIV expression') @self.pg.production('expression : expression MOD expression') @self.pg.production('expression : expression POW expression') @self.pg.production('expression : expression DIVEU expression') def binaryop(p): left = p[0] right = p[2] operator = p[1] if operator.gettokentype() == 'SUM': return Sum(left, right) elif operator.gettokentype() == 'SUB': return Sub(left, right) elif operator.gettokentype() == 'MUL': return Mul(left, right) elif operator.gettokentype() == 'MOD': return Mod(left, right) elif operator.gettokentype() == 'POW': return Pow(left, right) elif operator.gettokentype() == 'DIVEU': return DivEu(left, right) else: return Div(left, right) @self.pg.production('expression : expression AND expression') @self.pg.production('expression : expression OR expression') def logicoperators2(p): op = p[1] e1 = p[0] e2 = p[2] if op.gettokentype() == "AND": return And(e1, e2) else: return Or(e1, e2) @self.pg.production('expression : NOT expression') def logicoperator1(p): return ExpressionBase(Not(p[1]).eval(), "boolean") @self.pg.production('expression : expression IS expression') @self.pg.production('expression : expression LESS expression') @self.pg.production('expression : expression LESSE expression') @self.pg.production('expression : expression MORE expression') @self.pg.production('expression : expression MOREE expression') def comparators(p): c = p[1] e1 = p[0] e2 = p[2] if c.gettokentype() == "IS": return Egal(e1, e2) elif c.gettokentype() == "LESS": return Less(e1, e2) elif c.gettokentype() == "MORE": return More(e1, e2) elif c.gettokentype() == "LESSE": return LessOrEgal(e1, e2) else: return MoreOrEgal(e1, e2) @self.pg.production('expression : SUB expression') @self.pg.production('expression : SUM expression') def uniqueop(p): ope = p[0] exp = p[1] if ope.gettokentype() == 'SUM': return Sum(ExpressionBase(0, "integer"), exp) else: return Sub(ExpressionBase(0, "integer"), exp) @self.pg.production( 'expression : IDENTIFIER CRO_OPEN INTEGER CRO_CLOSE') def expressionlist(p): var = self.var.get(p[0].value) if var is not None: return var.get(int(p[2].value)) else: error(errors.NOTDECLARED, "Variable is not declared.", { "type": "token", "token": p[0] }) sys.exit(1) @self.pg.production('expression : FLOAT') @self.pg.production('expression : INTEGER') @self.pg.production('expression : STRING') @self.pg.production('expression : BOOLEAN') @self.pg.production('expression : IDENTIFIER') def expression(p): if p[0].gettokentype() == 'FLOAT': return ExpressionBase(float(p[0].value), "float") elif p[0].gettokentype() == 'STRING': return ExpressionBase(str(p[0].value)[1:-1], "string") elif p[0].gettokentype() == 'BOOLEAN': if p[0].value == "false": return ExpressionBase(False, "boolean") return ExpressionBase(True, "boolean") elif p[0].gettokentype() == 'IDENTIFIER': var = self.var.get(p[0].value) if var is not None: return ExpressionBase(var.value, var.kind, var) else: error(errors.NOTDECLARED, "Variable is not declared.", { "type": "token", "token": p[0] }) sys.exit(1) else: return ExpressionBase(int(p[0].value), "integer") @self.pg.error def error_handle(token): print("Syntax unexcepted : \n - Position :", token.getsourcepos(), "\n - Token : Valeur =", token.getstr(), "| Type =", token.gettokentype()) sys.exit(1) def get_parser(self): parser = self.pg.build() return parser
class Parser(): def __init__(self, module, builder, printf): self.pg = ParserGenerator([ 'PROG', 'BEGIN', 'END', 'OP', 'CP', 'TZ', 'TT', 'Z', 'FUNC', 'VAR', 'INT', 'REAL', 'NUMBER', 'ID', 'ASSIGN', 'EQUAL', 'NOT_EQUAL', 'AND', 'NOT', 'OR', 'MORE', 'LESS', 'SUM', 'SUB', 'MUL', 'DIV', 'IF', 'ELSE', 'WHILE', 'DO', 'BREAKCONTINUE', 'PRINT' ], precedence=[("left", ['MUL', 'DIV']), ("left", ['SUM', 'SUB'])]) self.module = module self.builder = builder self.printf = printf def parse(self): @self.pg.production( 'program : PROG ID TZ var functions BEGIN statements END') def program(p): return p[6] @self.pg.production('var : VAR variable TT type TZ') def var(p): return p[1] @self.pg.production('var : VAR variable TT type TZ var') def var2(p): return p[1], p[5] @self.pg.production('variable : ID') def variable(p): return p[0] @self.pg.production('variable : ID Z variable') def variable2(p): return p[0], p[2] @self.pg.production('type : INT') @self.pg.production('type : REAL') def type(p): return p[0] @self.pg.production('functions : function') def functions(p): return p[0].eval() @self.pg.production('functions : function functions') def functions2(p): return Eval_(self.builder, self.module, p[0], p[2]) @self.pg.production( 'function : FUNC ID OP var CP TT type TZ BEGIN statements END') def function(p): return Func_(self.builder, self.module, p[1], p[3], p[9]) @self.pg.production('expression : OP expression CP') def expression(p): return p[1] @self.pg.production('expression : expression SUM expression') @self.pg.production('expression : expression SUB expression') @self.pg.production('expression : expression MUL expression') @self.pg.production('expression : expression DIV expression') def expression(p): if p[1].gettokentype() == 'SUM': return Sum(self.builder, self.module, p[0], p[2]) elif p[1].gettokentype() == 'SUB': return Sub(self.builder, self.module, p[0], p[2]) elif p[1].gettokentype() == 'MUL': return Mul(self.builder, self.module, p[0], p[2]) elif p[1].gettokentype() == 'DIV': return Div(self.builder, self.module, p[0], p[2]) @self.pg.production('expression : NUMBER') def number(p): return Number(self.builder, self.module, p[0].value) @self.pg.production('expression : ID') def expression_id(p): return Id_load(self.builder, self.module, p[0]) @self.pg.production('expression : ID OP variable CP') def function3(p): return Call_(self.builder, self.module, p[0], p[2]) @self.pg.production('statements : statement TZ') def statements(p): return p[0] @self.pg.production('statements : statement TZ statements') def statements2(p): return Eval_(self.builder, self.module, p[0], p[2]) @self.pg.production('statement : type ID ASSIGN expression') def assign(p): print(p[0].value) return Id_save(self.builder, self.module, p[0], p[1], p[3]) @self.pg.production( 'statement : IF OP bool CP BEGIN statements END ELSE BEGIN statements END' ) def if_(p): return If_else(self.builder, self.module, p[2], p[5], p[9]) @self.pg.production('statement : IF OP bool CP BEGIN statements END') def if_2(p): return If_(self.builder, self.module, p[2], p[5]) @self.pg.production( 'statement : WHILE OP bool CP DO BEGIN statements END') def while_(p): return While_(self.builder, self.module, p[2], p[6]) @self.pg.production('statement : BREAKCONTINUE ') def breakcontinue(p): global goto goto = p[0].getstr() return @self.pg.production('statement : PRINT OP expression CP') def print_(p): return Print(self.builder, self.module, self.printf, p[2]) @self.pg.production('bool : OP bool CP') def bool_(p): return p[1] @self.pg.production('bool : expression EQUAL expression') @self.pg.production('bool : expression MORE expression') @self.pg.production('bool : expression LESS expression') @self.pg.production('bool : expression NOT_EQUAL expression') def bool_2(p): if p[1].gettokentype() == 'EQUAL': return Equal(self.builder, self.module, p[0], p[2]) elif p[1].gettokentype() == 'MORE': return More(self.builder, self.module, p[0], p[2]) elif p[1].gettokentype() == 'LESS': return Less(self.builder, self.module, p[0], p[2]) elif p[1].gettokentype() == 'NOT_EQUAL': return Not_equal(self.builder, self.module, p[0], p[2]) @self.pg.production('bool : bool AND bool') def and_(p): return And_(self.builder, self.module, p[0], p[2]) @self.pg.production('bool : bool OR bool') def or_(p): return Or_(self.builder, self.module, p[0], p[2]) @self.pg.production('bool : NOT bool') def not_(p): return Not_(self.builder, self.module, p[1]) @self.pg.error def error_handle(token): raise ValueError(token) def get_parser(self): return self.pg.build()
class Parser(): def __init__(self, module, builder, printf): self.pg = ParserGenerator( # A list of all token names, accepted by the parser. ['SUM', 'SUB', 'MUL', 'DIV', 'OPEN_PAREN', 'CLOSE_PAREN', 'SEMI_COLON', 'NUMBER', 'PRINT', ], # A list of precedence rules with ascending precedence, to # disambiguate ambiguous production rules. precedence=[ ('left', ['SUM', 'SUB', ]), ('left', ['MUL', 'DIV', ]), ] ) self.module = module self.builder = builder self.printf = printf def parse(self): @self.pg.production('program : PRINT OPEN_PAREN expression CLOSE_PAREN SEMI_COLON') def program(p): return Print(self.builder, self.module, self.printf, p[2]) @self.pg.production('expression : OPEN_PAREN expression CLOSE_PAREN') def expression_parens(p): expression = p[1] return expression @self.pg.production('expression : expression SUM expression') @self.pg.production('expression : expression SUB expression') @self.pg.production('expression : expression MUL expression') @self.pg.production('expression : expression DIV expression') def expression(p): left = p[0] right = p[2] operator = p[1] if operator.gettokentype() == 'SUM': return Sum(self.builder, self.module, left, right) elif operator.gettokentype() == 'SUB': return Sub(self.builder, self.module, left, right) elif operator.gettokentype() == 'MUL': return Mul(self.builder, self.module, left, right) elif operator.gettokentype() == 'DIV': return Div(self.builder, self.module, left, right) @self.pg.production('expression : expression expression', precedence='MUL') def implicit_multiplication(p): left = p[0] right = p[1] return Mul(self.builder, self.module, left, right) @self.pg.production('expression : NUMBER') def number(p): return Number(self.builder, self.module, p[0].value) @self.pg.error def error_handle(token): raise ValueError(token) def get_parser(self): return self.pg.build()
class Parser(): def __init__(self): self.pg = ParserGenerator([ 'NUMBER', 'STRING', 'IDENT', 'PRINT', 'READ', 'INT', 'IF', 'THEN', 'ELSE', 'END_IF', 'FOR', 'UNTIL', 'STEP', 'END_FOR', 'OPEN_PAREN', 'CLOSE_PAREN', 'END_STATEMENT', 'DECLARE_TYPE', 'ADD', 'SUB', 'MULT', 'DIV', 'LESS', 'MORE', 'LESS_EQ', 'MORE_EQ', ], precedence=[('left', ['ADD', 'SUB']), ('left', ['MUL', 'DIV'])]) self.vars = {} self.flags = {"for": False, "while": False, "if": False} def parse(self): @self.pg.production("main : expression") def main(p): return p[0] @self.pg.production( "expression : PRINT OPEN_PAREN expression CLOSE_PAREN END_STATEMENT" ) def imprime(p): if isinstance(p[2], Identificador): if p[2].nome in self.vars.keys(): return Imprime(self.vars[p[2].nome]) return Imprime(p[2]) @self.pg.production( "expression : READ OPEN_PAREN expression CLOSE_PAREN END_STATEMENT" ) def read_input(p): new_ident, new_value = Leia(p[2]).eval() self.vars[new_ident.nome].value = new_value return new_ident @self.pg.production('expression : IF expression THEN expression END_IF' ) @self.pg.production( 'expression : IF expression THEN expression ELSE expression END_IF' ) def expression_conditional_complete(p): if len(p) > 5: return p[3] if p[1].eval() else p[5] return p[3] if p[1].eval() else Nulo() @self.pg.production( 'expression : FOR expression UNTIL expression STEP expression expression END_FOR' ) def expression_control_loop(p): if isinstance(p[1], Identificador): if p[1].nome in self.vars.keys(): base = self.vars[p[1].nome] if isinstance(p[3], Identificador): if p[3].nome in self.vars.keys(): limite = self.vars[p[3].nome] if isinstance(base, Identificador) and isinstance( limite, Identificador): return ForLoop(base, limite, p[5], p[6]) return ForLoop(p[1], p[3], p[5], p[6]) @self.pg.production( 'expression : expression DECLARE_TYPE expression END_STATEMENT') def expression_attr(p): type_ident = p[0] ident = p[2] atrib = Atribuicao(type_ident, ident) ident_to_be_stored = atrib.right.tipo.value self.vars[ident_to_be_stored] = atrib.right return atrib @self.pg.production('expression : expression LESS expression') @self.pg.production('expression : expression MORE expression') @self.pg.production('expression : expression LESS_EQ expression') @self.pg.production('expression : expression MORE_EQ expression') def expression_bool(p): left = p[0] right = p[2] operator = p[1] if isinstance(p[0], Identificador): if p[0].nome in self.vars.keys(): left = self.vars[p[0].nome] if isinstance(p[2], Identificador): if p[2].nome in self.vars.keys(): right = self.vars[p[2].nome] if operator.gettokentype() == 'LESS': return Less(left, right) elif operator.gettokentype() == 'MORE': return More(left, right) elif operator.gettokentype() == 'LESS_EQ': return LessEqual(left, right) elif operator.gettokentype() == 'MORE_EQ': return MoreEqual(left, right) @self.pg.production('expression : expression ADD expression') @self.pg.production('expression : expression SUB expression') @self.pg.production('expression : expression MULT expression') @self.pg.production('expression : expression DIV expression') def expression_arg(p): left = p[0] right = p[2] operator = p[1] if isinstance(p[0], Identificador): if p[0].nome in self.vars.keys(): left = self.vars[p[0].nome] if isinstance(p[2], Identificador): if p[2].nome in self.vars.keys(): right = self.vars[p[2].nome] if operator.gettokentype() == 'ADD': return Add(left, right) elif operator.gettokentype() == 'SUB': return Sub(left, right) elif operator.gettokentype() == 'MULT': return Mult(left, right) elif operator.gettokentype() == 'DIV': return Div(left, right) @self.pg.production('expression : IDENT') def identifier(p): return Identificador(p[0].value, p[0]) @self.pg.production('expression : NUMBER') def number(p): return Numero(p[0].value) @self.pg.production('expression : STRING') def string(p): return String(p[0].value) @self.pg.production('expression : INT') def tipo(p): return Tipo(p[0].value) @self.pg.error def error_handle(token): raise ValueError(token) def get_parser(self): return self.pg.build()
class Parser(): def __init__(self, token_names): self.pg = ParserGenerator( # A list of all token names accepted by the parser. token_names) def parse(self): @self.pg.production( 'statement : IDENTIFIER parameter_list_specifier block_specifier quantity_specifier SEMI_COLON' ) @self.pg.production('statement : empty') def statement(p): # logic pass @self.pg.production( 'parameter_list_specifier : OPEN_PAREN parameter_list CLOSE_PAREN') @self.pg.production('parameter_list_specifier : empty') def parameter_list_specifier(p): # logic pass @self.pg.production( 'block_specifier : OPEN_CURLY statement_list CLOSE_CURLY') @self.pg.production('block_specifier : empty') def block_specifier(p): # logic pass @self.pg.production('statement_list : statement') @self.pg.production('statement_list : statement_list statement') @self.pg.production('statement_list : plain_text') def statement_list(p): # logic pass @self.pg.production('parameter_list : parameter_declaration') @self.pg.production( 'parameter_list : parameter_list COMMA parameter_declaration') def parameter_list(p): # logic pass @self.pg.production('parameter_declaration : STRING EQU STRING') @self.pg.production('parameter_declaration : empty') def parameter_declaration(p): # logic pass @self.pg.production('quantity_specifier : MUL NUMBER') @self.pg.production('quantity_specifier : empty') def quantity_specifier(p): # logic pass @self.pg.production('plain_text : STRING') @self.pg.production('plain_text : empty') def plain_text(p): # logic pass # success area begins here: @self.pg.production('quantity_specifier : MUL NUMBER') def quantity_specifier(p): return Number(p[0].value) @self.pg.production('empty :') def empty(p): pass @self.pg.error def error_handle(token): raise ValueError(token) def get_parser(self): return self.pg.build()
class Parser(): def __init__(self): self.pg = ParserGenerator( # A list of all token names accepted by the parser. ['NUMBER', 'PRINTTOLCD', 'OPEN_PAREN', 'CLOSE_PAREN', 'SEMI_COLON', 'SUM', 'SUB', 'STRING', 'SLEEP', 'OUTPUT', 'PINON', 'PINOFF', 'EQUAL', 'VAR','VARNAME','GETVAR','IF','ENDIF','THEN','EQUAL'] ) def parse(self): @self.pg.production('program : PRINTTOLCD OPEN_PAREN expression CLOSE_PAREN SEMI_COLON') def program(p): return Print(p[2]) @self.pg.production('program : SLEEP OPEN_PAREN expression CLOSE_PAREN SEMI_COLON') def sleep(p): return Sleep(p[2]) @self.pg.production('program : OUTPUT OPEN_PAREN expression CLOSE_PAREN SEMI_COLON') def output(p): return Output(p[2]) @self.pg.production('program : PINON OPEN_PAREN expression CLOSE_PAREN SEMI_COLON') def pinon(p): return PinOn(p[2]) @self.pg.production('program : PINOFF OPEN_PAREN expression CLOSE_PAREN SEMI_COLON') def pinoff(p): return PinOff(p[2]) @self.pg.production('program : VAR expression EQUAL expression SEMI_COLON') def var(p): return setVar(p[1],p[3]) @self.pg.production('program : IF expression EQUAL expression THEN program ENDIF') def ifstatement(p): return IfStatement(p[1],p[3],p[5]) @self.pg.production('expression : expression SUM expression') @self.pg.production('expression : expression SUB expression') def expression(p): left = p[0] right = p[2] operator = p[1] if operator.gettokentype() == 'SUM': return Sum(left, right) elif operator.gettokentype() == 'SUB': return Sub(left, right) @self.pg.production('expression : STRING') def string(p): return String(p[0].value) @self.pg.production('expression : VARNAME') def varname(p): s = p[0].value return Letter(s) # @self.pg.production('expression : GETVAR') # def getvar(p): # s = p[0].value # return getVar(s) @self.pg.production('expression : NUMBER') def number(p): return Number(p[0].value) @self.pg.error def error_handle(token): raise ValueError("Ran into a %s where it wasn't expected" + token.gettokentype) def get_parser(self): return self.pg.build()
class Parser(): def __init__(self, verbose=False): self.verbose = str(verbose).lower() self.setup_verbosity() self.parser_generator = ParserGenerator([ '$end', 'OPENQASM', 'INCLUDE', 'OPAQUE', 'BARRIER', 'IF', 'MEASURE', 'RESET', 'QREG', 'CREG', 'GATE', 'PAREN_OPEN', 'PAREN_CLOSE', 'STRING', 'OPEN_BRACKET', 'CLOSE_BRACKET', 'OPEN_BRACE', 'CLOSE_BRACE', 'SEMI_COLON', 'COLON', 'DASH', 'UNDER_SCORE', 'COMMA', 'QUOTE', 'U', 'CX', 'PLUS', 'MINUS', 'MUL', 'DIV', 'POW', 'PI', 'SIN', 'COS', 'TAN', 'EXP', 'LN', 'SQRT', 'ASSIGN_TO', 'EQU', 'ID', 'INT', 'REAL' ]) def setup_verbosity(self): global V V = getattr(importlib.import_module("qeda.verbose", self.verbose), self.verbose) V("Verbosity setup complete") def parse(self): @self.parser_generator.production( 'main : OPENQASM real SEMI_COLON program') @self.parser_generator.production( 'main : OPENQASM real SEMI_COLON include program') def main(p): V("Creating Main") V("QCODE: {}".format(QCODE)) return QCODE @self.parser_generator.production('include : INCLUDE STRING SEMI_COLON' ) def include(p): V("Including file {}".format(p[1])) return p[0] @self.parser_generator.production('program : statement') @self.parser_generator.production('program : program statement') def program(p): V("Creating program!") pass @self.parser_generator.production('statement : decl') @self.parser_generator.production( 'statement : gatedecl goplist CLOSE_BRACE') @self.parser_generator.production('statement : gatedecl CLOSE_BRACE') @self.parser_generator.production( 'statement : OPAQUE id idlist SEMI_COLON') @self.parser_generator.production( 'statement : OPAQUE id PAREN_OPEN PAREN_CLOSE idlist SEMI_COLON') @self.parser_generator.production( 'statement : OPAQUE id PAREN_OPEN idlist PAREN_CLOSE idlist SEMI_COLON' ) @self.parser_generator.production('statement : qop') @self.parser_generator.production( 'statement : IF PAREN_OPEN id EQU EQU int PAREN_CLOSE qop') @self.parser_generator.production( 'statement : BARRIER anylist SEMI_COLON') def statement(p): V("Creating statement!") pass @self.parser_generator.production( 'decl : QREG id OPEN_BRACKET int CLOSE_BRACKET SEMI_COLON') @self.parser_generator.production( 'decl : CREG id OPEN_BRACKET int CLOSE_BRACKET SEMI_COLON') def decl(p): V("Declaring register {} id {}".format(p[0].name, p[1].value)) if p[0].name == 'QREG': V("Creating quantum register") elif p[0].name == 'CREG': V("Creating classical register") pass @self.parser_generator.production( 'gatedecl : GATE id idlist OPEN_BRACE') @self.parser_generator.production( 'gatedecl : GATE id PAREN_OPEN PAREN_CLOSE idlist OPEN_BRACE') @self.parser_generator.production( 'gatedecl : GATE id PAREN_OPEN idlist PAREN_CLOSE idlist OPEN_BRACE' ) def gatedecl(p): V([x for x in p]) V('Declaring GATE: {}'.format(p[1].value)) if 'list' in str(type(p[2])): return GateDecl(p[1].value, args=p[2]) elif p[2].value == 'PAREN_OPEN': if len(p) == 7: return GateDecl(p[1].value, args=p[3]) return GateDecl(p[1].value, control=p[3]) @self.parser_generator.production('goplist : uop') @self.parser_generator.production('goplist : BARRIER idlist SEMI_COLON' ) @self.parser_generator.production('goplist : goplist uop') @self.parser_generator.production( 'goplist : goplist BARRIER idlist SEMI_COLON') def goplist(p): pass @self.parser_generator.production('qop : uop') @self.parser_generator.production( 'qop : MEASURE argument ASSIGN_TO argument SEMI_COLON') @self.parser_generator.production('qop : RESET argument SEMI_COLON') def qop(p): if "Token" in str(type(p[0])): V("Token") if p[0].name == 'MEASURE': V("MEASURE: {}, {}".format(p[1], p[3])) Measure(p[1]) V("Measure complete") elif p[0].name == 'RESET': V("RESET") else: return p[0] @self.parser_generator.production( 'uop : U PAREN_OPEN explist PAREN_CLOSE argument SEMI_COLON') @self.parser_generator.production( 'uop : CX argument COMMA argument SEMI_COLON') @self.parser_generator.production('uop : CX anylist SEMI_COLON') @self.parser_generator.production('uop : int anylist SEMI_COLON') @self.parser_generator.production( 'uop : int PAREN_OPEN PAREN_CLOSE anylist SEMI_COLON') @self.parser_generator.production( 'uop : int PAREN_OPEN explist PAREN_CLOSE anylist SEMI_COLON') @self.parser_generator.production( 'uop : id anylist SEMI_COLON' ) # Adds support for custom gates: ccx a,b,c; @self.parser_generator.production('uop : id id SEMI_COLON' ) # supports: y b; @self.parser_generator.production( 'uop : id id OPEN_BRACKET int CLOSE_BRACKET SEMI_COLON' ) # supports X a[1]; @self.parser_generator.production( 'uop : id PAREN_OPEN int PAREN_CLOSE SEMI_COLON') # Supports X(0); def uop(p): V('uop', p) if p[0].name in ('U', 'u'): V('U gate!') return p elif p[0].name in ('cx', 'CX'): V("CX Gate") if len(p) == 5: return CX(p[1], p[3]) else: return CX(p[0][0], p[0][1]) elif p[0].name == 'ID': V('a', p) if p[0].value.lower() == 'h': V("Hadamard!") return H(p[2]) elif p[0].value.lower() == 'i': V("Identity!") return I(p[2]) elif p[0].value.lower() == 's': V("S Gate") return S(p[2]) elif p[0].value.lower() == 'sdg': V("SDG Gate") return SDG(p[2]) elif p[0].value.lower() == 't': V("T Gate") return T(p[2]) elif p[0].value.lower() == 'tdg': V("TDG Gate") return TDG(p[2]) elif p[0].value.lower() == 'x': V("X Gate") return X(p[2]) elif p[0].value.lower() == 'y': V("Y Gate") return Y(p[2]) elif p[0].value.lower() == 'z': V("Z Gate") return Z(p[2]) elif p[0].value.lower() == 'rx': V("RX Gate") return RX(p[2]) elif p[0].value.lower() == 'ry': V("RY Gate") return RY(p[2]) elif p[0].value.lower() == 'rz': V("RZ Gate") return RZ(p[2]) else: V(p[0]) return p pass @self.parser_generator.production('anylist : idlist') @self.parser_generator.production('anylist : mixedlist') def anylist(p): x = [] if type(p[0]) == list: V("anylist list", p[0]) x = [x for x in p[0]] V("anylist list res", x) elif 'token' in str(type(p[0])): V('anylist token', p[0]) x = [x for x in p] return x @self.parser_generator.production('idlist : id COMMA id') @self.parser_generator.production('idlist : idlist COMMA id') def idlist(p): x = [] if type(p[0]) == list: V("idlist list", p[0]) x = [x for x in p[0]] x.append(p[2]) V('idlist list res', x) elif 'token' in str(type(p[0])): V('idlist token', p[0]) x = [p[0], p[2]] V('idlist token res', x) return x @self.parser_generator.production( 'mixedlist : id OPEN_BRACKET int CLOSE_BRACKET') @self.parser_generator.production('mixedlist : mixedlist COMMA id') @self.parser_generator.production( 'mixedlist : mixedlist COMMA id OPEN_BRACKET int CLOSE_BRACKET') @self.parser_generator.production( 'mixedlist : idlist COMMA id OPEN_BRACKET int CLOSE_BRACKET') def mixedlist(p): if 'token' in str(type(p[0])): x = [{'name': p[0], 'val': p[2]}] elif type(p[0]) == list: if len(p) == 3: x = [x for x in p[0]] x.append(p[2]) else: x = [x for x in p[0]] x.append({'name': [2], 'val': [4]}) V('mixedlist', x) return x @self.parser_generator.production('argument : id') @self.parser_generator.production('argument : real') @self.parser_generator.production('argument : int') @self.parser_generator.production('argument : anylist') def argument(p): V('arg', p) return p[0] @self.parser_generator.production('explist : expression') @self.parser_generator.production('explist : explist COMMA expression') def explist(p): if 'expression' in type(p[0]): x = [x for x in p] elif type(p[0]) == list: x = p[0] x.append(p[2]) return x @self.parser_generator.production('expression : real') @self.parser_generator.production('expression : int') @self.parser_generator.production('expression : PI') @self.parser_generator.production('expression : id') @self.parser_generator.production( 'expression : expression PLUS expression') @self.parser_generator.production( 'expression : expression MINUS expression') @self.parser_generator.production( 'expression : expression MUL expression') @self.parser_generator.production( 'expression : expression DIV expression') @self.parser_generator.production( 'expression : expression POW expression') @self.parser_generator.production( 'expression : PAREN_OPEN expression PAREN_CLOSE') @self.parser_generator.production( 'expression : unaryop PAREN_OPEN expression PAREN_CLOSE') def expression(p): V('expression', p) return p pass @self.parser_generator.production('unaryop : SQRT ') @self.parser_generator.production('unaryop : SIN ') @self.parser_generator.production('unaryop : COS ') @self.parser_generator.production('unaryop : TAN ') @self.parser_generator.production('unaryop : EXP ') @self.parser_generator.production('unaryop : LN ') def unaryop(p): V('unaryop', p) return p[0] @self.parser_generator.production('id : ID ') def id(p): V([p[x].value for x in range(len(p))]) V('setting id', p[0].value) return p[0] @self.parser_generator.production('int : INT') def nnint(p): V('setting int', p[0].value) return Int(p[0].value) @self.parser_generator.production('real : REAL') def real(p): V('setting float', p[0].value) return p[0] @self.parser_generator.error def error_handle(token): '''"Dirty" error handling''' V(token) raise ValueError(token) def get_parser(self): '''Returns a parser generator object''' return self.parser_generator.build()
class Pars(): def __init__(self): self.pg = ParserGenerator( ['INCLUDE', 'LIBstdio.h', 'MAIN', 'NUMBER', 'STR', 'PRINT', 'START', 'FINISH', 'OPEN_PARENS', 'CLOSE_PARENS', 'SEMI_COLON', 'SUM', 'SUB'], precedence=[('left', ['SUM', 'SUB']), ] ) def parse(self): @self.pg.production('expression : NUMBER') def number(p): return Number(int(p[0].value)) @self.pg.production('expression : STR') def strings(p): return String(p[0].value[1:-1]) @self.pg.production('expression : INCLUDE expression') def include(p): return p[1] @self.pg.production('expression : LIBstdio.h expression') def include(p): return p[1] @self.pg.production('expression : MAIN expression') def cmainc(p): return p[1] @self.pg.production('expression : START expression FINISH') def expression_start_finish(p): return p[1] @self.pg.production('expression : START OPEN_PARENS expression FINISH') def expression_open_parens(p): return p[1] @self.pg.production('expression : OPEN_PARENS expression CLOSE_PARENS') def expression_close_parens(p): return p[1] @self.pg.production('expression : START expression SEMI_COLON FINISH') def expression_semicolon(p): return p[1] @self.pg.production('expression : START expression SUM expression FINISH') @self.pg.production('expression : START expression SUB expression FINISH') def expression(p): left = p[0] right = p[2] operator = p[1] if operator.gettokentype() == 'SUM': return Sum(left, right) elif operator.gettokentype() == 'SUB': return Sub(left, right) @self.pg.production('expression : PRINT OPEN_PARENS expression CLOSE_PARENS SEMI_COLON') def expression(p): return Print(p[2]) @self.pg.error def error_handle(token): raise ValueError(token) def get_parser(self): return self.pg.build()
class ParserBuilder(object): # A list of all token names accepted by the parser. ACCEPTED_TOKENS = ( 'FROM', 'IMPORT', 'AS', 'LET', 'OPEN_CURLY_BRACKET', 'CLOSE_CURLY_BRACKET', 'FORWARD_SLASH', 'OPEN_PAREN', 'CLOSE_PAREN', 'OPEN_BRACKET', 'CLOSE_BRACKET', 'COLON', 'SEMICOLON', 'COMMA', 'PERIOD', 'NUMBER', 'IDENTIFIER', 'AMINO_ACID_SEQUENCE', 'EQUAL', 'TILDE', 'EXCLAMATION', ) def __init__(self): self.pg = ParserGenerator(self.ACCEPTED_TOKENS) self.build_parser() def build_parser(self): """Define the parser rules.""" # rply has it's own style which does not conform to pylint's expectations. # pylint: disable=W0613,C0103,W0612,C0301 @self.pg.production('program : import_list definition_list') @self.pg.production('program : import_list') @self.pg.production('program : definition_list') def program(state, p): imports = [] definition_list = None if len(p) == 2: # we have at least one import imports = p[0] definition_list = p[1] else: if isinstance(p[0], ast.DefinitionList): definition_list = p[0] else: imports = p[0] return ast.Program(imports, definition_list) @self.pg.production('import_list : import_list import') @self.pg.production('import_list : import') def program_import_list(state, p): if len(p) == 2: p[0].append(p[1]) return p[0] return [p[0]] @self.pg.production('import : FROM import_module IMPORT OPEN_PAREN import_identifiers CLOSE_PAREN') @self.pg.production('import : FROM import_module IMPORT import_identifiers') def program_import(state, p): if len(p) == 6: import_module = p[1] import_identifiers = p[4] if len(p) == 4: import_module = p[1] import_identifiers = p[3] return ast.Import(import_module, import_identifiers) @self.pg.production('import_module : import_module PERIOD IDENTIFIER') @self.pg.production('import_module : IDENTIFIER') def program_import_module(state, p): if len(p) == 3: return p[0] + [p[2].value] return [p[0].value] @self.pg.production('import_identifiers : import_identifiers COMMA import_identifier') @self.pg.production('import_identifiers : import_identifier') def program_import_identifiers(state, p): if len(p) == 3: p[0].append(p[2]) return p[0] return [p[0]] @self.pg.production('import_identifier : IDENTIFIER AS IDENTIFIER') @self.pg.production('import_identifier : IDENTIFIER') def import_identifier(state, p): import_identifier = p[0].value if len(p) == 3: alias_identifier = p[2].value else: alias_identifier = None return ast.ImportIdentifier(import_identifier, alias_identifier) @self.pg.production('definition_list : definition_list definition') @self.pg.production('definition_list : definition') def definition_list(state, p): if len(p) == 2: p[0].add_definition(p[1]) return p[0] return ast.DefinitionList([p[0]]) @self.pg.production('definition : variable_definition') @self.pg.production('definition : function_invoke') @self.pg.production('definition : assembly') def definition(state, p): return p[0] @self.pg.production('variable_definition : LET IDENTIFIER EQUAL definition_item') @self.pg.production('variable_definition : LET IDENTIFIER EQUAL function_invoke') @self.pg.production('variable_definition : LET IDENTIFIER EQUAL list_declaration') @self.pg.production('variable_definition : LET IDENTIFIER type_declaration EQUAL list_declaration') def variable_definition(state, p): variable_identifier = p[1].value if len(p) == 4: variable_type = None definition = p[3] elif len(p) == 5: variable_type = p[2] definition = p[4] return ast.VariableDeclaration(variable_identifier, variable_type, definition) @self.pg.production('type_declaration : OPEN_BRACKET IDENTIFIER CLOSE_BRACKET') def type_declaration(state, p): return ast.TypeDeclaration(p[1].value) @self.pg.production('list_declaration : OPEN_BRACKET list_items CLOSE_BRACKET') def list_declaration(state, p): return ast.ListDeclaration(p[1]) @self.pg.production('list_items : definition_item') @self.pg.production('list_items : definition_item COMMA list_items') def list_items(state, p): new_list = [p[0]] if len(p) == 3: new_list.extend(p[2]) return new_list @self.pg.production('definition_item : symbol_reference') @self.pg.production('definition_item : nucleotide_constant') @self.pg.production('definition_item : amino_acid_constant') @self.pg.production('definition_item : number_constant') def definition_item(state, p): return p[0] @self.pg.production('function_name_and_label : IDENTIFIER') @self.pg.production('function_name_and_label : IDENTIFIER COLON IDENTIFIER') def function_name_and_label(state, p): if len(p) == 3: # return Name and label return p[2].value, p[0].value return p[0].value, None @self.pg.production('function_invoke : function_name_and_label function_parameter_block') @self.pg.production('function_invoke : function_name_and_label OPEN_CURLY_BRACKET definition_list CLOSE_CURLY_BRACKET') def function_invoke(state, p): if len(p) == 2: return ast.FunctionInvocation(p[0][0], None, p[1], p[0][1]) return ast.FunctionInvocation(p[0][0], p[2], None, p[0][1]) @self.pg.production('function_parameter_block : OPEN_PAREN function_parameters CLOSE_PAREN') @self.pg.production('function_parameter_block : OPEN_PAREN CLOSE_PAREN') def function_param_block(state, p): if len(p) == 2: return None return p[1] @self.pg.production('function_parameters : definition_item') @self.pg.production('function_parameters : definition_item COMMA function_parameters') def function_parameters(state, p): x = [p[0]] if len(p) == 3: x.extend(p[2]) return x @self.pg.production('assembly : assembly_list') @self.pg.production('assembly : IDENTIFIER COLON assembly_list') def assembly(state, p): if len(p) == 1: return ast.Assembly(p[0]) elif len(p) == 3: return ast.Assembly(p[2], label=p[0].value) @self.pg.production('assembly_list : assembly_list SEMICOLON definition_item') @self.pg.production('assembly_list : definition_item') def assembly_list(state, p): if len(p) == 1: return [p[0]] elif len(p) == 3: p[0].append(p[2]) return p[0] @self.pg.production('number_constant : NUMBER') def number_constant(state, p): return ast.Constant(p[0].value, NUMBER_CONSTANT) @self.pg.production('nucleotide_constant : FORWARD_SLASH IDENTIFIER FORWARD_SLASH') def nucleotide_constant(state, p): return ast.SequenceConstant(p[1].value, UNAMBIGUOUS_DNA_SEQUENCE) @self.pg.production('amino_acid_constant : FORWARD_SLASH AMINO_ACID_SEQUENCE FORWARD_SLASH') def protein_constant(state, p): return ast.SequenceConstant(p[1].value[1:], UNAMBIGUOUS_PROTEIN_SEQUENCE) @self.pg.production('symbol_reference : symbol_identifier OPEN_BRACKET slice_index CLOSE_BRACKET') @self.pg.production('symbol_reference : symbol_identifier') def symbol_reference(state, p): identifier, invert = p[0] part_slice = None if len(p) == 4: part_slice = p[2] return ast.SymbolReference(identifier, part_slice, invert) @self.pg.production('symbol_identifier : EXCLAMATION IDENTIFIER') @self.pg.production('symbol_identifier : IDENTIFIER') def symbol_identifier(state, p): if len(p) == 2: invert = True identifier = p[1].value else: invert = False identifier = p[0].value return (identifier, invert) @self.pg.production('slice_index : slice_position COLON slice_position') def index_slice(state, p): return ast.Slice(p[0], p[2]) @self.pg.production('slice_position : TILDE slice_coordinates') @self.pg.production('slice_position : slice_coordinates') def slice_position(state, p): if len(p) == 2: approximate = True position_index, postfix = p[1] else: approximate = False position_index, postfix = p[0] return ast.SlicePosition(position_index, postfix, approximate) @self.pg.production('slice_coordinates : NUMBER') @self.pg.production('slice_coordinates : NUMBER IDENTIFIER') def slice_coordinates(state, p): position_index = int(p[0].value) postfix = None if len(p) == 2: postfix = p[1].value if postfix not in ['S', 'E']: raise ParsingError('Slice postfix can only be "S" or "E"') return (position_index, postfix) @self.pg.error def error_handle(state, lookahead): raise ParsingError( 'An error occurred parsing source document at %s' % lookahead.source_pos) def parse(self, tokens): parser = self.pg.build() parser_state = ParserState() return parser.parse(tokens, state=parser_state)
def __init__(self): # define the parser pg = ParserGenerator( [ "NUMBER", "PLUS", "MINUS", "MULTIPLY", "DIVIDE", "SEMICOLON", "PRINT", "PRINTLN", "STRING", "EQUAL", "IDENTIFIER", "BOOLEAN", "LBRACE", "RBRACE", "LPAREN", "RPAREN", "IF", "ELSE", "BOOLEAN_AND", "BOOLEAN_OR", "EQUAL_EQUAL", "NOT_EQUAL", "GREATER", "LESS", "GREATER_EQUAL", "LESS_EQUAL", "WHILE", "FOR" ], # A list of precedence rules with ascending precedence, to # disambiguate ambiguous production rules. precedence=[ ('left', ['LPAREN', 'RPAREN']), ('left', ['PLUS', 'MINUS']), ('left', ['MUL', 'DIV']), ('right', ['EQUAL']), ]) # parser definition # top-level statements @pg.production("main : statements") def main(s): # return the statement block return s[0] # multiple statement statements @pg.production("statements : statements statement") def statements(s): return ast.Block(s[0].getASTList() + [s[1]]) # single statement statements @pg.production("statements : statement") def statements_statement(s): return ast.Block([s[0]]) # single expression statement @pg.production("statement : expr SEMICOLON") def statement_expr(s): return ast.Statement(s[0]) # print/println statements @pg.production("statement : PRINT expr SEMICOLON") @pg.production("statement : PRINTLN expr SEMICOLON") def statement_print(s): return ast.PrintStatement(s[0].getstr(), s[1]) # while statement # can end with semicolon or not @pg.production( "statement : WHILE LPAREN expr RPAREN LBRACE statements RBRACE SEMICOLON" ) @pg.production( "statement : WHILE LPAREN expr RPAREN LBRACE statements RBRACE") def statement_while(s): return ast.WhileStatement(s[2], s[5]) # for statement # can end with semicolon or not @pg.production( "statement : FOR LPAREN statement expr SEMICOLON statement RPAREN LBRACE statements RBRACE SEMICOLON" ) @pg.production( "statement : FOR LPAREN statement expr SEMICOLON statement RPAREN LBRACE statements RBRACE" ) def statement_for(s): return ast.ForStatement(s[2], s[3], s[5], s[8]) # parenthese support for expressions # not working @pg.production("val : LPAREN expr RPAREN") def expr_parens(s): return ast.ParentheseValue(s[1]) # assignment expression @pg.production("expr : expr EQUAL expr") def expr_assignment(s): return ast.AssignmentExpression(s[0], s[2]) # binary operator expressions # algebratic operations -> return number @pg.production("expr : expr PLUS expr") @pg.production("expr : expr MINUS expr") @pg.production("expr : expr MULTIPLY expr") @pg.production("expr : expr DIVIDE expr") # boolean operations -> return boolean @pg.production("expr : expr BOOLEAN_OR expr") @pg.production("expr : expr BOOLEAN_AND expr") # number operations -> return boolean @pg.production("expr : expr GREATER_EQUAL expr") @pg.production("expr : expr LESS_EQUAL expr") @pg.production("expr : expr GREATER expr") @pg.production("expr : expr LESS expr") # for both number and booleans -> return boolean @pg.production("expr : expr EQUAL_EQUAL expr") @pg.production("expr : expr NOT_EQUAL expr") def expr_binop(s): return ast.BinaryOperator(s[1].getstr(), s[0], s[2]) # single value/identifier expression @pg.production("expr : val") def expr_val(s): return ast.Expr(s[0]) # single identifier expression @pg.production("expr : IDENTIFIER") def expr_id(s): return ast.Expr(ast.Identifier(s[0].getstr())) # single if expression, body of if expression can be either statements or expression # if expression is evaluated to Null if the body are statements # body must be consistent, which means all the clause has to be either expressions or statements # don't forget semicolor at the end of the if block @pg.production("expr : IF LPAREN expr RPAREN LBRACE expr RBRACE ") @pg.production("expr : IF LPAREN expr RPAREN LBRACE statements RBRACE") def expr_if(s): return ast.IfExpression(s[2], s[5]) # if - else if - else expression. Else - if is optional @pg.production( "expr : IF LPAREN expr RPAREN LBRACE expr RBRACE else-if-body-list else-body" ) @pg.production( "expr : IF LPAREN expr RPAREN LBRACE statements RBRACE else-if-body-list else-body" ) def expr_if_elseif_else(s): return ast.IfElseIfElseExpression(s[2], s[5], s[7], s[8]) # if - else expression. DO NOT INCLUDE else if body lists (put placeholder empty else if body list) @pg.production( "expr : IF LPAREN expr RPAREN LBRACE expr RBRACE else-body") @pg.production( "expr : IF LPAREN expr RPAREN LBRACE statements RBRACE else-body") def expr_if_else(s): return ast.IfElseIfElseExpression(s[2], s[5], ast.ElseIfBodyList([]), s[7]) # define the else if body in the case of multiple (one or more) else - if expressions @pg.production("else-if-body-list : else-if-body-list else-if-body") @pg.production("else-if-body-list : else-if-body-list else-if-body") def expr_else_if_body_list(s): return ast.ElseIfBodyList(s[0].getASTList() + [s[1]]) # define a single else-if-body as a else-if-body-list @pg.production("else-if-body-list : else-if-body") def expr_else_if_body_list__else_if_body(s): return ast.ElseIfBodyList([s[0]]) @pg.production( "else-if-body : ELSE IF LPAREN expr RPAREN LBRACE expr RBRACE") @pg.production( "else-if-body : ELSE IF LPAREN expr RPAREN LBRACE statements RBRACE" ) def expr_else_if_body(s): return ast.ElseIfBody(s[3], s[6]) # define the else body @pg.production("else-body : ELSE LBRACE expr RBRACE") @pg.production("else-body : ELSE LBRACE statements RBRACE") def expr_else_body(s): return ast.ElseBody(s[2]) # number value @pg.production("val : NUMBER") def val_number(s): return ast.Number(float(s[0].getstr())) # string value @pg.production("val : STRING") def val_string(s): return ast.String(s[0].getstr()) # boolean value @pg.production("val : BOOLEAN") def val_boolean(s): return ast.Boolean(s[0].getstr()) # build the parser self.parser = pg.build()
class Parser(): def __init__(self, state): self.state = state self.pg = ParserGenerator( # A list of all token names accepted by the parser. [ 'NUMBER', 'DOT', 'COMMA', 'HYPHEN', 'OPEN_PAREN', 'CLOSE_PAREN', 'ATHOM', 'DEF_BASE', 'DEF_NOT', 'NOT', 'IFF', 'IMPLIE', 'AND', 'OR', 'DEF_IFF', 'DEF_IMPLIE', 'DEF_AND', 'DEF_OR' ], precedence=[('left', ['NOT', 'AND', 'OR', 'IMPLIE', 'IFF'])]) self.variables = {} self.formule_latex = '' self.error = {'messages': []} def parse(self): @self.pg.production('program : steps') def program(p): data = {} if len(self.error['messages']): firstMessage = 'Os seguintes erros foram encontrados:' data["status"] = "error" data["firstMessage"] = firstMessage error_number = 1 errorList = [] for error_message in self.error['messages']: errorList.append('Erro {}: {}'.format( error_number, error_message)) error_number += 1 data["errorList"] = errorList data["errorNumber"] = error_number else: firstMessage = 'Fórmulas estão corretas. Código látex:' data["status"] = 'ok' data["firstMessage"] = firstMessage latex = '\\[\n' + self.variables[list( self.variables)[-1]][0].toLatex() + '\\]\n' data["latex"] = latex fileHandle(data) @self.pg.production('steps : steps step') @self.pg.production('steps : step') def steps(p): return self.variables @self.pg.production('step : NUMBER DOT ATHOM athoms DEF_BASE') def step_base(p): number_line = p[0].value athoms = [p[2].value] + p[3] if number_line in self.variables: for athom in athoms: self.variables[number_line].append( BinaryFormule(key=athom)) source_position = p[0].getsourcepos() line_error = source_position.lineno self.set_error(1, line_error, number_line) return self.variables[number_line] = [] for athom in athoms: self.variables[number_line].append(BinaryFormule(key=athom)) @self.pg.production('step : NUMBER DOT formule DEF_NOT NUMBER') def step_negation(p): number_line = p[0].value formule = p[2] source_position = p[0].getsourcepos() line_error = source_position.lineno if isinstance(formule, BinaryFormule): self.variables[number_line] = [formule] self.set_error(3, line_error, formule.toString()) return if number_line in self.variables: self.variables[number_line] = self.variables[number_line] + [ formule ] self.set_error(1, line_error, number_line) return if not (p[4].value in self.variables): self.variables[number_line] = [formule] self.set_error(2, line_error, p[4].value) return self.variables[number_line] = [formule] if not (negationDef().eval(formule, p[4].value, self.variables)): self.set_error(4, line_error, formule.toString()) @self.pg.production( 'step : NUMBER DOT formule DEF_AND NUMBER HYPHEN NUMBER') @self.pg.production( 'step : NUMBER DOT formule DEF_OR NUMBER HYPHEN NUMBER') @self.pg.production( 'step : NUMBER DOT formule DEF_IMPLIE NUMBER HYPHEN NUMBER') @self.pg.production( 'step : NUMBER DOT formule DEF_IFF NUMBER HYPHEN NUMBER') def step(p): formule = p[2] operator = formule.key line_error = p[0].getsourcepos().lineno number_line = p[0].value used_formule1_line = p[4].value used_formule2_line = p[6].value if number_line in self.variables: self.variables[number_line] = self.variables[number_line] + [ formule ] self.set_error(1, line_error, number_line) return if not (used_formule1_line in self.variables): self.variables[number_line] = [formule] self.set_error(2, line_error, used_formule1_line) return if not (used_formule2_line in self.variables): self.variables[number_line] = [formule] self.set_error(2, line_error, used_formule2_line) return self.variables[number_line] = [formule] result = binaryDef().eval(p[2], operator, used_formule1_line, used_formule2_line, self.variables) if result == 0: self.set_error(0, line_error, formule.left.toString()) elif result == 1: self.set_error(0, line_error, formule.right.toString()) @self.pg.production('formule : NOT formule') @self.pg.production('formule : ATHOM') @self.pg.production('formule : formule AND formule') @self.pg.production('formule : formule OR formule') @self.pg.production('formule : formule IMPLIE formule') @self.pg.production('formule : formule IFF formule') def formule(p): if len(p) < 3: if p[0].gettokentype() == 'ATHOM': return BinaryFormule(key=p[0].value) if p[0].gettokentype() == 'NOT': return UnaryFormule(key=p[1]) else: return BinaryFormule(key=p[1].value, left=p[0], right=p[2]) @self.pg.production('formule : OPEN_PAREN formule CLOSE_PAREN') def paren_formule(p): return p[1] @self.pg.production('athoms : COMMA ATHOM athoms') @self.pg.production('athoms : ') def athoms(p): if (len(p) == 0): return [] else: return [p[1].value] + p[2] @self.pg.error def error_handle(token): productions = self.state.splitlines() error = '' if (productions == ['']): error = 'Nenhuma demonstração foi recebida, verifique a entrada.' if token.gettokentype() == '$end': error = 'Uma das definições não está completa, verifica se todas regras foram aplicadas corretamente.' else: source_position = token.getsourcepos() line = source_position.lineno error = "token {} não esperado na linha {}: {}".format( token.value, line, productions[line - 1]) data = { 'status': 'error', 'firstMessage': 'O seguinte erro foi encontrado', 'error': error } fileHandle(data) raise ValueError(error) def set_error(self, type, line_error, token_error): productions = self.state.splitlines() if type == 0: self.error['messages'].append( "A fórmula {} não foi definido anteriormente, na linha {}: {}". format(token_error, line_error, productions[line_error - 1])) elif type == 1: self.error['messages'].append( "Número {} já foi definido antes da linha {}: {}".format( token_error, line_error, productions[line_error - 1])) elif type == 2: self.error['messages'].append( "linha não definida {} referenciado na linha {}: {}".format( token_error, line_error, productions[line_error - 1])) elif type == 3: self.error['messages'].append( "Fórmula {} é binaria, quando o esperado é uma negação, na linha {}: {}" .format(token_error, line_error, productions[line_error - 1])) else: self.error['messages'].append( "Fórmula {} utilizado na linha {} não foi definido anteriormente: {}" .format(token_error[1:], line_error, productions[line_error - 1])) def get_parser(self): return self.pg.build()
@PG.production("charge : + DIGIT") def charge_production_plus_many(p): "+D" return +int_from_digit(p[1]) ##### ATOM CLASS ##### # class ::= ':' NUMBER # class :: int @PG.production("class : colon NUMBER") def class_production(p): "return :: int." return p[1] @PG.error def error_handler(token, expected=None): "Handle parser errors." if DEBUG: raise ValueError(("Ran into a %s (%s) where it wasn't expected."+\ "At %s. Instead expected: %s.") % (repr(token.name), \ repr(token.value), dictof(token.source_pos), repr(expected))) else: print "Warning: parser error" LEXER = LG.build() PARSER = PG.build()
class Parserr(): def __init__(self, module, builder, printf , name): self.pg = ParserGenerator( # A list of all token names accepted by the parser. ['DECLARE', 'EQUAL', 'NUMBER', 'INC', 'DEC', 'OPEN_PAREN', 'CLOSE_PAREN', 'SEMI_COLON', 'COMMA', 'COMMENT', 'TEXT', 'INCLI', 'CALL', 'PROCEDURE', 'BEGIN', 'END', 'BRIGHT', 'VIB', 'MOV', 'FOR', 'FEND', 'TIMES', 'TEMP', 'OBJ', 'SOUND', 'CASE', 'WHEN', 'THEN','ELSE', 'END_CASE','DOW', 'ENDDO'] ) self.module = module self.builder = builder self.printf = printf self.comment = "" self.case = "" self.dow = "" self.procedures = [] self.token = 0 self.arguments = [] self.declarations = [] self.fort = "" self.whenDec = [] self.name = name def parse(self): @self.pg.production('x : ') @self.pg.production('x : x program') @self.pg.production('program : program y') def program(p): return [self.declarations,self.procedures, self.name] @self.pg.production('program : ') def programE(p): return # Declare @self.pg.production('y : DECLARE TEXT EQUAL NUMBER SEMI_COLON') def declare(p): if self.token == 0: raise SystemExit("No se ha puesto un comentario al inicio") return elif self.token == 1: if len(p[1].value) > 10: raise SystemExit("Supera las 10 posiciones") return if (p[1].value).islower() == True: dCopy = self.declarations for i in dCopy: if(i.name == p[1].value): raise SystemExit("Ya existe una variable con ese nombre") return self.declarations.append(Variable(p[1].value, p[3].value)) self.token = 2 elif self.token == 2: if len(p[1].value) > 10: raise SystemExit("Supera las 10 posiciones") return if (p[1].value).islower() == True: dCopy = self.declarations for i in dCopy: if(i.name == p[1].value): raise SystemExit("Ya existe una variable con ese nombre") return self.declarations.append(Variable(p[1].value, p[3].value)) elif self.token == -3: if len(p[1].value) > 10: raise SystemExit("Supera las 10 posiciones") return if (p[1].value).islower() == True: dCopy = self.declarations for i in dCopy: if(i.name == p[1].value): raise SystemExit("Ya existe una variable con ese nombre") return (self.procedures[len(self.procedures) - 1]).declaration.append(Variable(p[1].value, p[3].value)) elif self.token == 4: raise SystemExit("DECLARE esta fuera de un procedimiento") return elif self.token == 6: if self.fort.token == 3: raise SystemExit("No se pueden hacer declaraciones en el For") return @self.pg.production('y : DECLARE TEXT SEMI_COLON') def emptyDeclare(p): if self.token == 0: raise SystemExit("No se ha puesto un comentario al inicio") return elif self.token == 1: if len(p[1].value) > 10: raise SystemExit("Supera las 10 posiciones") return if (p[1].value).islower() == True: dCopy = self.declarations for i in dCopy: if(i.name == p[1].value): raise SystemExit("Ya existe una variable con ese nombre") return self.declarations.append(Variable(p[1].value)) self.token = 2 elif self.token == 2: if len(p[1].value) > 10: raise SystemExit("Supera las 10 posiciones") return if (p[1].value).islower() == True: dCopy = self.declarations for i in dCopy: if(i.name == p[1].value): raise SystemExit("Ya existe una variable con ese nombre") return self.declarations.append(Variable(p[1].value)) elif self.token == -3: if len(p[1].value) > 10: raise SystemExit("Supera las 10 posiciones") return if (p[1].value).islower() == True: dCopy = (self.procedures[len(self.procedures) - 1]).declaration for i in dCopy: if(i.name == p[1].value): raise SystemExit("Ya existe una variable con ese nombre") return (self.procedures[len(self.procedures) - 1]).declaration.append(Variable(p[1].value)) elif self.token == 4: raise SystemExit("DECLARE esta fuera de un procedimiento") return elif self.token == 6: if self.fort.token == 3: raise SystemExit("No se pueden hacer declaraciones en el For") return @self.pg.production('y : TEXT EQUAL NUMBER SEMI_COLON') def reDeclare(p): if self.token == 0: raise SystemExit("No se ha puesto un comentario al inicio") return elif self.token == 1: raise SystemExit("No se han declarado variables") return elif self.token == 2: raise SystemExit("DECLARE esta fuera de un procedimiento") return elif self.token == -3: (self.procedures[len(self.procedures) - 1]).array.append(Variable(p[0].value,p[2].value)) self.token = 3 return elif self.token == 3: (self.procedures[len(self.procedures) - 1]).array.append(Variable(p[0].value,p[2].value)) return elif self.token == 4: raise SystemExit("DECLARE esta fuera de un procedimiento") return elif self.token == 6: (self.fort.cycle).append(Variable(p[0].value,p[2].value)) return elif self.token == -6: (self.fort.cycle[len(self.fort.cycle) -1]).cycle.append(Variable(p[0].value,p[2].value)) return # Case @self.pg.production('y : CASE') def case(p): if(self.token == 8): self.case.whenDec[len(self.case.whenDec) - 1].function.append(Case(self.token)) self.token = -8 else: if(self.token == 3 or self.token == -3): self.case = Case(3) self.token = 7 return @self.pg.production('y : WHEN TEXT EQUAL NUMBER THEN') def caseWhen(p): if(self.token == -8): i = len(self.case.whenDec[len(self.case.whenDec) - 1].function) - 1 self.case.whenDec[len(self.case.whenDec) - 1].function[i].whenDec.append(When(p[1].value, p[3].value)) else: self.case.whenDec.append(When(p[1].value, p[3].value)) self.token = 8 return @self.pg.production('y : ELSE') def caseElse(p): if(self.token == -8): i = len(self.case.whenDec[len(self.case.whenDec) - 1].function) - 1 self.case.whenDec[len(self.case.whenDec) - 1].function[i].whenDec.append(When(None, None)) else: self.case.whenDec.append(When(None, None)) self.token = 8 return @self.pg.production('y : END_CASE SEMI_COLON') def caseEnd(p): if(self.case.cToken == 3): self.procedures[len(self.procedures) - 1].array.append(self.case) self.token = 3 elif(self.token == -8): self.token = 8 print("END") return # Incremento @self.pg.production('y : INC OPEN_PAREN TEXT COMMA NUMBER CLOSE_PAREN SEMI_COLON') def IncP(p): if self.token == 0: raise SystemExit("No se ha puesto un comentario al inicio") return elif self.token == 1: raise SystemExit("No se han declarado variables") return elif self.token == 2: raise SystemExit("Inc() esta fuera de un procedimiento") return elif self.token == -3: left = p[2].value right = Number(p[4].value) self.token = 3 self.name = self.name + "r" return (self.procedures[len(self.procedures) - 1]).array.append(Inc(self.builder, self.module,self.printf,left, right, self.name)) elif self.token == 3: left = p[2].value right = Number(p[4].value) self.name = self.name + "r" return (self.procedures[len(self.procedures) - 1]).array.append(Inc(self.builder, self.module,self.printf,left, right, self.name)) elif self.token == 4: raise SystemExit("Inc() esta fuera de un procedimiento") return elif self.token == 6: left = p[2].value right = Number(p[4].value) self.name = self.name + "r" return (self.fort.cycle).append(Inc(self.builder, self.module,self.printf,left, right, self.name)) elif self.token == -6: left = p[2].value right = Number(p[4].value) self.name = self.name + "r" return (self.fort.cycle[len(self.fort.cycle) -1]).cycle.append(Inc(self.builder, self.module,self.printf,left, right, self.name)) elif self.token == 8: left = p[2].value right = Number(p[4].value) return (self.case.whenDec[len(self.case.whenDec) - 1]).function.append(Inc(self.builder, self.module,self.printf,left, right, self.name)) elif self.token == -8: left = p[2].value right = Number(p[4].value) i = len(self.case.whenDec[len(self.case.whenDec) - 1].function) - 1 j = len(self.case.whenDec[len(self.case.whenDec) - 1].function[i].whenDec) - 1 return (self.case.whenDec[len(self.case.whenDec) - 1]).function[i].whenDec[j].function.append(Inc(self.builder, self.module,self.printf,left, right, self.name)) elif self.token == 9: left = p[2].value right = Number(p[4].value) self.name = self.name + "r" return (self.dow.function.append(Inc(self.builder, self.module,self.printf,left, right, self.name))) elif self.token == -9: left = p[2].value right = Number(p[4].value) self.name = self.name + "r" return (self.dow.function[len(self.dow.function)-1].function.append(Inc(self.builder, self.module,self.printf,left, right, self.name))) # Decremento @self.pg.production('y : DEC OPEN_PAREN TEXT COMMA NUMBER CLOSE_PAREN SEMI_COLON') def DecP(p): if self.token == 0: raise SystemExit("No se ha puesto un comentario al inicio") return elif self.token == 1: raise SystemExit("No se han declarado variables") return elif self.token == 2: raise SystemExit("Dec() esta fuera de un procedimiento") return elif self.token == -3: left = p[2].value right = Number(p[4].value) self.token = 3 self.name = self.name + "r" return (self.procedures[len(self.procedures) - 1]).array.append(Dec(self.builder, self.module,self.printf,left, right, self.name)) elif self.token == 3: left = p[2].value right = Number(p[4].value) self.name = self.name + "r" return (self.procedures[len(self.procedures) - 1]).array.append(Dec(self.builder, self.module,self.printf,left, right, self.name)) elif self.token == 4: raise SystemExit("Dec() esta fuera de un procedimiento") return elif self.token == 6: left = p[2].value right = Number(p[4].value) self.name = self.name + "r" return (self.fort.cycle).append(Dec(self.builder, self.module,self.printf,left, right, self.name)) elif self.token == -6: left = p[2].value right = Number(p[4].value) self.name = self.name + "r" return (self.fort.cycle[len(self.fort.cycle) -1]).cycle.append(Dec(self.builder, self.module,self.printf,left, right, self.name)) elif self.token == 8: left = p[2].value right = Number(p[4].value) return (self.case.whenDec[len(self.case.whenDec) - 1]).function.append(Dec(self.builder, self.module,self.printf,left, right, self.name)) elif self.token == -8: left = p[2].value right = Number(p[4].value) i = len(self.case.whenDec[len(self.case.whenDec) - 1].function) - 1 j = len(self.case.whenDec[len(self.case.whenDec) - 1].function[i].whenDec) - 1 return (self.case.whenDec[len(self.case.whenDec) - 1]).function[i].whenDec[j].function.append(Dec(self.builder, self.module,self.printf,left, right, self.name)) elif self.token == 9: left = Number(p[2].value) right = Number(p[4].value) self.name = self.name + "r" return (self.dow.function.append(Dec(self.builder, self.module,self.printf,left, right, self.name))) elif self.token == -9: left = Number(p[2].value) right = Number(p[4].value) self.name = self.name + "r" return (self.dow.function[len(self.dow.function)-1].function.append(Dec(self.builder, self.module,self.printf,left, right, self.name))) # Comentario @self.pg.production('y : COMMENT z') def CommentP(p): print("Comment: " + self.comment[1:len(self.comment)]) self.comment = "" if self.token == 0: self.token = 1 return @self.pg.production('z : z TEXT') def CommentPI(p): self.comment += " " + str(p[1].value) return @self.pg.production('z : ') def CommentPE(p): return # Inclinacion @self.pg.production('y : INCLI OPEN_PAREN TEXT CLOSE_PAREN SEMI_COLON') def InclinationP(p): if self.token == 0: raise SystemExit("No se ha puesto un comentario al inicio") return elif self.token == 1: raise SystemExit("No se han declarado variables") return elif self.token == 2: raise SystemExit("Inclination() esta fuera de un procedimiento") return elif self.token == -3: self.token = 3 self.name = self.name + "r" return (self.procedures[len(self.procedures) - 1]).array.append(Inclination(self.builder, self.module,self.printf,p[2].value,self.name)) elif self.token == 3: self.name = self.name + "r" return (self.procedures[len(self.procedures) - 1]).array.append(Inclination(self.builder,self.module,self.printf,p[2].value,self.name)) elif self.token == 4: raise SystemExit("Inclination() esta fuera de un procedimiento") return elif self.token == 6: self.name = self.name + "r" return (self.fort.cycle).append(Inclination(self.builder, self.module,self.printf,p[2].value,self.name)) elif self.token == -6: self.name = self.name + "r" return (self.fort.cycle[len(self.fort.cycle) -1]).cycle.append(Inclination(self.builder, self.module,self.printf,p[2].value,self.name)) elif self.token == 8: return (self.case.whenDec[len(self.case.whenDec) - 1]).function.append(Inclination(self.builder, self.module,self.printf,p[2].value,self.name)) elif self.token == -8: i = len(self.case.whenDec[len(self.case.whenDec) - 1].function) - 1 j = len(self.case.whenDec[len(self.case.whenDec) - 1].function[i].whenDec) - 1 return (self.case.whenDec[len(self.case.whenDec) - 1]).function[i].whenDec[j].function.append(Inclination(self.builder, self.module,self.printf,p[2].value,self.name)) elif self.token == 9: self.name = self.name + "r" return (self.dow.function.append(Inclination(self.builder, self.module,self.printf,p[2].value,self.name))) elif self.token == -9: self.name = self.name + "r" return (self.dow.function[len(self.dow.function)-1].function.append(Inclination(self.builder, self.module,self.printf,p[2].value,self.name))) # Object @self.pg.production('y : OBJ OPEN_PAREN TEXT CLOSE_PAREN SEMI_COLON') def ObjectP(p): if self.token == 0: raise SystemExit("No se ha puesto un comentario al inicio") return elif self.token == 1: raise SystemExit("No se han declarado variables") return elif self.token == 2: raise SystemExit("Object() esta fuera de un procedimiento") return elif self.token == -3: self.token = 3 self.name = self.name + "r" return (self.procedures[len(self.procedures) - 1]).array.append(Object(self.builder, self.module,self.printf,p[2].value,self.name)) elif self.token == 3: self.name = self.name + "r" return (self.procedures[len(self.procedures) - 1]).array.append(Object(self.builder, self.module,self.printf,p[2].value,self.name)) elif self.token == 4: raise SystemExit("Object() esta fuera de un procedimiento") return elif self.token == 6: self.name = self.name + "r" return (self.fort.cycle).append(Object(self.builder, self.module,self.printf,p[2].value,self.name)) elif self.token == -6: self.name = self.name + "r" return (self.fort.cycle[len(self.fort.cycle) -1]).cycle.append(Object(self.builder, self.module,self.printf,p[2].value,self.name)) elif self.token == 8: self.name = self.name + "r" return (self.case.whenDec[len(self.case.whenDec) - 1]).function.append(Object(self.builder, self.module,self.printf,p[2].value,self.name)) elif self.token == -8: self.name = self.name + "r" i = len(self.case.whenDec[len(self.case.whenDec) - 1].function) - 1 j = len(self.case.whenDec[len(self.case.whenDec) - 1].function[i].whenDec) - 1 return (self.case.whenDec[len(self.case.whenDec) - 1]).function[i].whenDec[j].function.append(Object(self.builder, self.module,self.printf,p[2].value,self.name)) elif self.token == 9: self.name = self.name + "r" return (self.dow.function.append(Object(self.builder, self.module,self.printf,p[2].value,self.name))) elif self.token == -9: self.name = self.name + "r" return (self.dow.function[len(self.dow.function)-1].function.append(Object(self.builder, self.module,self.printf,p[2].value,self.name))) # Sounds @self.pg.production('y : SOUND OPEN_PAREN TEXT CLOSE_PAREN SEMI_COLON') def SoundsP(p): if self.token == 0: raise SystemExit("No se ha puesto un comentario al inicio") return elif self.token == 1: raise SystemExit("No se han declarado variables") return elif self.token == 2: raise SystemExit("Sounds() esta fuera de un procedimiento") return elif self.token == -3: self.token = 3 self.name = self.name + "r" return (self.procedures[len(self.procedures) - 1]).array.append(Sounds(self.builder, self.module,self.printf,p[2].value,self.name)) elif self.token == 3: self.name = self.name + "r" return (self.procedures[len(self.procedures) - 1]).array.append(Sounds(self.builder, self.module,self.printf,p[2].value,self.name)) elif self.token == 4: raise SystemExit("Sounds() esta fuera de un procedimiento") return elif self.token == 6: self.name = self.name + "r" return (self.fort.cycle).append(Sounds(self.builder, self.module,self.printf,p[2].value,self.name)) elif self.token == -6: self.name = self.name + "r" return (self.fort.cycle[len(self.fort.cycle) -1]).cycle.append(Sounds(self.builder, self.module,self.printf,p[2].value,self.name)) elif self.token == 8: self.name = self.name + "r" return (self.case.whenDec[len(self.case.whenDec) - 1]).function.append(Sounds(self.builder, self.module,self.printf,p[2].value,self.name)) elif self.token == -8: self.name = self.name + "r" i = len(self.case.whenDec[len(self.case.whenDec) - 1].function) - 1 j = len(self.case.whenDec[len(self.case.whenDec) - 1].function[i].whenDec) - 1 return (self.case.whenDec[len(self.case.whenDec) - 1]).function[i].whenDec[j].function.append(Sounds(self.builder, self.module,self.printf,p[2].value,self.name)) elif self.token == 9: self.name = self.name + "r" return (self.dow.function.append(Sounds(self.builder, self.module,self.printf,p[2].value,self.name))) elif self.token == -9: self.name = self.name + "r" return (self.dow.function[len(self.dow.function)-1].function.append(Sounds(self.builder, self.module,self.printf,p[2].value,self.name))) #Iluminacion @self.pg.production('y : BRIGHT OPEN_PAREN TEXT CLOSE_PAREN SEMI_COLON') def BrightnessP(p): if self.token == 0: raise SystemExit("No se ha puesto un comentario al inicio") return elif self.token == 1: raise SystemExit("No se han declarado variables") return elif self.token == 2: raise SystemExit("Brightness() esta fuera de un procedimiento") return elif self.token == -3: self.token = 3 self.name = self.name + "r" return (self.procedures[len(self.procedures) - 1]).array.append(Brightness(self.builder, self.module,self.printf,p[2].value,self.name)) elif self.token == 3: self.name = self.name + "r" return (self.procedures[len(self.procedures) - 1]).array.append(Brightness(self.builder,self.module,self.printf,p[2].value,self.name)) elif self.token == 4: raise SystemExit("Brightness() esta fuera de un procedimiento") return elif self.token == 6: self.name = self.name + "r" return (self.fort.cycle).append(Brightness(self.builder, self.module,self.printf,p[2].value,self.name)) elif self.token == -6: self.name = self.name + "r" return (self.fort.cycle[len(self.fort.cycle) -1]).cycle.append(Brightness(self.builder, self.module,self.printf,p[2].value,self.name)) elif self.token == 8: self.name = self.name + "r" return (self.case.whenDec[len(self.case.whenDec) - 1]).function.append(Brightness(self.builder, self.module,self.printf,p[2].value,self.name)) elif self.token == -8: self.name = self.name + "r" i = len(self.case.whenDec[len(self.case.whenDec) - 1].function) - 1 j = len(self.case.whenDec[len(self.case.whenDec) - 1].function[i].whenDec) - 1 return (self.case.whenDec[len(self.case.whenDec) - 1]).function[i].whenDec[j].function.append(Brightness(self.builder, self.module,self.printf,p[2].value,self.name)) elif self.token == 9: self.name = self.name + "r" return (self.dow.function.append(Brightness(self.builder, self.module,self.printf,p[2].value,self.name))) elif self.token == -9: self.name = self.name + "r" return (self.dow.function[len(self.dow.function)-1].function.append(Brightness(self.builder, self.module,self.printf,p[2].value,self.name))) # Temperature @self.pg.production('y : TEMP OPEN_PAREN TEXT CLOSE_PAREN SEMI_COLON') def TemperatureP(p): if self.token == 0: raise SystemExit("No se ha puesto un comentario al inicio") return elif self.token == 1: raise SystemExit("No se han declarado variables") return elif self.token == 2: raise SystemExit("Temperature() esta fuera de un procedimiento") return elif self.token == -3: self.token = 3 self.name = self.name + "r" return (self.procedures[len(self.procedures) - 1]).array.append(Temperature(self.builder, self.module,self.printf,p[2].value,self.name)) elif self.token == 3: self.name = self.name + "r" return (self.procedures[len(self.procedures) - 1]).array.append(Temperature(self.builder, self.module,self.printf,p[2].value,self.name)) elif self.token == 4: raise SystemExit("Temperature() esta fuera de un procedimiento") return elif self.token == 6: self.name = self.name + "r" return (self.fort.cycle).append(Temperature(self.builder, self.module,self.printf,p[2].value,self.name)) elif self.token == -6: self.name = self.name + "r" return (self.fort.cycle[len(self.fort.cycle) -1]).cycle.append(Temperature(self.builder, self.module,self.printf,p[2].value,self.name)) elif self.token == 8: self.name = self.name + "r" return (self.case.whenDec[len(self.case.whenDec) - 1]).function.append(Temperature(self.builder, self.module,self.printf,p[2].value,self.name)) elif self.token == -8: self.name = self.name + "r" i = len(self.case.whenDec[len(self.case.whenDec) - 1].function) - 1 j = len(self.case.whenDec[len(self.case.whenDec) - 1].function[i].whenDec) - 1 return (self.case.whenDec[len(self.case.whenDec) - 1]).function[i].whenDec[j].function.append(Temperature(self.builder, self.module,self.printf,p[2].value,self.name)) elif self.token == 9: self.name = self.name + "r" return (self.dow.function.append(Temperature(self.builder, self.module,self.printf,p[2].value,self.name))) elif self.token == -9: self.name = self.name + "r" return (self.dow.function[len(self.dow.function)-1].function.append(Temperature(self.builder, self.module,self.printf,p[2].value,self.name))) #Vibracion @self.pg.production('y : VIB OPEN_PAREN TEXT CLOSE_PAREN SEMI_COLON') def VibrationP(p): if self.token == 0: raise SystemExit("No se ha puesto un comentario al inicio") return elif self.token == 1: raise SystemExit("No se han declarado variables") return elif self.token == 2: raise SystemExit("Vibration() esta fuera de un procedimiento") return elif self.token == -3: self.token = 3 self.name = self.name + "r" return (self.procedures[len(self.procedures) - 1]).array.append(Vibration(self.builder, self.module,self.printf,p[2].value,self.name)) elif self.token == 3: self.name = self.name + "r" return (self.procedures[len(self.procedures) - 1]).array.append(Vibration(self.builder,self.module,self.printf,p[2].value,self.name)) elif self.token == 4: raise SystemExit("Vibration() esta fuera de un procedimiento") return elif self.token == 6: self.name = self.name + "r" return (self.fort.cycle).append(Vibration(self.builder, self.module,self.printf,p[2].value,self.name)) elif self.token == -6: self.name = self.name + "r" return (self.fort.cycle[len(self.fort.cycle) -1]).cycle.append(Vibration(self.builder, self.module,self.printf,p[2].value,self.name)) elif self.token == 8: self.name = self.name + "r" return (self.case.whenDec[len(self.case.whenDec) - 1]).function.append(Vibration(self.builder, self.module,self.printf,p[2].value,self.name)) elif self.token == -8: self.name = self.name + "r" i = len(self.case.whenDec[len(self.case.whenDec) - 1].function) - 1 j = len(self.case.whenDec[len(self.case.whenDec) - 1].function[i].whenDec) - 1 return (self.case.whenDec[len(self.case.whenDec) - 1]).function[i].whenDec[j].function.append(Vibration(self.builder, self.module,self.printf,p[2].value,self.name)) elif self.token == 9: self.name = self.name + "r" return (self.dow.function.append(Vibration(self.builder, self.module,self.printf,p[2].value,self.name))) elif self.token == -9: self.name = self.name + "r" return (self.dow.function[len(self.dow.function)-1].function.append(Vibration(self.builder, self.module,self.printf,p[2].value,self.name))) #Movimientos @self.pg.production('y : MOV OPEN_PAREN TEXT CLOSE_PAREN SEMI_COLON') def MoveP(p): if self.token == 0: raise SystemExit("No se ha puesto un comentario al inicio") return elif self.token == 1: raise SystemExit("No se han declarado variables") return elif self.token == 2: raise SystemExit("Move() esta fuera de un procedimiento") return elif self.token == -3: self.token = 3 self.name = self.name + "r" return (self.procedures[len(self.procedures) - 1]).array.append(Move(self.builder, self.module,self.printf,p[2].value,self.name)) elif self.token == 3: self.name = self.name + "r" return (self.procedures[len(self.procedures) - 1]).array.append(Move(self.builder,self.module,self.printf,p[2].value,self.name)) elif self.token == 4: raise SystemExit("Move() esta fuera de un procedimiento") return elif self.token == 6: self.name = self.name + "r" return (self.fort.cycle).append(Move(self.builder, self.module,self.printf,p[2].value,self.name)) elif self.token == -6: self.name = self.name + "r" return (self.fort.cycle[len(self.fort.cycle) -1]).cycle.append(Move(self.builder, self.module,self.printf,p[2].value,self.name)) elif self.token == 8: self.name = self.name + "r" return (self.case.whenDec[len(self.case.whenDec) - 1]).function.append(Move(self.builder, self.module,self.printf,p[2].value,self.name)) elif self.token == -8: self.name = self.name + "r" i = len(self.case.whenDec[len(self.case.whenDec) - 1].function) - 1 j = len(self.case.whenDec[len(self.case.whenDec) - 1].function[i].whenDec) - 1 return (self.case.whenDec[len(self.case.whenDec) - 1]).function[i].whenDec[j].function.append(Move(self.builder, self.module,self.printf,p[2].value,self.name)) elif self.token == 9: self.name = self.name + "r" return (self.dow.function.append(Move(self.builder, self.module,self.printf,p[2].value,self.name))) elif self.token == -9: self.name = self.name + "r" return (self.dow.function[len(self.dow.function)-1].function.append(Move(self.builder, self.module,self.printf,p[2].value,self.name))) # Call @self.pg.production('y : CALL TEXT SEMI_COLON') def CallNP(p): if self.token == 0: raise SystemExit("No se ha puesto un comentario al inicio") return elif self.token == 1: raise SystemExit("No se han declarado variables") return elif self.token == 2: raise SystemExit("Call esta fuera de un procedimiento") return elif self.token == -3: self.token = 3 return (self.procedures[len(self.procedures) - 1]).array.append(Call(p[1].value)) elif self.token == 3: return (self.procedures[len(self.procedures) - 1]).array.append(Call(p[1].value)) elif self.token == 4: raise SystemExit("Call esta fuera de un procedimiento") return elif self.token == 6: return (self.fort.cycle).append(Call(p[1].value)) elif self.token == -6: (self.fort.cycle[len(self.fort.cycle) -1]).cycle.append(Call(p[1].value)) return elif self.token == 8: return (self.case.whenDec[len(self.case.whenDec) - 1]).function.append(Call(p[1].value)) elif self.token == -8: i = len(self.case.whenDec[len(self.case.whenDec) - 1].function) - 1 j = len(self.case.whenDec[len(self.case.whenDec) - 1].function[i].whenDec) - 1 return (self.case.whenDec[len(self.case.whenDec) - 1]).function[i].whenDec[j].function.append(Call(p[1].value)) elif self.token == 9: return (self.dow.function.append(Call(p[1].value))) elif self.token == -9: return (self.dow.function[len(self.dow.function)-1].function.append(Call(p[1].value))) @self.pg.production('y : CALL TEXT OPEN_PAREN args CLOSE_PAREN SEMI_COLON') def CallEP(p): if self.token == 0: raise SystemExit("No se ha puesto un comentario al inicio") return elif self.token == 1: raise SystemExit("No se han declarado variables") return elif self.token == 2: raise SystemExit("Call() esta fuera de un procedimiento") return elif self.token == -3: self.token = 3 (self.procedures[len(self.procedures) - 1]).array.append(Call(p[1].value, self.arguments)) self.arguments = [] return elif self.token == 3: (self.procedures[len(self.procedures) - 1]).array.append(Call(p[1].value, self.arguments)) self.arguments = [] return elif self.token == 4: raise SystemExit("Call() esta fuera de un procedimiento") return elif self.token == 6: (self.fort.cycle).append(Call(p[1].value, self.arguments)) self.arguments = [] return elif self.token == -6: (self.fort.cycle[len(self.fort.cycle) -1]).cycle.append(Call(p[1].value, self.arguments)) self.arguments = [] return elif self.token == 8: (self.case.whenDec[len(self.case.whenDec) - 1]).function.append(Call(p[1].value, self.argument)) self.arguments = [] return elif self.token == -8: i = len(self.case.whenDec[len(self.case.whenDec) - 1].function) - 1 j = len(self.case.whenDec[len(self.case.whenDec) - 1].function[i].whenDec) - 1 (self.case.whenDec[len(self.case.whenDec) - 1]).function[i].whenDec[j].function.append(Call(p[1].value, self.argument)) self.arguments = [] return elif self.token == 9: return (self.dow.function.append(Call(p[1].value, self.argument))) elif self.token == -9: return (self.dow.function[len(self.dow.function)-1].function.append(Call(p[1].value, self.argument))) # For @self.pg.production('y : FOR NUMBER TIMES') def ForP(p): if self.token == 0: raise SystemExit("No se ha puesto un comentario al inicio") return elif self.token == 1: raise SystemExit("No se han declarado variables") return elif self.token == 2: raise SystemExit("For() esta fuera de un procedimiento") return elif self.token == -3: self.fort = For(p[1].value,3) (self.procedures[len(self.procedures) - 1]).array.append(self.fort) self.token = 6 return elif self.token == 3: self.fort = For(p[1].value,self.token) (self.procedures[len(self.procedures) - 1]).array.append(self.fort) self.token = 6 return elif self.token == 4: raise SystemExit("For() esta fuera de un procedimiento") return # revisar elif self.token == 6: (self.fort.cycle).append(For(p[1].value,self.token)) self.token == -6 return #FEnd @self.pg.production('y : FEND SEMI_COLON') def FEndP(p): if self.token == -6: self.token = (self.fort.cycle[len(self.fort.cycle) -1]).token elif self.token == 6: if self.fort.token == 3: self.token = self.fort.token return # Procedure Begin @self.pg.production('y : PROCEDURE TEXT OPEN_PAREN args CLOSE_PAREN BEGIN') def prodNP(p): if self.token == 0: raise SystemExit("No se ha puesto un comentario al inicio") return elif self.token == 1: raise SystemExit("No se han declarado variables") return elif self.token == 2: self.procedures.append(Procedure(p[1].value, self.arguments)) self.token = -3; self.arguments = [] return elif self.token == 3: raise SystemExit("No se puede crear un procedimiento dentro de otro") return elif self.token == 4: self.procedures.append(Procedure(p[1].value, self.arguments)) self.token = -3; self.arguments = [] return elif self.token == 6: raise SystemExit("No se puede hacer un procedimiento dentro de un For") return @self.pg.production('y : PROCEDURE TEXT OPEN_PAREN CLOSE_PAREN BEGIN') def prodP(p): if self.token == 0: raise SystemExit("No se ha puesto un comentario al inicio") return elif self.token == 1: raise SystemExit("No se han declarado variables") return elif self.token == 2: self.procedures.append(Procedure(p[1].value)) self.token = -3; return elif self.token == 3: raise SystemExit("No se puede crear un procedimiento dentro de otro") return elif self.token == 4: self.procedures.append(Procedure(p[1].value)) self.token = -3; return elif self.token == 6: raise SystemExit("No se puede hacer un procedimiento dentro de un For") return # Procedure End @self.pg.production('y : END SEMI_COLON') def prodEP(p): if self.token == 3: self.token = 4; return (self.procedures[len(self.procedures) - 1]) elif self.token == -3: self.token = 4; return (self.procedures[len(self.procedures) - 1]) # Dow @self.pg.production('y : DOW OPEN_PAREN TEXT COMMA NUMBER COMMA NUMBER COMMA NUMBER CLOSE_PAREN') def dowN(p): miVar = p[2].value valIni = (p[4].value) increment = (p[6].value) valFin = (p[8].value) if self.token == 9: self.dow.function.append(Dow(miVar,valIni,increment,valFin,self.token)) self.token = -9 else: self.dow = Dow(miVar,valIni,increment,valFin,self.token) self.token=9 return @self.pg.production('y : ENDDO SEMI_COLON') def dowe(p): if self.token == -9: self.token = 9 elif self.dow.token == -3: self.token = 3 self.procedures[len(self.procedures) - 1].array.append(self.dow) # Argumentos @self.pg.production('args : TEXT COMMA args') def argsC(p): self.arguments.append(p[0].value) return @self.pg.production('args : TEXT') def args(p): self.arguments.append(p[0].value) return # Error @self.pg.error def error_handle(token): raise ValueError(token) def get_parser(self): return self.pg.build()
@pg.production('expr : NUMBER') def expression_number(p): return ast.Number(int(p[0].getstr())) @pg.production('expr : LPAREN expr RPAREN') def expression_parens(p): return p[1] @pg.production('expr : ADD expr expr') @pg.production('expr : SUBSTRACT expr expr') @pg.production('expr : MULTIPLY expr expr') @pg.production('expr : DIVIDE expr expr') def expression_binop(p): left = p[1] right = p[2] if p[0].gettokentype() == 'ADD': return ast.Add(left, right) elif p[0].gettokentype() == 'SUBSTRACT': return ast.Substract(left, right) elif p[0].gettokentype() == 'MULTIPLY': return ast.Multiply(left, right) elif p[0].gettokentype() == 'DIVIDE': return ast.Divide(left, right) else: raise AssertionError('Oops, this should not be possible!') parser = pg.build()
class Parser(): def __init__(self, module, builder, printf, scanf, definations = {}): self.pg = ParserGenerator( # Tokens that can be accepted by our parser ['NUMBER', 'WRITE', 'WRITELN', 'OPEN_PAREN', 'CLOSE_PAREN', 'SEMI_COLON', 'SUM', 'SUB','MUL','DIV','MOD', 'VAR', 'ASSIGN', 'AND', 'OR', 'NOT', 'TRUE', 'FALSE', 'EQUALS', 'LESS', 'GREATER', 'LESS_EQ', 'GREAT_EQ', 'NOT_EQUALS', 'COMMA', 'STRING', 'IF', 'ELSE', 'OPEN_CURLY', 'CLOSE_CURLY', 'NOPS','FUNCTION', 'RETURN', 'FOR', 'INPUT', 'WHILE' ], ## Defining the precedence of operators in language precedence = [ ('left', ['SUM', 'SUB']), ('left', ['MUL', 'DIV']), ('left', ['MOD']) ] ) ## Setting the module, builder and printf system call reference self.module = module self.builder = builder self.printf = printf self.scanf = scanf ## Initializing the defaults constructs for our language ## Like a global string called True, False etc. initialize(builder, module, definations) self.constants = {} self.constants['false'] = self.builder.bitcast(globalFalse, globalVoidPtr) self.constants['true'] = self.builder.bitcast(globalTrue, globalVoidPtr) self.constants['int'] = self.builder.bitcast(globalInt, globalVoidPtr) ''' Method that does the actual parsing ''' def parse(self): ## a program is a list of statements @self.pg.production('program : statements') def program(p): return Statements(self.builder, self.module, p) ## statements is either onestatemnt or statements followed by onestatemnt @self.pg.production('statements : onestatement') @self.pg.production('statements : statements onestatement') def statements(p): return Line(self.builder, self.module, p) ## onestatement represents every single line possible in our code ## onestatement consist of two type of constructs ## for and if statement which don't end with semicolon ## semicolon statement followed by SEMI_COLON token. ';' @self.pg.production('onestatement : forstatement') @self.pg.production('onestatement : ifelsestatement') @self.pg.production('onestatement : whilestatement') @self.pg.production('onestatement : semicolon SEMI_COLON') def onestatement(p): return Line(self.builder, self.module, p[0]) ## These are the group of statemetns that actually require to end with semi colon ## Consist of ## list of all the statemnets constructs in our language @self.pg.production('semicolon : noopsstatement') @self.pg.production('semicolon : functiondefination') @self.pg.production('semicolon : returnstatement') @self.pg.production('semicolon : inputstatement') @self.pg.production('semicolon : functioncall') @self.pg.production('semicolon : writestatement') @self.pg.production('semicolon : writelnstatement') @self.pg.production('semicolon : assignmentstatement') def semicolonstatement(p): return p[0] ''' ------- All Statements in the language ----------- ''' ## There is a keyword called 'nothing' in our language ## The need for this is that sometimes make a if condition ## but don't know what to do as of now. Leaving a block empty throws error. ## So, you can write 'nothing;' which is a valid construct and also ## as the name suggests does nothing :) @self.pg.production('noopsstatement : NOPS') def noopsstatement(p): ## Passing empty list thus adding no construct to the code return Line(self.builder, self.module, []) ## Function defination is supposed to be a prototype. ## it is supposed to be like ## function name(args*) @self.pg.production('functiondefination : FUNCTION VAR OPEN_PAREN argslist CLOSE_PAREN') @self.pg.production('functiondefination : FUNCTION VAR OPEN_PAREN CLOSE_PAREN') def functiondefination(p): if len(p) == 4: ## If len is 4 that means we have no arguments in the function ## p[1].value is the name of the function return DefineFunction(self.builder, self.module, self.printf, self.scanf, p[1].value, []) else: ## p[3] is supposed to give argslist in the next case return DefineFunction(self.builder, self.module, self.printf, self.scanf, p[1].value, p[3]) ## arglist is collection of variable names separated by , ## like a, b, c @self.pg.production('argslist : VAR') @self.pg.production('argslist : argslist COMMA VAR') def argslist(p): if len(p) == 1: return p[0].value else: ## Flattening the args list ## It is used because in case of multpile args the array can be recursive ## So, it picks every element to same depth values = p[:-1:2] if type(values[0]) == list: values[0].append(p[-1].value) return values[0] else: values.append(p[-1].value) return values ## The return statement can be used to return an evaluated expression @self.pg.production('returnstatement : RETURN expression') def returnstatement(p): return ReturnValue(self.builder, self.module, p[1]) ## assignment statements can be used to assign a value to a variable ## Also, not that our language can detect if the variable is declared on not ## and declare it for you automatically :) @self.pg.production('assignmentstatement : VAR ASSIGN expression') @self.pg.production('assignmentstatement : VAR ASSIGN functioncall') def assignmentstatement(p): return Assign(self.builder, self.module, p[0].value, p[2]) ## write takes a list of printable statements and prints it one by one ## Eg : write(2, 2 == 2, "Rahul") ## should print 2 True Rahul in console @self.pg.production('writestatement : WRITE OPEN_PAREN printstatement CLOSE_PAREN') def writestatement(p): return Line(self.builder, self.module, p[2]) ## writeln is same as write but adds a newline after all values have been printed @self.pg.production('writelnstatement : WRITELN OPEN_PAREN printstatement CLOSE_PAREN') def writelnstatement(p): withnewline = p[2].value ## Append a Write commant to print \n at the end of previous list withnewline.append(Write(self.builder, self.module, self.printf, String("\n", trim = False), self.constants)) return Line(self.builder, self.module, withnewline) @self.pg.production('inputstatement : INPUT OPEN_PAREN VAR CLOSE_PAREN') def inputstatement(p): return Input(self.builder, self.module, self.scanf, p[2].value, self.constants) ## printstatement is a list of printable statements comma separated @self.pg.production('printstatement : oneprintstatement') @self.pg.production('printstatement : printstatement COMMA oneprintstatement') def printstatement(p): return Line(self.builder, self.module, p[::2]) ## oneprintstatemnet can be any expression or a STRING kind @self.pg.production('oneprintstatement : allexpression') @self.pg.production('oneprintstatement : STRING') def oneprintstatement(p): try: isString = p[0].gettokentype() return Write(self.builder, self.module, self.printf, String(p[0].value), self.constants) except AttributeError: return Write(self.builder, self.module, self.printf, p[0], self.constants) return Write(self.builder, self.module, self.printf, p[0], self.constants) ## Function call is when you call a function but don't store the return value ## it takes an optional comma separated expression list @self.pg.production('functioncall : VAR OPEN_PAREN CLOSE_PAREN') @self.pg.production('functioncall : VAR OPEN_PAREN expresslist CLOSE_PAREN') def functincall(p): if len(p) == 3: return CallFunction(self.builder, self.module, p[0].value, []) else: return CallFunction(self.builder, self.module, p[0].value, p[2]) ## Return list of expressions @self.pg.production('expresslist : expression') @self.pg.production('expresslist : expresslist COMMA expression') def expresslist(p): if len(p) == 1: return p[0] else: values = p[:-1:2] if type(values[0]) == list: values[0].append(p[-1]) return values[0] else: values.append(p[-1]) return values ## If statement can be a if followed by logical expression then optional else ## each if and else takes a block as next parameter which is the set of statemnets @self.pg.production('ifelsestatement : IF log_expression block ELSE block') @self.pg.production('ifelsestatement : IF log_expression block') def ifelsestatement(p): if len(p) == 3: return If(self.builder, self.module, p[1], p[2]) else: return IfElse(self.builder, self.module, p[1], p[2], p[4]) ## For has the syntax like ## for (assignment; logical_expression; assignment2) block @self.pg.production('forstatement : FOR OPEN_PAREN assignmentstatement SEMI_COLON log_expression SEMI_COLON assignmentstatement CLOSE_PAREN block') def forstatement(p): return For(self.builder, self.module, p[2], p[4], p[6], p[8]) ## While has the syntax like ## while(logical_expression) block @self.pg.production('whilestatement : WHILE OPEN_PAREN log_expression CLOSE_PAREN block') def whilestatement(p): return While(self.builder,self.module,p[2],p[4]) ## A block is a single statement ## In case you need multiple statements you need to enclose it in curly braces @self.pg.production('block : onestatement') @self.pg.production('block : OPEN_CURLY statements CLOSE_CURLY') def block(p): if len(p) == 1: return Line(self.builder, self.module, p[0]) else: return Line(self.builder, self.module, p[1]) ''' ------- All Expressions in the language ----------- ''' ## allexpression consist of expression or logical expression @self.pg.production('allexpression : expression') @self.pg.production('allexpression : log_expression') def allexpression(p): return Line(self.builder, self.module, p[0]) ## Logical Expressions ## logical expressions when operated with and, or, not also give logical expression @self.pg.production('log_expression : log_expression OR log_expression') @self.pg.production('log_expression : log_expression AND log_expression') @self.pg.production('log_expression : NOT log_expression') def log_expression(p): if len(p) == 3: # And Or case left = p[0] right = p[2] operator = p[1] if operator.gettokentype() == 'OR': return Or(self.builder, self.module, left, right) else: return And(self.builder, self.module, left, right) else: return Not(self.builder, self.module, p[1]) ## The keyword True, False are logical expression itself ## Also, we can enclose a logical expression in () and it is still logical expression @self.pg.production('log_expression : TRUE') @self.pg.production('log_expression : FALSE') @self.pg.production('log_expression : OPEN_PAREN log_expression CLOSE_PAREN') def log_expression_value(p): if p[0].gettokentype() == 'TRUE': return Bool(self.builder, self.module, True) elif p[0].gettokentype() == "FALSE": return Bool(self.builder, self.module, False) else: return Line(self.builder, self.module, p[1]) ## This is the tricky part ## Since relational operators give either true or false ## We have wrapped it within logical expression @self.pg.production('log_expression : rel_expression') def log_expression_relation(p): return Line(self.builder, self.module, p[0]) ## Relational expressions @self.pg.production('rel_expression : expression EQUALS expression') @self.pg.production('rel_expression : expression LESS expression') @self.pg.production('rel_expression : expression GREATER expression') @self.pg.production('rel_expression : expression LESS_EQ expression') @self.pg.production('rel_expression : expression GREAT_EQ expression') @self.pg.production('rel_expression : expression NOT_EQUALS expression') def arithmatic_relations(p): left = p[0] right = p[2] operator = p[1] if operator.gettokentype() == 'EQUALS': return Equals(self.builder, self.module, left, right) elif operator.gettokentype() == 'LESS': return Less(self.builder, self.module, left, right) elif operator.gettokentype() == 'GREATER': return Greater(self.builder, self.module, left, right) elif operator.gettokentype() == 'LESS_EQ': return LessEq(self.builder, self.module, left, right) elif operator.gettokentype() == 'GREAT_EQ': return GreatEq(self.builder, self.module, left, right) elif operator.gettokentype() == 'NOT_EQUALS': return NotEquals(self.builder, self.module, left, right) ## Arithmatic Expressions @self.pg.production('expression : expression SUM expression') @self.pg.production('expression : expression SUB expression') @self.pg.production('expression : expression MUL expression') @self.pg.production('expression : expression DIV expression') @self.pg.production('expression : expression MOD expression') def expression(p): left = p[0] right = p[2] operator = p[1] if operator.gettokentype() == 'SUM': return Sum(self.builder, self.module, left, right) elif operator.gettokentype() == 'SUB': return Sub(self.builder, self.module, left, right) elif operator.gettokentype() == 'MUL': return Mul(self.builder, self.module, left, right) elif operator.gettokentype() == 'DIV': return Div(self.builder, self.module, left, right) elif operator.gettokentype() == 'MOD': return Mod(self.builder, self.module, left, right) ## A function call is also a valid expression @self.pg.production('expression : functioncall') def callexpression(p): return p[0] ## A number, variable or (expression) are also expression @self.pg.production('expression : NUMBER') @self.pg.production('expression : VAR') @self.pg.production('expression : OPEN_PAREN expression CLOSE_PAREN') def stopexpression(p): if p[0].gettokentype() == 'NUMBER': return Number(self.builder, self.module, p[0].value) elif p[0].gettokentype() == 'VAR': return Var(self.builder, self.module, p[0].value) elif p[0].gettokentype() == 'OPEN_PAREN': return Line(self.builder, self.module, p[1]) @self.pg.error def error_handle(token): raise ValueError(token) def get_parser(self): return self.pg.build()
class Parser(): def __init__(self, state): self.state = state self.pg = ParserGenerator( # A list of all token names accepted by the parser. ['NUM', 'DOT', 'COMMA', 'OPEN_PAREN', 'CLOSE_PAREN', 'NOT', 'IMPLIE', 'AND', 'OR', 'IMP_INTROD', 'AND_INTROD', 'BOTTOM', 'OPEN_BRACKET', 'NEG_INTROD', 'NEG_ELIM', 'HYPOTESIS', 'PREMISE', 'ATHOM', 'CLOSE_BRACKET'], precedence=[ ('left', ['NOT','AND', 'OR', 'IMPLIE']), ] ) self.symbol_table = SymbolTable() def parse(self): @self.pg.production('program : steps') def program(p): formules = p[0] for i in range(0, len(formules)): formule = formules[i] rule = self.symbol_table.get_rule(formule.toString()) if(isinstance(rule, PremisseDef) ): pass elif(isinstance(rule, HypotesisDef)): pass elif(isinstance(rule, NegationEliminationDef)): formule1 = self.symbol_table.lookup_formule_by_line(rule.formule, rule.reference1) formule2 = self.symbol_table.lookup_formule_by_line(rule.formule, rule.reference2) if(rule.eval(formule1, formule2) == 4): print('Deu certo') else: print('Algo deu errado') @self.pg.production('steps : steps step') @self.pg.production('steps : step') def steps(p): if len(p) == 1: return [p[0]] else: p[0].append(p[1]) return p[0] @self.pg.production('step : NUM DOT formule PREMISE') def Premisse(p): formule = p[2] premisse = PremisseDef(p[0].value, formule) self.symbol_table.insert(premisse) return formule @self.pg.production('step : NUM DOT formule HYPOTESIS') @self.pg.production('step : NUM DOT formule HYPOTESIS OPEN_BRACKET') def Hypotesis(p): if len(p) > 4: self.symbol_table.add_scope() formule = p[2] hypotesis = HypotesisDef(p[0].value, formule) self.symbol_table.insert(hypotesis) return formule @self.pg.production('step : NUM DOT formule NEG_ELIM NUM COMMA NUM') @self.pg.production('step : NUM DOT formule NEG_ELIM NUM COMMA NUM CLOSE_BRACKET') def Negation_elim(p): formule = p[2] negationElimination = NegationEliminationDef(p[0].value, formule, p[4].value, p[6].value) self.symbol_table.insert(negationElimination) if len(p) == 8: self.symbol_table.end_scope() return formule @self.pg.production('formule : NOT formule') @self.pg.production('formule : ATHOM') @self.pg.production('formule : BOTTOM') @self.pg.production('formule : formule AND formule') @self.pg.production('formule : formule OR formule') @self.pg.production('formule : formule IMPLIE formule') def formule(p): if len(p) < 3: if p[0].gettokentype() == 'ATHOM': return AthomFormule(key=p[0].value) elif p[0].gettokentype() == 'BOTTOM': return AthomFormule(key=p[0].value) elif p[0].gettokentype() == 'NOT': return NegationFormule(key=p[1]) else: return BinaryFormule(key=p[1].value, left=p[0], right=p[2]) @self.pg.production('formule : OPEN_PAREN formule CLOSE_PAREN') def paren_formule(p): return p[1] @self.pg.error def error_handle(token): raise ValueError(token) def get_parser(self): return self.pg.build()
class Parser: def __init__(self, syntax=False): self.pg = ParserGenerator( # A list of all token names accepted by the parser. [ 'STRING', 'INTEGER', 'FLOAT', 'BOOLEAN', 'PI', 'E', 'PRINT', 'ABSOLUTE', 'SIN', 'COS', 'TAN', 'POWER', 'CONSOLE_INPUT', '(', ')', ';', ',', '{', '}', 'LET', 'AND', 'OR', 'NOT', 'IF', 'ELSE', '=', '==', '!=', '>=', '>', '<', '<=', 'SUM', 'SUB', 'MUL', 'DIV', 'IDENTIFIER', 'FUNCTION' ], # A list of precedence rules with ascending precedence, to # disambiguate ambiguous production rules. precedence=(('left', ['FUNCTION']), ('left', ['LET']), ('left', ['=']), ('left', ['IF', 'ELSE', ';']), ('left', ['AND', 'OR']), ('left', ['NOT']), ('left', ['==', '!=', '>=', '>', '<', '<=']), ('left', ['SUM', 'SUB']), ('left', ['MUL', 'DIV']), ('left', ['STRING', 'INTEGER', 'FLOAT', 'BOOLEAN', 'PI', 'E']))) self.syntax = syntax self.parse() pass # End Parser's constructor ! def parse(self): @self.pg.production("main : program") def main_program(state, p): if self.syntax is True: return [Node("program", p[0])] return Main(p[0]) @self.pg.production('program : statement_full') def program_statement(state, p): if self.syntax is True: return [Node("statement_full", p[0])] return Program(p[0], None, state) @self.pg.production('program : statement_full program') def program_statement_program(state, p): if self.syntax is True: return [Node("statement_full", p[0]), Node("program", p[1])] return Program(p[0], p[1], state) @self.pg.production('expression : ( expression )') def expression_parenthesis(state, p): # In this case we need parenthesis only for precedence # so we just need to return the inner expression if self.syntax is True: return [Node("("), Node("expression", p[1]), Node(")")] return ExpressParenthesis(p[1]) @self.pg.production('statement_full : IF ( expression ) { block }') def expression_if(state, p): if self.syntax is True: return [ Node("IF"), Node("("), Node("expression", p[2]), Node(")"), Node("{"), Node("block", p[5]), Node("}") ] return If(condition=p[2], body=p[5], state=state) @self.pg.production( 'statement_full : IF ( expression ) { block } ELSE { block }') def expression_if_else(state, p): if self.syntax is True: return [ Node("IF"), Node("("), Node("expression", p[2]), Node(")"), Node("{"), Node("block", p[5]), Node("}"), Node("ELSE"), Node("{"), Node("block", p[9]), Node("}") ] return If(condition=p[2], body=p[5], else_body=p[9], state=state) @self.pg.production('block : statement_full') def block_expr(state, p): if self.syntax is True: return [Node("statement_full", p[0])] return Block(p[0], None, state) @self.pg.production('block : statement_full block') def block_expr_block(state, p): if self.syntax is True: return [Node("statement_full", p[0]), Node("block", p[1])] return Block(p[0], p[1], state) @self.pg.production('statement_full : statement ;') def statement_full(state, p): if self.syntax is True: return [Node("statement", p[0]), Node(";")] return StatementFull(p[0]) @self.pg.production('statement : expression') def statement_expr(state, p): if self.syntax is True: return [Node("expression", p[0])] return Statement(p[0]) @self.pg.production('statement : LET IDENTIFIER = expression') def statement_assignment(state, p): if self.syntax is True: return [ Node("LET"), Node("IDENTIFIER", p[1]), Node("="), Node("expression", p[3]) ] return Assignment(Variable(p[1].getstr(), state), p[3], state) @self.pg.production( 'statement_full : FUNCTION IDENTIFIER ( ) { block }') def statement_func_noargs(state, p): if self.syntax is True: return [ Node("FUNCTION"), Node("IDENTIFIER", p[1]), Node("("), Node(")"), Node("{"), Node("block", p[5]), Node("}") ] return FunctionDeclaration(name=p[1].getstr(), args=None, block=p[5], state=state) @self.pg.production('expression : NOT expression') def expression_not(state, p): if self.syntax is True: return [Node("NOT"), Node("expression", p[1])] return Not(p[1], state) @self.pg.production('expression : expression SUM expression') @self.pg.production('expression : expression SUB expression') @self.pg.production('expression : expression MUL expression') @self.pg.production('expression : expression DIV expression') def expression_binary_operator(state, p): if p[1].gettokentype() == 'SUM': if self.syntax is True: return [ Node("expression", p[0]), Node("+"), Node("expression", p[2]) ] return Sum(p[0], p[2], state) elif p[1].gettokentype() == 'SUB': if self.syntax is True: return [ Node("expression", p[0]), Node("-"), Node("expression", p[2]) ] return Sub(p[0], p[2], state) elif p[1].gettokentype() == 'MUL': if self.syntax is True: return [ Node("expression", p[0]), Node("*"), Node("expression", p[2]) ] return Mul(p[0], p[2], state) elif p[1].gettokentype() == 'DIV': if self.syntax is True: return [ Node("expression", p[0]), Node("/"), Node("expression", p[2]) ] return Div(p[0], p[2], state) else: raise LogicError('Oops, this should not be possible!') @self.pg.production('expression : expression != expression') @self.pg.production('expression : expression == expression') @self.pg.production('expression : expression >= expression') @self.pg.production('expression : expression <= expression') @self.pg.production('expression : expression > expression') @self.pg.production('expression : expression < expression') @self.pg.production('expression : expression AND expression') @self.pg.production('expression : expression OR expression') def expression_equality(state, p): if p[1].gettokentype() == '==': if self.syntax is True: return [ Node("expression", p[0]), Node("=="), Node("expression", p[2]) ] return Equal(p[0], p[2], state) elif p[1].gettokentype() == '!=': if self.syntax is True: return [ Node("expression", p[0]), Node("!="), Node("expression", p[2]) ] return NotEqual(p[0], p[2], state) elif p[1].gettokentype() == '>=': if self.syntax is True: return [ Node("expression", p[0]), Node(">="), Node("expression", p[2]) ] return GreaterThanEqual(p[0], p[2], state) elif p[1].gettokentype() == '<=': if self.syntax is True: return [ Node("expression", p[0]), Node("<="), Node("expression", p[2]) ] return LessThanEqual(p[0], p[2], state) elif p[1].gettokentype() == '>': if self.syntax is True: return [ Node("expression", p[0]), Node(">"), Node("expression", p[2]) ] return GreaterThan(p[0], p[2], state) elif p[1].gettokentype() == '<': if self.syntax is True: return [ Node("expression", p[0]), Node("<"), Node("expression", p[2]) ] return LessThan(p[0], p[2], state) elif p[1].gettokentype() == 'AND': if self.syntax is True: return [ Node("expression", p[0]), Node("AND"), Node("expression", p[2]) ] return And(p[0], p[2], state) elif p[1].gettokentype() == 'OR': if self.syntax is True: return [ Node("expression", p[0]), Node("OR"), Node("expression", p[2]) ] return Or(p[0], p[2], state) else: raise LogicError("Shouldn't be possible") @self.pg.production('expression : CONSOLE_INPUT ( )') def program(state, p): if self.syntax is True: return [Node("CONSOLE_INPUT"), Node("("), Node(")")] return Input() @self.pg.production('expression : CONSOLE_INPUT ( expression )') def program(state, p): if self.syntax is True: return [ Node("CONSOLE_INPUT"), Node("("), Node("expression", p[2]), Node(")") ] return Input(expression=p[2], state=state) @self.pg.production('statement : PRINT ( )') def program(state, p): if self.syntax is True: return [Node("PRINT"), Node("("), Node(")")] return Print() @self.pg.production('statement : PRINT ( expression )') def program(state, p): if self.syntax is True: return [ Node("PRINT"), Node("("), Node("expression", p[2]), Node(")") ] return Print(expression=p[2], state=state) @self.pg.production('expression : ABSOLUTE ( expression )') def expression_absolute(state, p): if self.syntax is True: return [ Node("ABSOLUTE"), Node("("), Node("expression", p[2]), Node(")") ] return Absolute(p[2], state) @self.pg.production('expression : SIN ( expression )') def expression_absolute(state, p): if self.syntax is True: return [ Node("SIN"), Node("("), Node("expression", p[2]), Node(")") ] return Sin(p[2], state) @self.pg.production('expression : COS ( expression )') def expression_absolute(state, p): if self.syntax is True: return [ Node("COS"), Node("("), Node("expression", p[2]), Node(")") ] return Cos(p[2], state) @self.pg.production('expression : TAN ( expression )') def expression_absolute(state, p): if self.syntax is True: return [ Node("TAN"), Node("("), Node("expression", p[2]), Node(")") ] return Tan(p[2], state) @self.pg.production('expression : POWER ( expression , expression )') def expression_absolute(state, p): if self.syntax is True: return [ Node("POWER"), Node("("), Node("expression", p[2]), Node(","), Node("expression", p[4]), Node(")") ] return Pow(p[2], p[4], state) @self.pg.production('expression : IDENTIFIER') def expression_variable(state, p): # Cannot return the value of a variable if it isn't yet defined if self.syntax is True: return [Node("IDENTIFIER", p[0])] return Variable(p[0].getstr(), state) @self.pg.production('expression : IDENTIFIER ( )') def expression_call_noargs(state, p): # Cannot return the value of a function if it isn't yet defined if self.syntax is True: return [Node("IDENTIFIER", p[0]), Node("("), Node(")")] return CallFunction(name=p[0].getstr(), args=None, state=state) @self.pg.production('expression : const') def expression_const(state, p): if self.syntax is True: return [Node("const", p[0])] return p[0] @self.pg.production('const : FLOAT') def constant_float(state, p): if self.syntax is True: return [Node("FLOAT", p[0])] return Float(p[0].getstr(), state) @self.pg.production('const : BOOLEAN') def constant_boolean(state, p): if self.syntax is True: return [Node("BOOLEAN", p[0])] return Boolean(p[0].getstr(), state) @self.pg.production('const : INTEGER') def constant_integer(state, p): if self.syntax is True: return [Node("INTEGER", p[0])] return Integer(p[0].getstr(), state) @self.pg.production('const : STRING') def constant_string(state, p): if self.syntax is True: return [Node("STRING", p[0])] return String(p[0].getstr().strip('"\''), state) @self.pg.production('const : PI') def constant_pi(state, p): if self.syntax is True: return [Node("PI", p[0])] return ConstantPI(p[0].getstr(), state) @self.pg.production('const : E') def constant_e(state, p): if self.syntax is True: return [Node("E", p[0])] return ConstantE(p[0].getstr(), state) @self.pg.error def error_handle(state, token): raise ValueError(token) def build(self): return self.pg.build()
class Parser(): def __init__(self): # The list of tokens from the lexer file self.pg = ParserGenerator([token for token in operators.keys()], precedence=[ ("left", ["ADD", "SUBTRACT"]), ("left", ["MULTIPLY", "DIVIDE"]), ]) def parse(self): @self.pg.production('program : expression') def program(p): return Program(p[0]) @self.pg.production('expression : expression expression') def expression(p): return Expression(p) @self.pg.production('expression : PRINT expression') def print_(p): return Print(p[1]) # Binary operations @self.pg.production('expression : ADD expression WITH expression') def add(p): return Add(p[1], p[3]) @self.pg.production('expression : SUBTRACT expression FROM expression') def subtract(p): return Subtract(p[1], p[3]) @self.pg.production('expression : MULTIPLY expression BY expression') def multiply(p): return Multiply(p[1], p[3]) @self.pg.production('expression : DIVIDE expression BY expression') def divide(p): return Divide(p[1], p[3]) # Handle assinging @self.pg.production('expression : ASSIGN variable_name TO expression') def assign(p): return Assign(p[1], p[3]) # defining expressions @self.pg.production('variable_name : IDENTIFIER') def identifier(p): return Identifier(p[0].value) @self.pg.production('expression : NUMBER') def number(p): return Number(p[0].value) @self.pg.production('expression : STRING') def string(p): return String(p[0].value) @self.pg.production('expression : RPN') def rpn(p): return Rpn(p[0].value) @self.pg.error def error_handle(token): raise ValueError(token) def get_parser(self): return self.pg.build()
class Parser(): def __init__(self): self.pg = ParserGenerator( TOKENS, precedence=[ ('left', ['ADD', 'SUB']), ('left', ['MOD']), ('left', ['NOT_EQ']), ] ) def parse(self): @self.pg.production('fsm : fsm_pre LBRACE fsm_rules RBRACE') def fsm(p) -> FSM: (start, dones) = p[0] rules = {k: v for (k, v) in p[2]} return FSM(start.val, [n.val for n in dones], rules) @self.pg.production('number : NUMBER') @self.pg.production('expr : number') def number(p) -> SynthExpr: if isinstance(p[0], Num): return p[0] return Num(int(p[0].value)) @self.pg.production('id : ID') @self.pg.production('expr : id') def id(p) -> SynthExpr: if isinstance(p[0], RegRef): return p[0] return RegRef(p[0].value) @self.pg.production('expr : expr ADD expr') @self.pg.production('expr : expr SUB expr') @self.pg.production('expr : expr MOD expr') @self.pg.production('expr : expr NOT_EQ expr') def expr(p) -> SynthExpr: left = p[0] right = p[2] operator = p[1] return Binop(operator.value, left, right) @self.pg.production('number_rep : number COMMA number_rep') @self.pg.production('number_rep : number') def number_rep(p) -> List[SynthExpr]: if len(p) == 1: return [p[0]] else: return [p[0]] + [p[2]] @self.pg.production('next : NEXT LPAREN number RPAREN') def direct_next(p) -> NextState: return DirectNext(p[2].val) @self.pg.production('next : NEXT LPAREN id COMMA number COMMA number RPAREN') def cond_next(p) -> NextState: return CondNext(p[2], p[4].val, p[6].val) @self.pg.production('next : DONE') def done_next(p) -> NextState: return Done() @self.pg.production('update : id LEFT_ARROW expr') def update(p) -> Update: return Update(p[0], p[2]) @self.pg.production('updates : update SEMI updates') @self.pg.production('updates : update SEMI') def updates(p) -> List[Update]: if len(p) == 2: return [p[0]] else: return [p[0]] + p[2] @self.pg.production('action : LBRACE updates next RBRACE') @self.pg.production('action : LBRACE next RBRACE') def action(p) -> Action: if len(p) == 3: return Action([], p[1]) else: return Action(p[1], p[2]) @self.pg.production('fsm_pre : LPAREN START EQUAL number COMMA DONE EQUAL LBRACKET number_rep RBRACKET RPAREN') def fsm_pre(p): return (p[3], p[8]) @self.pg.production('fsm_rule : number COLON action') def fsm_rule(p): return (p[0].val, p[2]) @self.pg.production('fsm_rules : fsm_rule fsm_rules') @self.pg.production('fsm_rules : fsm_rule') def fsm_rules(p): if len(p) == 1: return [p[0]] else: return [p[0]] + p[1] @self.pg.error def error_handle(token): pos = token.getsourcepos() raise ValueError( "Failed to parse `%s' on line %s, column %s." % (token.value, pos.lineno, pos.colno)) def get_parser(self): return self.pg.build()
class Parser: def __init__(self, state): self.pg = ParserGenerator(tokens=[ "FN", "LET", "RET", "(", ")", "=", ";", "{", "}", ",", "NUMBER", "FLOAT", "FALSE", "TRUE", "TO", "REF", "DEREF", "ADDR", "PTR", "IDENTIFIER" ], precedence=[ ("left", ["NUMBER", "FLOAT"]), ("left", ["IDENTIFIER"]), ("left", [",", ";"]), ("left", ["FN", "LET", "RET"]), ("left", ["="]), ("right", ["REF", "DEREF", "ADDR"]), ("left", ["TO"]), ("left", ["{", "}"]), ("left", ["(", ")"]), ], cache_id="soda_cache") self.state = state def build(self): # bug poop @self.pg.production("program : definitions") def program_definitions(p): return ProgramNode(p[0]) @self.pg.production("definitions : definitions definitions") @self.pg.production("definitions : definition") def definitions_all(p): return DefinitionsNode(p) @self.pg.production("definition : statements") @self.pg.production("definition : functions") def definition_all(p): return p[0] @self.pg.production("functions : functions functions") @self.pg.production("functions : function") def functions_all(p): return FunctionsNode(p) @self.pg.production("function : FN type IDENTIFIER arguments closure") def function_def(p): return FunctionNode(p[0], p[1], p[2], p[3], p[4]) @self.pg.production("closure : { statements }") @self.pg.production("closure : { }") def closure_all(p): if len(p) == 3: return ClosureNode([p[1]]) else: return ClosureNode([]) @self.pg.production("arguments : ( internal_arguments )") @self.pg.production("arguments : ( )") def arguments_paren_internal(p): if len(p) == 3: return ArgumentsNode([p[1]]) else: return ArgumentsNode([]) @self.pg.production( "internal_arguments : internal_arguments , internal_argument") @self.pg.production( "internal_arguments : internal_argument , internal_argument") @self.pg.production("internal_arguments : internal_argument") def internal_arguments(p): tmp = [] for tok in p: if not hasattr(tok, "gettokentype"): tmp.append(tok) return ArgumentsNode(tmp) @self.pg.production("internal_argument : IDENTIFIER type") def internal_argument(p): return ArgumentNode(p[0], p[1]) @self.pg.production("statements : statements statements") @self.pg.production("statements : statement") def statements_all(p): return StatementsNode(p) @self.pg.production("statement : IDENTIFIER call") @self.pg.production("expr : IDENTIFIER call") def statements_call(p): return CallNode(p[0], p[1]) @self.pg.production("call : ( )") @self.pg.production("call : ( call_arguments )") def call_op(p): if len(p) == 2: return CallOpNode([]) else: return CallOpNode([p[1]]) @self.pg.production("call_arguments : call_arguments , call_arguments") @self.pg.production("call_arguments : expr , expr") @self.pg.production("call_arguments : expr") def call_arguments(p): temp = [] for tok in p: if not isinstance(tok, Token): temp.append(tok) return CallArgumentsNode(temp) @self.pg.production("statement : RET expr ;") def statement_return(p): return ReturnNode(p[0], p[1]) @self.pg.production("statement : LET IDENTIFIER type = expr ;") def statements_let(p): return LetNode(p[1], p[2], p[4]) @self.pg.production("statement : LET IDENTIFIER = expr ;") def statements_let(p): return LetNode(p[1], None, p[3]) @self.pg.production("statement : LET IDENTIFIER type ;") def statements_let(p): return LetNode(p[1], p[2], None) @self.pg.production("expr : expr TO type") def expr_casting(p): return CastNode(p[1], p[0], p[2]) @self.pg.production("expr : REF expr") def expr_refrence(p): return RefNode(p[0], p[1]) @self.pg.production("expr : DEREF expr") def expr_derefrence(p): return DerefNode(p[0], p[1]) @self.pg.production("expr : ADDR expr") def expr_refrence(p): return AddressNode(p[0], p[1]) @self.pg.production("expr : ( expr )") def expr_paren_expr(p): return p[1] @self.pg.production("expr : IDENTIFIER") def expr_identifier(p): return VariableNode(p[0]) @self.pg.production("expr : TRUE") @self.pg.production("expr : FALSE") def expr_boolean(p): return BoolNode(p[0]) @self.pg.production("expr : NUMBER") def expr_number(p): return NumberNode(p[0]) @self.pg.production("expr : FLOAT") def expr_number(p): return FloatNode(p[0]) @self.pg.production("expr : FLOAT") def expr_number(p): return FloatNode(p[0]) @self.pg.production("type : ( IDENTIFIER )") def type_identifier(p): return TypeNode(p[1]) @self.pg.production("type : ( ptrs IDENTIFIER )") def ptrtype_identifier(p): return TypeNode(p[2], is_ptr=p[1]) @self.pg.production("ptrs : ptrs ptrs") @self.pg.production("ptrs : PTR") def ptrs_count(p): if len(p) != 1: return PtrNode(p) else: return PtrNode([]) @self.pg.error def error_handler(token): self.state.error_handler("Came across unexpected token.", token.getsourcepos()) warnings.filterwarnings("ignore", category=ParserGeneratorWarning) return self.pg.build()
constr = state.tagged[tag_name] return constr(p[1]) elif state.accept_unknown_tags: return TaggedValue(tag_name, p[1]) else: raise KeyError("No registered constructor for tag '{}'".format(tag_name)) @pg.production("value : tag value") def value_tagged(state, p): return handle_tagged_value(state, p) @pg.production("value : ns_tag value") def value_tagged_ns(state, p): return handle_tagged_value(state, p) parser = pg.build() def loads(code, tagged=None, accept_unknown_tags=False): state = State(tagged, accept_unknown_tags) return parser.parse(lexer.lex(code), state) CHARS = { '\t': 'tab', '\n': 'newline', '\r': 'return', ' ': 'space' } ESCAPE = re.compile(r'[\x00-\x1f\\"\b\f\n\r\t]') ESCAPE_DCT = { '\\': '\\\\',
class Parser(): def __init__(self): self.pg = ParserGenerator( # A list of all token names accepted by the parser. [ 'INT', 'PRINT', 'OPENPAR', 'CLOSEPAR', 'PLUS', 'MINUS', 'MULT', 'DIV', 'ASSIGN', 'BREAKLINE', 'IDENT', 'IF', 'END', 'ELSE', 'GREATERTHAN', 'LESSTHAN', 'COMMA', 'COLON', 'AND', 'OR', 'NOT', 'DEF', 'VOID', 'INTEGER', 'BOOLEAN', 'TRUE', 'FALSE', 'WHILE', 'WEND', 'INPUT', 'AS', 'CALL', 'EQUAL' ]) def parse(self): @self.pg.production('program : expression') def program(p): return @self.pg.production( 'program : expression PRINT OPENPAR expression CLOSEPAR') def program(p): return Print(p[3]) @self.pg.production('program : PRINT OPENPAR expression CLOSEPAR') def program(p): return Print(p[2]) @self.pg.production('expression : expression PLUS expression') @self.pg.production('expression : expression MINUS expression') @self.pg.production('expression : expression MULT expression') @self.pg.production('expression : expression DIV expression') @self.pg.production('expression : expression ASSIGN expression') @self.pg.production('expression : expression GREATERTHAN expression') @self.pg.production('expression : expression LESSTHAN expression') @self.pg.production('expression : expression EQUAL expression') def expression(p): left = p[0] right = p[2] operator = p[1] if operator.gettokentype() == 'PLUS': return Sum(left, right) elif operator.gettokentype() == 'MINUS': return Sub(left, right) elif operator.gettokentype() == 'MULT': return Mult(left, right) elif operator.gettokentype() == 'DIV': return Div(left, right) elif operator.gettokentype() == 'ASSIGN': return Assign(left, right) elif operator.gettokentype() == 'GREATERTHAN': return GreaterThan(left, right) elif operator.gettokentype() == 'LESSTHAN': return LessThan(left, right) elif operator.gettokentype() == 'EQUAL': return Equal(left, right) @self.pg.production('expression : INT') def number(p): return Number(p[0].value) @self.pg.production('expression : IDENT') def ident(p): return Ident(p[0].value) @self.pg.error def error_handle(token): raise ValueError(token) def get_parser(self): return self.pg.build()
def create_parser(tokens): pg = ParserGenerator( tokens, precedence=[ ("left", ["OR"]), ("left", ["AND"]), ("right", ["NOT"]), ("left", ["EQ", "NE", "LE", "GE", "LT", "GT"]), ("left", ["ADD", "SUB"]), ("left", ["MUL", "DIV", "MOD"]), ("right", ["MINUS"]), ("right", ["POW"]), ("nonassoc", ["LPAREN", "RPAREN"]), ], cache_id="lang", ) @pg.production("program : block") def program(p): return ast.Program(p[0]) @pg.production("scope : LBRACE block RBRACE") def scope(p): return ast.Block(p[1].block) @pg.production("scope : LBRACE RBRACE") def scope_empty(p): return ast.Block(None) @pg.production("block : block stmt") def block(p): return ast.Block(p[0].block + [p[1]]) @pg.production("block : stmt") def block_stmt(p): return ast.Block([p[0]]) @pg.production("stmt : FN SYMBOL LPAREN fn_args RPAREN scope") def stmt_fn(p): return ast.Fn(p[1].getstr(), p[3], p[5]) @pg.production("fn_args : fn_args COMMA def_arg") def fn_args(p): return ast.FnArgs(p[0].args + [p[2]]) @pg.production("fn_args : def_arg") def def_args_arg(p): return ast.FnArgs([p[0]]) @pg.production("fn_args :") def def_args_empty(p): return ast.FnArgs([]) @pg.production("def_arg : SYMBOL COLON type") def def_arg(p): return ast.FnArg(p[0].getstr(), p[2]) @pg.production("stmt : SYMBOL DEFINE expr") def stmt_define(p): return ast.Define(p[0].getstr(), p[2]) @pg.production("stmt : SYMBOL ASSIGN expr") def stmt_assign(p): return ast.Assign(p[0].getstr(), p[2]) @pg.production("stmt : PRINTLN LPAREN expr RPAREN") @pg.production("stmt : PRINT LPAREN expr RPAREN") def stmt_print(p): if p[0].gettokentype() == "PRINTLN": return ast.Print(p[2], True) elif p[0].gettokentype() == "PRINT": return ast.Print(p[2], False) @pg.production("stmt : expr") def stmt_expr(p): return ast.Statement(p[0]) @pg.production("expr : scope") def expr_scope(p): return p[0] @pg.production("expr : SYMBOL LPAREN args RPAREN") def expr_call(p): return ast.Call(p[0].getstr(), p[2]) @pg.production("args : args COMMA expr") def args(p): return ast.Args(p[0].args + [p[2]]) @pg.production("args : expr") def args_expr(p): return ast.Args([p[0]]) @pg.production("args :") def args_empty(p): return ast.Args([]) @pg.production("expr : IF expr scope ELSE scope") def expr_if_else(p): return ast.IfElse(p[1], p[2], p[4]) @pg.production("expr : IF expr scope") def expr_if(p): return ast.If(p[1], p[2]) @pg.production("expr : WHILE expr scope") def expr_while(p): return ast.While(p[1], p[2]) @pg.production("expr : FOR stmt SC expr SC stmt scope") def expr_for(p): return ast.For(p[1], p[3], p[5], p[6]) @pg.production("expr : NOT expr") def expr_not(p): return ast.Not(p[1]) @pg.production("expr : SYMBOL") def expr_symbol(p): return ast.ValueSymbol(p[0].getstr()) @pg.production("expr : CAST LPAREN type COMMA expr RPAREN") def expr_cast(p): return ast.Cast(p[2], p[4]) @pg.production("type : INT") @pg.production("type : FLOAT") @pg.production("type : STR") @pg.production("type : BOOL") def expr_type(p): return ast.Type(p[0].gettokentype()) @pg.production("expr : VALUE_INT") def expr_number_int(p): return ast.ValueInt(int(p[0].getstr())) @pg.production("expr : VALUE_FLOAT") def expr_number_float(p): return ast.ValueFloat(float(p[0].getstr())) @pg.production("expr : VALUE_STR") def expr_str(p): return ast.ValueStr(p[0].getstr()) @pg.production("expr : TRUE") def expr_true(p): return ast.ValueTrue() @pg.production("expr : FALSE") def expr_false(p): return ast.ValueFalse() @pg.production("expr : LPAREN expr RPAREN") def expr_parens(p): return p[1] @pg.production("expr : expr ADD expr") @pg.production("expr : expr SUB expr") @pg.production("expr : expr MUL expr") @pg.production("expr : expr DIV expr") @pg.production("expr : expr POW expr") @pg.production("expr : expr MOD expr") @pg.production("expr : expr EQ expr") @pg.production("expr : expr NE expr") @pg.production("expr : expr LE expr") @pg.production("expr : expr GE expr") @pg.production("expr : expr LT expr") @pg.production("expr : expr GT expr") @pg.production("expr : expr AND expr") @pg.production("expr : expr OR expr") def expr_binop(p): left = p[0] op = p[1].gettokentype() right = p[2] def is_number(x): return isinstance(x, ast.ValueInt) or isinstance( x, ast.ValueFloat) # Mathematical identities optimziation if op == "ADD": if is_number(left) and left.value == 0: # 0 + x = x return right elif is_number(right) and right.value == 0: # x + 0 = x return left elif op == "SUB": if is_number(left) and left.value == 0: # 0 - x = -x return ast.Minus(right) elif is_number(right) and right.value == 0: # x - 0 = x return left elif op == "MUL": if is_number(left) and left.value == 1: # 1 * x = x return right elif is_number(left) and left.value == 2: # 2 * x = x + x return ast.BinaryOp(operator.add, right, right) elif is_number(right) and right.value == 1: # x * 1 = x return left elif is_number(right) and right.value == 2: # x * 2 = x + x return ast.BinaryOp(operator.add, left, left) elif op == "DIV": if is_number(right) and right.value == 1: # x / 1 = x return left elif is_number(right) and right.value == 2: # x / 2 = x * 0.5 return ast.BinaryOp(operator.mul, left, ast.ValueFloat(0.5)) elif op == "POW": if is_number(right) and right.value == 2: # x ^ 2 = x * x return ast.BinaryOp(operator.mul, left, left) methods = { "ADD": operator.add, "SUB": operator.sub, "MUL": operator.mul, "DIV": operator.truediv, "POW": operator.pow, "MOD": operator.mod, "EQ": operator.eq, "NE": operator.ne, "LE": operator.le, "GE": operator.ge, "LT": operator.lt, "GT": operator.gt, "AND": operator.and_, "OR": operator.or_, } assert op in methods return ast.BinaryOp(methods[op], left, right) return pg.build()
class Parser: class Number: """ Number data type that represent an 8 bit integer """ def __init__(self, value): self.value = value def eval(self): """ evaluate """ return int(self.value) def generate(self): return [ ] class String: """ String data type """ def __init__(self, value): self.value = value def eval(self): """ evaluate """ return int(self.value) def generate(self): return [ ] class Boolean: """ Boolean data type """ def __init__(self, value): self.value = value def eval(self): """ evaluate """ return int(self.value) def generate(self): return [ ] class BinaryOp(): """ Base class for any binary operations """ def __init__(self, left, right): self.left = left self.right = right class Sum(BinaryOp): def eval(self): return self.left.eval() + self.right.eval() class Sub(BinaryOp): def eval(self): return self.left.eval() - self.right.eval() class Mult(BinaryOp): def eval(self): return self.left.eval() * self.right.eval() class LeftDiv(BinaryOp): def eval(self): return self.left.eval() / self.right.eval() class RightDiv(BinaryOp): def eval(self): return self.right.eval() / self.left.eval() class Print(): def __init__(self, value): self.value = value def eval(self): print(self.value.eval()) def __init__(self, tokens): self.pg = ParserGenerator(tokens) def parse(self): @self.pg.production('letter : "A" | "B" | "C" | "D" | "E" | "F" | "G" | "H" | "I" | "J" | "K" | "L" | "M" | "N" \ | "O" | "P" | "Q" | "R" | "S" | "T" | "U" \ | "V" | "W" | "X" | "Y" | "Z" | "a" | "b" \ | "c" | "d" | "e" | "f" | "g" | "h" | "i" \ | "j" | "k" | "l" | "m" | "n" | "o" | "p" \ | "q" | "r" | "s" | "t" | "u" | "v" | "w" \ | "x" | "y" | "z" ') def letter(p): """ evaluate letters """ pass @self.pg.production('digit : "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" ') def digit(p): pass @self.pg.production('symbol : "[" | "]" | "{" | "}" | "(" | ")" | "<" | ">" \ | "'" | '"' | "=" | "|" | "." | "," | ";" ') def symbol(p): pass @self.pg.production('program : PRINT OPEN_PAREN expression CLOSE_PAREN SEMI_COLON') def program(p): return self.Print(p[2]) @self.pg.production('expression : expression SUM expression') @self.pg.production('expression : expression SUB expression') def expression(p): left = p[0] right = p[2] operator = p[1] if operator.gettokentype() == 'SUM': return self.Sum(left, right) elif operator.gettokentype() == 'SUB': return self.Sub(left, right) @self.pg.production('expression : NUMBER') def number(p): return self.Number(p[0].value) @self.pg.error def error_handle(token): raise ValueError(token) @property def getParser(self): return self.pg.build()
class Parser(): def __init__(self, dic_variables, dic_etiquetas): self.pg = ParserGenerator( # A list of all token names accepted by the parser. ['LODD','STOD','ADDD','SUBD','JPOS','JZER','JUMP','LOCO','LODL','STOL','ADDL','SUBL','JNEG','JNZE','CALL','PUSHI','POPI','PUSH','POP','RETN','SWAP','INSP','DESP','INPAC', 'OUTAC','HALT','DIRECCION', 'NUMERO', 'VARIABLE', 'ETIQUETA'] ) self.dic_variables=dic_variables self.dic_etiquetas=dic_etiquetas def parse(self): @self.pg.production('expression : LODD expression') @self.pg.production('expression : STOD expression') @self.pg.production('expression : ADDD expression') @self.pg.production('expression : SUBD expression') @self.pg.production('expression : JPOS expression') @self.pg.production('expression : JZER expression') @self.pg.production('expression : JUMP expression') @self.pg.production('expression : LOCO expression') @self.pg.production('expression : LODL expression') @self.pg.production('expression : STOL expression') @self.pg.production('expression : ADDL expression') @self.pg.production('expression : SUBL expression') @self.pg.production('expression : JNEG expression') @self.pg.production('expression : JNZE expression') @self.pg.production('expression : CALL expression') @self.pg.production('expression : INSP expression') @self.pg.production('expression : DESP expression') def expression(p): if p[0].gettokentype() == 'LODD': return Lodd(p[1]) elif p[0].gettokentype() == 'STOD': return Stod(p[1]) elif p[0].gettokentype() == 'ADDD': return Addd(p[1]) elif p[0].gettokentype() == 'SUBD': return Subd(p[1]) elif p[0].gettokentype() == 'JPOS': return Jpos(p[1]) elif p[0].gettokentype() == 'JZER': return Jzer(p[1]) elif p[0].gettokentype() == 'JUMP': return Jump(p[1]) elif p[0].gettokentype() == 'LOCO': return Loco(p[1]) elif p[0].gettokentype() == 'LODL': return Lodl(p[1]) elif p[0].gettokentype() == 'STOL': return Stol(p[1]) elif p[0].gettokentype() == 'ADDL': return Addl(p[1]) elif p[0].gettokentype() == 'SUBL': return Subl(p[1]) elif p[0].gettokentype() == 'JNEG': return Jneg(p[1]) elif p[0].gettokentype() == 'JNZE': return Jnze(p[1]) elif p[0].gettokentype() == 'CALL': return Call(p[1]) elif p[0].gettokentype() == 'INSP': return Insp(p[1]) elif p[0].gettokentype() == 'DESP': return Desp(p[1]) @self.pg.production('expression : PUSHI') @self.pg.production('expression : POPI') @self.pg.production('expression : PUSH') @self.pg.production('expression : POP') @self.pg.production('expression : RETN') @self.pg.production('expression : SWAP') @self.pg.production('expression : INPAC') @self.pg.production('expression : OUTAC') @self.pg.production('expression : HALT') def expression(p): if p[0].gettokentype() == 'PUSHI': return Pushi() elif p[0].gettokentype() == 'POPI': return Popi() elif p[0].gettokentype() == 'PUSH': return Push() elif p[0].gettokentype() == 'POP': return Pop() elif p[0].gettokentype() == 'RETN': return Retn() elif p[0].gettokentype() == 'SWAP': return Swap() elif p[0].gettokentype() == 'INPAC': return Inpac() elif p[0].gettokentype() == 'OUTAC': return Outac() elif p[0].gettokentype() == 'HALT': return Halt() @self.pg.production('expression : DIRECCION') def expression(p): return Direccion(p[0]) @self.pg.production('expression : VARIABLE') def expression(p): return Variable(p[0].value, self.dic_variables) @self.pg.production('expression : NUMERO') def expression(p): return NumeroUnsigned(p[0].value) @self.pg.production('expression : ETIQUETA expression') def expression(p): return Etiqueta_Inicial(p[1]) @self.pg.production('expression : ETIQUETA') def expression(p): return Etiqueta(p[0].value, self.dic_etiquetas) @self.pg.error def error_handle(token): raise ValueError(token) def get_parser(self): return self.pg.build()
class Parser: def __init__(self): self.pg = ParserGenerator( [ 'NUMBER', '(', ')', 'SUM', 'SUB', 'MUL', 'DIV', 'PRINT', '=', 'NEWLINE', 'IDENTIFIER', 'STRING', '$end', 'IF', '==', '!=', '>=', '<=', '<', '>', 'COLON', 'ELSE', 'ELIF', 'DEF', 'END', 'SLEEP', ',', 'open', 'read', '.', 'return', 'import', '{', '}', 'AND', 'await', '@', 'from', '[', ']' ], precedence=[('left', ['SUM', 'SUB']), ('left', ['MUL', 'DIV']), ('left', ['DEF', 'END', 'return', 'IDENTIFIER']), ('left', ['IF', 'COLON', 'ELIF', 'ELSE', 'NEWLINE']), ('left', [ '==', '!=', '>=', '>', '<', '<=', ]), ('left', ['=']), ('left', ['{', '}'])]) self.build() def build(self): @self.pg.production("main : program") def main_program(env, p): return p[0] @self.pg.production('program : statement_full') def program_statement(env, p): return Program(p[0]) @self.pg.production('program : statement_full program') def program_statement_program(env, p): if type(p[1]) is Program: program = p[1] else: program = Program(p[-1]) program.add_statement(p[0]) return p[1] @self.pg.production('statement_full : statement NEWLINE') @self.pg.production('statement_full : statement $end') def statement_full(env, p): try: p[0].gettokentype() return p[1] except AttributeError: return p[0] @self.pg.production('statement : IDENTIFIER = expression') def assignment(env, p): if isinstance(p[2], Function): return Assignment(Variable(p[0].value), p[2]) return Assignment(Variable(p[0].value), p[2]) @self.pg.production('expression : IDENTIFIER') def variable(env, p): return Variable(p[0].value) @self.pg.production('statement : expression') def statement_expr(env, p): return p[0] @self.pg.production('expression : IDENTIFIER [ expression ]') def index(env, p): return Index(Variable(p[0].value), p[2].value) @self.pg.production('statement : PRINT ( expression )') def printsw(env, p): return Print(p[2]) @self.pg.production('statement : SLEEP ( NUMBER )') def sleep(env, p): return Sleep(int(p[2].value)) @self.pg.production('expression : NUMBER') def number(env, p): return Number(int(p[0].value)) @self.pg.production('expression : STRING') def string(env, p): return String(str(p[0].value)) @self.pg.production('expression : expression SUM expression') @self.pg.production('expression : expression SUB expression') @self.pg.production('expression : expression MUL expression') @self.pg.production('expression : expression DIV expression') def binop(env, p): left = p[0] right = p[2] if p[1].gettokentype() == 'SUM': return Sum(left, right) elif p[1].gettokentype() == 'SUB': return Sub(left, right) elif p[1].gettokentype() == 'MUL': return Mul(left, right) elif p[1].gettokentype() == 'DIV': return Div(left, right) else: raise AssertionError('Oops, this should not be possible!') @self.pg.production( 'expression : IF expression COLON NEWLINE block END') def expression_if(env, p): return If(condition=p[1], body=p[4]) @self.pg.production( 'expression : IF expression COLON NEWLINE block ELSE COLON NEWLINE block END' ) def expression_if_else(env, p): return If(condition=p[1], body=p[4], else_body=p[8]) @self.pg.production( 'expression : IF expression COLON NEWLINE block ELIF expression COLON NEWLINE block END' ) def expression_if_elif(env, p): return If(condition=p[1], body=p[4], elif_condition=p[6], elif_body=p[9]) @self.pg.production( 'expression : IF expression COLON NEWLINE block ELIF expression COLON NEWLINE block ELSE COLON NEWLINE block END' ) def expression_if_elif_else(env, p): return If(condition=p[1], body=p[4], elif_condition=p[6], elif_body=p[9], else_body=p[13]) @self.pg.production('expression : expression != expression') @self.pg.production('expression : expression == expression') @self.pg.production('expression : expression >= expression') @self.pg.production('expression : expression <= expression') @self.pg.production('expression : expression > expression') @self.pg.production('expression : expression < expression') def expression_equality(env, p): left = p[0] right = p[2] check = p[1] if check.gettokentype() == '==': return Equal(left, right) elif check.gettokentype() == '!=': return NotEqual(left, right) elif check.gettokentype() == '>=': return GreaterThanEqual(left, right) elif check.gettokentype() == '<=': return LessThanEqual(left, right) elif check.gettokentype() == '>': return GreaterThan(left, right) elif check.gettokentype() == '<': return LessThan(left, right) else: raise ValueError("Shouldn't be possible") @self.pg.production('block : statement_full') def block_expr(env, p): return Block(p[0]) @self.pg.production('block : statement_full block') def block_expr_block(env, p): if type(p[1]) is Block: b = p[1] else: b = Block(p[1]) b.add_statement(p[0]) return b @self.pg.production("function : IDENTIFIER ( )") def function_call(env, p): return Function(p[0].value) @self.pg.production("function : IDENTIFIER ( args )") def function_callargs(env, p): have = list(p[2].statements) env.args[1] = have return Function(p[0].value, Array(p[2])) @self.pg.production('function : IDENTIFIER . IDENTIFIER ( ) ') def importedfunc(env, p): return ImportedFunction(p[0].value, p[2].value) @self.pg.production('function : IDENTIFIER . IDENTIFIER ( args ) ') def importedfuncargs(env, p): return ImportedFunction(p[0].value, p[2].value, p[4]) @self.pg.production( 'function : IDENTIFIER . IDENTIFIER ( args AND kwargs ) ') def importedfuncboth(env, p): return ImportedFunction(p[0].value, p[2].value, p[4], p[6]) @self.pg.production('function : IDENTIFIER . IDENTIFIER ( kwargs ) ') def importedfunckwargs(env, p): return ImportedFunction(p[0].value, p[2].value, None, p[4]) @self.pg.production('expression : function') def function(env, p): return p[0] @self.pg.production('expression : await function') def awaitfunction(env, p): return Await(p[1]) @self.pg.production( 'funcstatement : defstatement ( ) COLON NEWLINE block END') def funcstate(env, p): return AssignmentFunction(p[0], p[5], None) @self.pg.production( 'statement : @ IDENTIFIER . IDENTIFIER NEWLINE funcstatement') def blank_deco(env, p): return DecoratedFunction(p[1].value, p[3].value, p[5], False, None, None) @self.pg.production( 'statement : @ IDENTIFIER . IDENTIFIER ( ) NEWLINE funcstatement') def none_deco(env, p): return DecoratedFunction(p[1].value, p[3].value, p[7], True, None, None) @self.pg.production( 'statement : @ IDENTIFIER . IDENTIFIER ( args AND kwargs ) NEWLINE funcstatement' ) def both_deco(env, p): return DecoratedFunction(p[1].value, p[3].value, p[10], True, p[5], p[7]) @self.pg.production( 'statement : @ IDENTIFIER . IDENTIFIER ( kwargs ) NEWLINE funcstatement' ) def kwargs_deco(env, p): return DecoratedFunction(p[1].value, p[3].value, p[8], True, None, p[5]) @self.pg.production( 'statement : @ IDENTIFIER . IDENTIFIER ( args ) NEWLINE funcstatement' ) def args_deco(env, p): return DecoratedFunction(p[1].value, p[3].value, p[8], True, p[5], None) @self.pg.production("defstatement : DEF IDENTIFIER") def defstatement(env, p): return p[1].value @self.pg.production("statement : funcstatement") def function_assign(env, p): return p[0] @self.pg.production( "funcstatement : defstatement ( args ) COLON NEWLINE block END") def function_assign(env, p): need = list(x.name for x in p[2].statements) env.args[0] = need func = AssignmentFunction(p[0], p[6], Array(p[2])) return func @self.pg.production('args : IDENTIFIER') @self.pg.production('args : IDENTIFIER ,') def arglist_single(env, p): return InnerArray([Variable(p[0].value)]) @self.pg.production('args : IDENTIFIER , args') def arglist(env, p): p[2].append(Variable(p[0].value)) return p[2] @self.pg.production('args : expression') @self.pg.production('args : expression ,') def args_single(env, p): return InnerArray([p[0]]) @self.pg.production('args : expression , args') def arglist(env, p): p[2].append(p[0]) return p[2] @self.pg.production('expression : open ( STRING )') @self.pg.production('openfile : open ( STRING )') def openfile(env, p): return Open(p[2].value) @self.pg.production('expression : openfile . read ( )') @self.pg.production('expression : IDENTIFIER . read ( )') def readfile(env, p): if type(p[0]) == Open: return Read(Open(p[0].filepath)) else: return Read(Variable(p[0].value)) @self.pg.production('statement : returning') def returning(env, p): return p[0] @self.pg.production('returning : return expression') def returnz(env, p): return Return(p[1]) @self.pg.production('statement : import idlist') def importing(env, p): return Import(p[1], None) @self.pg.production('idlist : IDENTIFIER') @self.pg.production('idlist : IDENTIFIER . idlist') def importz(env, p): try: return p[0].value + "." + p[2] except IndexError: return p[0].value @self.pg.production('statement : from idlist import IDENTIFIER') def imported(env, p): return Import(p[3].value, p[1]) @self.pg.production('expression : IDENTIFIER . IDENTIFIER') def importez(env, p): return GetAttr(p[0].value, p[2].value) @self.pg.production('kwargs : IDENTIFIER = expression') @self.pg.production('kwargs : IDENTIFIER = expression ,') def kwargs_single(state, p): return InnerDict({p[0].value: p[2]}) @self.pg.production('kwargs : IDENTIFIER = expression , kwargs') def arglist(state, p): p[4].update(p[0].value, p[2]) return p[4] @self.pg.production('dict : expression COLON expression') @self.pg.production('dict : expression COLON expression ,') def kwargs_single(state, p): return InnerDict({p[0]: p[2]}) @self.pg.production('dict : expression COLON expression , dict') def arglist(state, p): p[4].update(p[0], p[2]) return p[4] @self.pg.production('expression : { dict }') def expression_dict(state, p): return Dict(p[1]) @self.pg.error def error_handler(env, token): if token.gettokentype() == "$end": raise SyntaxError( "Ran into EoF while still parsing. Check to make sure you have end after every if/def" ) print(token.getsourcepos()) raise ValueError("Ran into a %s where it wasn't expected" % token.gettokentype()) def get_parser(self): return self.pg.build()
return ast.UnaryNot(p[1], p[0].getsourcepos()) @pg.production("expression : expression IS expression") @pg.production("expression : expression DOUBLE_EQ expression") def expression_equality(p): return ast.Equals(p[0], p[2], p[1].getsourcepos()) @pg.production("expression : expression NOT_EQ expression") def expression_notequals(p): return ast.NotEquals(p[0], p[2], p[1].getsourcepos()) @pg.production("expression : IDENTIFIER") def expression_identifier(p): return ast.IdentifierExpression(p[0].getstr(), p[0].getsourcepos()) @pg.production("none : ") def none(p): return None @pg.error def error_handler(token): raise ParsingError("Ran into a '%s' where it was't expected" % token.getstr(), token.getsourcepos()) PARSER = pg.build() def create_parser(): return PARSER def create_lexer(): return get_lexer()
class Parser(): def __init__(self, module, builder, printf): self.pg = ParserGenerator( # A list of all token names accepted by the parser. [ 'NUMERO', 'ESCREVA', 'APAR', 'FPAR', 'PONTO_VIRGULA', 'SOMA', 'SUB', 'MUL', 'DIV', ], precedence=[ ('left', [ 'SOMA', 'SUB', ]), ('left', [ 'MUL', 'DIV', ]), ], ) self.module = module self.builder = builder self.printf = printf def parse(self): @self.pg.production( 'programa : ESCREVA APAR expressao FPAR PONTO_VIRGULA') def programa(p): return Print(self.builder, self.module, self.printf, p[2]) @self.pg.production('expressao : expressao SOMA expressao') @self.pg.production('expressao : expressao SUB expressao') @self.pg.production('expressao : expressao MUL expressao') @self.pg.production('expressao : expressao DIV expressao') def expressao(p): left = p[0] right = p[2] operator = p[1] if operator.gettokentype() == 'SOMA': return Sum(self.builder, self.module, left, right) elif operator.gettokentype() == 'SUB': return Sub(self.builder, self.module, left, right) elif operator.gettokentype() == 'MUL': return Mul(self.builder, self.module, left, right) elif operator.gettokentype() == 'DIV': return Div(self.builder, self.module, left, right) @self.pg.production('expressao : NUMERO') def number(p): return Number(self.builder, self.module, p[0].value) @self.pg.error def error_handle(token): raise ValueError(token) def get_parser(self): return self.pg.build()
class Parser: def __init__(self, syntax=False): self.pg = ParserGenerator( # A list of all token names accepted by the parser. get_all_tokens_name(), # A list of precedence rules with ascending precedence, to # disambiguate ambiguous production rules. precedence=((AppConstant.LEFT, [TokenEnum.FUNCTION.name]), (AppConstant.LEFT, [TokenEnum.LET.name]), (AppConstant.LEFT, [TokenEnum.ASSIGN.name]), (AppConstant.LEFT, [ TokenEnum.IF.name, TokenEnum.ELSE.name, TokenEnum.SEMI_COLON.name ]), (AppConstant.LEFT, [TokenEnum.AND.name, TokenEnum.OR.name ]), (AppConstant.LEFT, [TokenEnum.NOT.name]), (AppConstant.LEFT, [ TokenEnum.EQ.name, TokenEnum.NEQ.name, TokenEnum.GTEQ.name, TokenEnum.GT.name, TokenEnum.LT.name, TokenEnum.LTEQ.name ]), (AppConstant.LEFT, [TokenEnum.SUM.name, TokenEnum.SUB.name]), (AppConstant.LEFT, [TokenEnum.MUL.name, TokenEnum.DIV.name]), (AppConstant.LEFT, [ TokenEnum.STRING.name, TokenEnum.INTEGER.name, TokenEnum.FLOAT.name, TokenEnum.BOOLEAN.name, TokenEnum.PI.name, TokenEnum.E.name ]))) self.syntax = syntax self.parse() pass # End Parser's constructor ! def parse(self): @self.pg.production("main : program") def main_program(state, p): if self.syntax is True: return [Node(AppConstant.PROGRAM_NODE_NAME, p[0])] return Main(p[0]) @self.pg.production('program : statement_full') def program_statement(state, p): if self.syntax is True: return [Node(AppConstant.STATEMENT_FULL_NODE_NAME, p[0])] return Program(p[0], None, state) @self.pg.production('program : statement_full program') def program_statement_program(state, p): if self.syntax is True: return [ Node(AppConstant.STATEMENT_FULL_NODE_NAME, p[0]), Node(AppConstant.PROGRAM_NODE_NAME, p[1]) ] return Program(p[0], p[1], state) @self.pg.production('expression : LEFT_PARENT expression RIGHT_PARENT') def expression_parenthesis(state, p): if self.syntax is True: return [ Node('{'), Node(AppConstant.EXPRESSION_NODE_NAME, p[1]), Node('}') ] return ExpressParenthesis(p[1]) @self.pg.production( 'statement_full : IF LEFT_PARENT expression RIGHT_PARENT LEFT_BRACKET block RIGHT_BRACKET' ) def expression_if(state, p): if self.syntax is True: return [ Node(AppConstant.IF_NODE_NAME), Node('{'), Node(AppConstant.EXPRESSION_NODE_NAME, p[2]), Node('}'), Node('{'), Node(AppConstant.BLOCK_NODE_NAME, p[5]), Node('}') ] return If(condition=p[2], body=p[5], state=state) @self.pg.production( 'statement_full : IF LEFT_PARENT expression RIGHT_PARENT LEFT_BRACKET' ' block ' 'RIGHT_BRACKET ELSE LEFT_BRACKET' ' block ' 'RIGHT_BRACKET') def expression_if_else(state, p): if self.syntax is True: return [ Node(AppConstant.IF_NODE_NAME), Node('{'), Node(AppConstant.EXPRESSION_NODE_NAME, p[2]), Node('}'), Node('{'), Node(AppConstant.BLOCK_NODE_NAME, p[5]), Node('}'), Node(AppConstant.ELSE_NODE_NAME), Node('{'), Node(AppConstant.BLOCK_NODE_NAME, p[9]), Node('}') ] return If(condition=p[2], body=p[5], else_body=p[9], state=state) @self.pg.production('block : statement_full') def block_expr(state, p): if self.syntax is True: return [Node("statement_full", p[0])] return Block(p[0], None, state) @self.pg.production('block : statement_full block') def block_expr_block(state, p): if self.syntax is True: return [ Node("statement_full", p[0]), Node(AppConstant.BLOCK_NODE_NAME, p[1]) ] return Block(p[0], p[1], state) @self.pg.production('statement_full : statement ' + TokenEnum.SEMI_COLON.name) def statement_full(state, p): if self.syntax is True: return [ Node(AppConstant.STATEMENT_NODE_NAME, p[0]), Node(AppConstant.SEMI_COLON_SIGN) ] return StatementFull(p[0]) @self.pg.production('statement : expression') def statement_expr(state, p): if self.syntax is True: return [Node(AppConstant.EXPRESSION_NODE_NAME, p[0])] return Statement(p[0]) @self.pg.production('statement : LET IDENTIFIER ASSIGN expression') def statement_assignment(state, p): if self.syntax is True: return [ Node(AppConstant.LET_NODE_NAME), Node(AppConstant.IDENTIFIER_NODE_NAME, p[1]), Node(AppConstant.EQUAL_SIGN), Node(AppConstant.EXPRESSION_NODE_NAME, p[3]) ] return Assignment(Variable(p[1].getstr(), state), p[3], state) @self.pg.production( 'statement_full : FUNCTION IDENTIFIER LEFT_PARENT RIGHT_PARENT LEFT_BRACKET block RIGHT_BRACKET' ) def statement_func_noargs(state, p): if self.syntax is True: return [ Node(AppConstant.FUNCTION_NODE_NAME), Node(AppConstant.IDENTIFIER_NODE_NAME, p[1]), Node('{'), Node('}'), Node('{'), Node(AppConstant.BLOCK_NODE_NAME, p[5]), Node('}') ] return FunctionDeclaration(name=p[1].getstr(), args=None, block=p[5], state=state) @self.pg.production('expression : NOT expression') def expression_not(state, p): if self.syntax is True: return [ Node(AppConstant.NOT_NODE_NAME), Node(AppConstant.EXPRESSION_NODE_NAME, p[1]) ] return Not(p[1], state) @self.pg.production('expression : expression SUM expression') @self.pg.production('expression : expression SUB expression') @self.pg.production('expression : expression MUL expression') @self.pg.production('expression : expression DIV expression') def expression_binary_operator(state, p): if p[1].gettokentype() == TokenEnum.SUM.name: if self.syntax is True: return [ Node(AppConstant.EXPRESSION_NODE_NAME, p[0]), Node(AppConstant.SUM_SIGN), Node(AppConstant.EXPRESSION_NODE_NAME, p[2]) ] return Sum(p[0], p[2], state) elif p[1].gettokentype() == TokenEnum.SUB.name: if self.syntax is True: return [ Node(AppConstant.EXPRESSION_NODE_NAME, p[0]), Node(AppConstant.SUM_SIGN), Node(AppConstant.EXPRESSION_NODE_NAME, p[2]) ] return Sub(p[0], p[2], state) elif p[1].gettokentype() == TokenEnum.MUL.name: if self.syntax is True: return [ Node(AppConstant.EXPRESSION_NODE_NAME, p[0]), Node(AppConstant.MUL_SIGN), Node(AppConstant.EXPRESSION_NODE_NAME, p[2]) ] return Mul(p[0], p[2], state) elif p[1].gettokentype() == TokenEnum.DIV.name: if self.syntax is True: return [ Node(AppConstant.EXPRESSION_NODE_NAME, p[0]), Node(AppConstant.DIV_SIGN), Node(AppConstant.EXPRESSION_NODE_NAME, p[2]) ] return Div(p[0], p[2], state) else: raise LogicError('Oops, this should not be possible!') @self.pg.production('expression : expression NEQ expression') @self.pg.production('expression : expression EQ expression') @self.pg.production('expression : expression GTEQ expression') @self.pg.production('expression : expression LTEQ expression') @self.pg.production('expression : expression GT expression') @self.pg.production('expression : expression LT expression') @self.pg.production('expression : expression AND expression') @self.pg.production('expression : expression OR expression') def expression_equality(state, p): if p[1].gettokentype() == TokenEnum.EQ.name: if self.syntax is True: return [ Node(AppConstant.EXPRESSION_NODE_NAME, p[0]), Node(AppConstant.EQUAL_SIGN), Node(AppConstant.EXPRESSION_NODE_NAME, p[2]) ] return Equal(p[0], p[2], state) elif p[1].gettokentype() == TokenEnum.NEQ.name: if self.syntax is True: return [ Node(AppConstant.EXPRESSION_NODE_NAME, p[0]), Node(AppConstant.NOT_EQUAL_SIGN), Node(AppConstant.EXPRESSION_NODE_NAME, p[2]) ] return NotEqual(p[0], p[2], state) elif p[1].gettokentype() == TokenEnum.GTEQ.name: if self.syntax is True: return [ Node(AppConstant.EXPRESSION_NODE_NAME, p[0]), Node(AppConstant.GREATER_THAN_EQUAL_SIGN), Node(AppConstant.EXPRESSION_NODE_NAME, p[2]) ] return GreaterThanEqual(p[0], p[2], state) elif p[1].gettokentype() == TokenEnum.LTEQ.name: if self.syntax is True: return [ Node(AppConstant.EXPRESSION_NODE_NAME, p[0]), Node(AppConstant.LESS_THAN__EQUAL_SIGN), Node(AppConstant.EXPRESSION_NODE_NAME, p[2]) ] return LessThanEqual(p[0], p[2], state) elif p[1].gettokentype() == TokenEnum.GT.name: if self.syntax is True: return [ Node(AppConstant.EXPRESSION_NODE_NAME, p[0]), Node(AppConstant.GREATER_THAN_SIGN), Node(AppConstant.EXPRESSION_NODE_NAME, p[2]) ] return GreaterThan(p[0], p[2], state) elif p[1].gettokentype() == TokenEnum.LT.name: if self.syntax is True: return [ Node(AppConstant.EXPRESSION_NODE_NAME, p[0]), Node(AppConstant.LESS_THAN_SIGN), Node(AppConstant.EXPRESSION_NODE_NAME, p[2]) ] return LessThan(p[0], p[2], state) elif p[1].gettokentype() == TokenEnum.AND.name: if self.syntax is True: return [ Node(AppConstant.EXPRESSION_NODE_NAME, p[0]), Node(AppConstant.AND_NODE_NAME), Node(AppConstant.EXPRESSION_NODE_NAME, p[2]) ] return And(p[0], p[2], state) elif p[1].gettokentype() == TokenEnum.OR.name: if self.syntax is True: return [ Node(AppConstant.EXPRESSION_NODE_NAME, p[0]), Node(AppConstant.OR_NODE_NAME), Node(AppConstant.EXPRESSION_NODE_NAME, p[2]) ] return Or(p[0], p[2], state) else: raise LogicError("Shouldn't be possible") @self.pg.production('expression : INPUTTER LEFT_PARENT RIGHT_PARENT') def program(state, p): if self.syntax is True: return [ Node(AppConstant.INPUTTER_NODE_NAME), Node('{'), Node('}') ] return Input() @self.pg.production( 'expression : INPUTTER LEFT_PARENT expression RIGHT_PARENT') def program(state, p): if self.syntax is True: return [ Node(AppConstant.INPUTTER_NODE_NAME), Node('{'), Node(AppConstant.EXPRESSION_NODE_NAME, p[2]), Node('}') ] return Input(expression=p[2], state=state) @self.pg.production('statement : PRINT LEFT_PARENT RIGHT_PARENT') def program(state, p): if self.syntax is True: return [ Node(AppConstant.PRINT_NODE_NAME), Node('{'), Node('}') ] return Print() @self.pg.production( 'statement : PRINT LEFT_PARENT expression RIGHT_PARENT') def program(state, p): if self.syntax is True: return [ Node(AppConstant.PRINT_NODE_NAME), Node('{'), Node(AppConstant.EXPRESSION_NODE_NAME, p[2]), Node('}') ] return Print(first_expression=p[2], state=state) @self.pg.production( 'statement : PRINT LEFT_PARENT expression COMMA expression RIGHT_PARENT' ) def program(state, p): if self.syntax is True: return [ Node(AppConstant.PRINT_NODE_NAME), Node('{'), Node(AppConstant.EXPRESSION_NODE_NAME, p[2]), Node('}') ] return Print(first_expression=p[2], second_expression=p[4], state=state) @self.pg.production( 'expression : ABSOLUTE LEFT_PARENT expression RIGHT_PARENT') def expression_absolute(state, p): if self.syntax is True: return [ Node(AppConstant.MATH_ABS_NODE_NAME), Node('{'), Node(AppConstant.EXPRESSION_NODE_NAME, p[2]), Node('}') ] return Absolute(p[2], state) @self.pg.production( 'expression : SIN LEFT_PARENT expression RIGHT_PARENT') def expression_absolute(state, p): if self.syntax is True: return [ Node(AppConstant.MATH_SIN_NODE_NAME), Node('{'), Node(AppConstant.EXPRESSION_NODE_NAME, p[2]), Node('}') ] return Sin(p[2], state) @self.pg.production( 'expression : COS LEFT_PARENT expression RIGHT_PARENT') def expression_absolute(state, p): if self.syntax is True: return [ Node(AppConstant.MATH_COS_NODE_NAME), Node('{'), Node(AppConstant.EXPRESSION_NODE_NAME, p[2]), Node('}') ] return Cos(p[2], state) @self.pg.production( 'expression : TAN LEFT_PARENT expression RIGHT_PARENT') def expression_absolute(state, p): if self.syntax is True: return [ Node(AppConstant.MATH_TAN_NODE_NAME), Node('{'), Node(AppConstant.EXPRESSION_NODE_NAME, p[2]), Node('}') ] return Tan(p[2], state) @self.pg.production( 'expression : POWER LEFT_PARENT expression COMMA expression RIGHT_PARENT' ) def expression_absolute(state, p): if self.syntax is True: return [ Node(AppConstant.MATH_POW_NODE_NAME), Node('{'), Node(AppConstant.EXPRESSION_NODE_NAME, p[2]), Node(AppConstant.COMMA_SIGN), Node(AppConstant.EXPRESSION_NODE_NAME, p[4]), Node('}') ] return Pow(p[2], p[4], state) @self.pg.production('expression : IDENTIFIER') def expression_variable(state, p): # Cannot return the value of a variable if it isn't yet defined if self.syntax is True: return [Node(AppConstant.IDENTIFIER_NODE_NAME, p[0])] return Variable(p[0].getstr(), state) @self.pg.production('expression : IDENTIFIER LEFT_PARENT RIGHT_PARENT') def expression_call_noargs(state, p): # Cannot return the value of a function if it isn't yet defined if self.syntax is True: return [ Node(AppConstant.IDENTIFIER_NODE_NAME, p[0]), Node('{'), Node('}') ] return CallFunction(name=p[0].getstr(), args=None, state=state) @self.pg.production('expression : const') def expression_const(state, p): if self.syntax is True: return [Node(AppConstant.CONSTANT_NODE_NAME, p[0])] return p[0] @self.pg.production('const : FLOAT') def constant_float(state, p): if self.syntax is True: return [Node(AppConstant.FLOAT_NODE_NAME, p[0])] return Float(p[0].getstr(), state) @self.pg.production('const : BOOLEAN') def constant_boolean(state, p): if self.syntax is True: return [Node(AppConstant.BOOLEAN_NODE_NAME, p[0])] return Boolean(p[0].getstr(), state) @self.pg.production('const : INTEGER') def constant_integer(state, p): if self.syntax is True: return [Node(AppConstant.INTEGER_NODE_NAME, p[0])] return Integer(p[0].getstr(), state) @self.pg.production('const : STRING') def constant_string(state, p): if self.syntax is True: return [Node(AppConstant.STRING_NODE_NAME, p[0])] return String(p[0].getstr().strip('"\''), state) @self.pg.production('const : PI') def constant_pi(state, p): if self.syntax is True: return [Node(AppConstant.MATH_CONST_PI_NODE_NAME, p[0])] return MathConstPI(p[0].getstr(), state) @self.pg.production('const : E') def constant_e(state, p): if self.syntax is True: return [Node(AppConstant.MATH_CONST_E_NODE_NAME, p[0])] return MathConstE(p[0].getstr(), state) @self.pg.error def error_handle(state, token): raise ValueError(token) def build(self): return self.pg.build()
class Parser(): def __init__(self): self.pg = ParserGenerator( # A list of all token names accepted by the parser. [ 'NUMBER', 'PRINT', 'SCANF', 'OPEN_KEY', 'CLOSE_KEY', 'OPEN_PAR', 'CLOSE_PAR', 'SEMI_COLON', 'DOTS', 'COMMA', 'SUM', 'SUB', 'MULT', 'DIV', 'OR', 'AND', 'NOT', 'BIGGER_THAN', 'SMALLER_THAN', 'EQUAL_TO', 'DIFF', 'INT', 'CHAR', 'VOID', 'WHILE', 'IF', 'ELSE', 'FUNC', 'QUOTE' ], precedence=[('left', ['PLUS', 'MINUS']), ('left', ['MULT', 'DIV']), ('left', ['AND', 'OR'])]) #___________PROGRAM___________________________________________ def parse(self): @self.pg.production('program : statement') def program(p): return p[0] #_____________FUNCTION___________________________________________ # funct # : 'f', variable , "(", variable, {",", variable} ,")" ,':' # |'{',statement ,'}' # ; @self.pg.production( 'statement : FUNC variable OPEN_PAREN variable OPEN_KEY COMMA variable CLOSE_KEY CLOSE_PAREN DOTS' ) def function(p): return Function(p[1], p[3], p[5]) # @self.pg.production('statement : OPEN_KEY statement CLOSE_KEY') #_____________STATEMENT___________________________________________ # statement # : 'if', paren_expr, '{',statement,'}' ,':' # | 'if', paren_expr ,'{',statement,'}' ,'else' ,'{',statement,'}' ,':' # | 'while', paren_expr, '{',statement,'}' ,':' # | 'print', paren_expr, ';' # | atribution # ;'' @self.pg.production( 'statement : IF paren_expression OPEN_KEY statement CLOSE_KEY DOTS' ) def statement_if(p): return If(p[1], p[3]) @self.pg.production( 'statement : IF paren_expression OPEN_KEY statement CLOSE_KEY ELSE OPEN_KEY statement CLOSE_KEY DOTS' ) def statement_if_else(p): return IfElse(p[1], p[3], p[7]) @self.pg.production( 'statement : WHILE paren_expression OPEN_KEY statement CLOSE_KEY DOTS' ) def statement_while(p): return IfElse(p[1], p[3]) @self.pg.production('statement : PRINT paren_expression SEMI_COLON') def statement_print(p): return Print(p[1]) # @self.pg.production('statement : attribution') # def atribution(p): #_____________PAREN_EXPRESSION__________________________________________ # paren_expression # : '(', expression, ')' # | '(' ,bools, ')' # | '(' ,relats, ')' # ; @self.pg.production('paren_expression : OPEN_PAR expression CLOSE_PAR') @self.pg.production('paren_expression : OPEN_PAR booleans CLOSE_PAR') @self.pg.production( 'paren_expression : OPEN_PAR relational_expression CLOSE_PAR') def paren_expression(p): return p[1] #_____________BOOLEANS__________________________________________ # bools # : expression, '//', expression # | expression, '&&', expression # | expression, '!', expression # ; @self.pg.production('booleans : expression OR expression', precedence='OR') @self.pg.production('booleans : expression AND expression', precedence='AND') @self.pg.production('booleans : expression NOT expression') def booleans(p): left = p[0] right = p[2] bool_operator = p[1] if bool_operator.gettokentype() == 'OR': return Or(left, right) elif bool_operator.gettokentype() == 'AND': return And(left, right) elif bool_operator.gettokentype() == 'NOT': return Not(left) #_____________RELATIONAL_EXPRESSION___________________________________________ # relats # : expression, '>', expression # | expression, '<', expression # | expression, '==', expression # | expression, '!=', expression # ; @self.pg.production( 'relational_expression : expression BIGGER_THAN expression') @self.pg.production( 'relational_expression : expression SMALLER_THAN expression') @self.pg.production( 'relational_expression : expression EQUAL_TO EQUAL_TO expression') @self.pg.production( 'relational_expression : expression DIFF expression') def relational_expression(p): left = p[0] right = p[2] relat_operator = p[1] if relat_operator.gettokentype() == 'BIGGER_THAN': return Bigger(left, right) elif relat_operator.gettokentype() == 'SMALLER_THAN': return Smaller(left, right) elif relat_operator.gettokentype() == 'EQUAL_TO': return Equal(left, right) elif relat_operator.gettokentype() == 'DIFF': return Different(left, right) #_____________EXPRESSION___________________________________________ # expression # :term # |term, '+', term # |term, '-', term # ; @self.pg.production('expression : term') @self.pg.production('expression : term SUM term', precedence='PLUS') @self.pg.production('expression : term SUB term', precedence='MINUS') def expression(p): left = p[0] right = p[2] operator = p[1] if operator.gettokentype() == 'SUM': return Sum(left, right) elif operator.gettokentype() == 'SUB': return Sub(left, right) elif operator.gettokentype() == None: return left #_____________TERM___________________________________________ # term # : factor, '*', factor # | factor, '/', factor # ; @self.pg.production('term : factor MULT factor', precedence='MULT') @self.pg.production('term : factor DIV factor', precedence='DIV') def term(p): left = p[0] right = p[2] t_operator = p[1] if t_operator.gettokentype() == 'MULT': return Multiply(left, right) elif t_operator.gettokentype() == 'DIV': return Divide(left, right) #_____________FACTOR___________________________________________ # factor # : '+', factor # | '-', factor # | number # | '(',expression,')' # | variable # ; @self.pg.production('factor : SUM factor') @self.pg.production('factor : SUB factor') @self.pg.production('factor : number') @self.pg.production('factor : OPEN_PAR expression CLOSE_PAR') @self.pg.production('factor : variable') def factor(p): left = p[0] right = p[2] middle = p[1] if left.gettokentype() == 'SUM': return Plus(middle) elif left.gettokentype() == 'SUB': return Minus(middle) elif left.gettokentype() == 'number': return left elif middle.gettokentype() == 'expression': return middle elif left.gettokentype() == 'variable': return left #_____________ATTRIBUTION___________________________________________ # attribution # : variable, '=', expression # ; @self.pg.production('attribution : variable EQUAL_TO expression') def attribution(p): return #_____________VARIABLE___________________________________________ # variable # : STRING, {STRING, INT, '_'} # ; @self.pg.production('expression : STRING') @self.pg.production('expression : STRINGINT') @self.pg.production('expression : STRING_') @self.pg.production('expression : STRING_STRING') @self.pg.production('expression : STRING_INT') def variable(p): return String(p[0].value) #_____________NUMBER___________________________________________ # number # : FLOAT # ; @self.pg.production('expression : NUMBER') def number(p): return Number(p[0].value) #____________STRING__________________________________________ # STRING # : "A" | "B" | "C" | "D" | "E" | "F" | "G" # | "H" | "I" | "J" | "K" | "L" | "M" | "N" # | "O" | "P" | "Q" | "R" | "S" | "T" | "U" # | "V" | "W" | "X" | "Y" | "Z" # | "a" | "b"| "c" | "d" | "e" | "f" | "g" # | "h" | "i"| "j" | "k" | "l" | "m" | "n" # | "o" | "p"| "q" | "r" | "s" | "t" | "u" # | "v" | "w"| "x" | "y" | "z" ; # ; @self.pg.production('expression : STRING') def string(p): return String(p[0].value) #_____________FLOAT___________________________________________ # FLOAT # : INT, ['.', INT] # ; @self.pg.production('expression : FLOAT') @self.pg.production('expression : INT.INT') def float(p): return Number(p[0].value) #_____________INTEGER___________________________________________ # INT # : "0"|"1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" # ; @self.pg.production('expression : INT') def integer(p): return Number(p[0].value) # _____________TEXT___________________________________________ @self.pg.production('text : QUOTE IDENTIFIER QUOTE') def text(p): return p[1] @self.pg.error def error_handle(token): raise ValueError(token) def get_parser(self): return self.pg.build()