Spaces:
Runtime error
Runtime error
from dataclasses import dataclass | |
import sys | |
from lexer import * | |
# import sim | |
from dataclasses_sim import * | |
class Parser(object): | |
def __init__(self, lexer): | |
self.lexer = lexer | |
self.curr_token = self.lexer.get_token() | |
self.lexer.lineNum = 0 | |
def check_type(self, Type): | |
if self.curr_token.type == Type: | |
self.curr_token = self.lexer.get_token() | |
else: | |
print("Expected Token Type: ", Type) | |
print("Got Token: ", self.curr_token) | |
print("At line number:", self.lexer.lineNum) | |
print(self.lexer.curLine) | |
print(" "*(self.lexer.curLinePos-1),"^") | |
sys.exit('Invalid character') | |
def parse_if(self): | |
self.check_type(IF) | |
condition = self.logical() | |
self.check_type(THEN) | |
if self.curr_token.type != BEGIN and self.curr_token.type != IF and self.curr_token.type != WHILE and self.curr_token.type != FOR and self.curr_token.type != FUNCTION: | |
true = self.parse() | |
self.check_type(SEMI) | |
else: | |
true = self.parse() | |
self.check_type(ELSE) | |
while self.curr_token.type == IF: | |
self.check_type(IF) | |
condition = self.logical() | |
self.check_type(THEN) | |
if self.curr_token.type != BEGIN and self.curr_token.type != IF and self.curr_token.type != WHILE and self.curr_token.type != FOR and self.curr_token.type != FUNCTION: | |
true = self.parse() | |
self.check_type(SEMI) | |
else: | |
true = self.parse() | |
self.check_type(ELSE) | |
if self.curr_token.type != END: | |
if self.curr_token.type != BEGIN and self.curr_token.type != IF and self.curr_token.type != WHILE and self.curr_token.type != FOR and self.curr_token.type != FUNCTION: | |
false = self.parse() | |
self.check_type(SEMI) | |
else: | |
false = self.parse() | |
else: | |
false = None | |
self.check_type(END) | |
node = IfElse(condition, true, false) | |
return node | |
def parse_begin(self): | |
"""parse_begin : """ | |
self.check_type(BEGIN) | |
if self.curr_token.type == END: | |
self.check_type(END) | |
return Seq([]) | |
# s = self.parse_list() | |
ignoreSEMI = False | |
if self.curr_token.type == IF or self.curr_token.type == WHILE or self.curr_token.type == FOR or self.curr_token.type == FUNCTION or self.curr_token.type == BEGIN: | |
ignoreSEMI = True | |
e = self.parse() | |
token = self.curr_token | |
Type = token.type | |
seq = [e] | |
while Type != END: | |
if not ignoreSEMI: | |
self.check_type(SEMI) | |
ignoreSEMI = False | |
if self.curr_token.type == END: | |
break | |
if self.curr_token.type == IF or self.curr_token.type == WHILE or self.curr_token.type == FOR or self.curr_token.type == FUNCTION or self.curr_token.type == BEGIN: | |
ignoreSEMI = True | |
e = self.parse() | |
seq.append(e) | |
token = self.curr_token | |
Type = token.type | |
# if Type == SEMI: | |
# self.check_type(SEMI) | |
self.check_type(END) | |
return Seq(seq) | |
# return s | |
def parse_for(self): | |
self.check_type(FOR) | |
start = self.parse() | |
# print("Hi", start) | |
self.check_type(SEMI) | |
condition = self.logical() | |
# print("Hi2", end) | |
self.check_type(SEMI) | |
increment = self.parse() | |
# print("Hi3",jump) | |
self.check_type(DO) | |
if self.curr_token.type != BEGIN and self.curr_token.type != IF and self.curr_token.type != WHILE and self.curr_token.type != FOR and self.curr_token.type != FUNCTION: | |
body = self.parse() | |
self.check_type(SEMI) | |
self.check_type(END) | |
return ForLoop(start, condition, increment, body) | |
body = self.parse() | |
self.check_type(END) | |
return ForLoop(start, condition, increment, body) | |
def parse_while(self): | |
self.check_type(WHILE) | |
c = self.logical() | |
self.check_type(DO) | |
if self.curr_token.type != BEGIN and self.curr_token.type != IF and self.curr_token.type != WHILE and self.curr_token.type != FOR and self.curr_token.type != FUNCTION: | |
b = self.parse() | |
self.check_type(SEMI) | |
self.check_type(END) | |
return While(c, b) | |
b = self.parse() | |
self.check_type(END) | |
return While(c, b) | |
def parse_list_append(self): | |
self.check_type(APPEND) | |
self.check_type(LPAREN) | |
var = self.variable() | |
self.check_type(COMMA) | |
item = self.parse() | |
self.check_type(RPAREN) | |
return list_append(var, item) | |
def parse_list_slice(self, c): | |
self.check_type(LSPAREN) | |
if self.curr_token.type==COMMA: | |
start = NumLiteral(0) | |
else: | |
start = self.parse() | |
if self.curr_token.type==RSPAREN: | |
index_type = True | |
self.check_type(RSPAREN) | |
elif self.curr_token.type==COMMA: | |
index_type = False | |
self.check_type(COMMA) | |
end = self.parse() | |
else: | |
index_type = False | |
end = self.parse() | |
if index_type==False: | |
if self.curr_token.type==COMMA: | |
self.check_type(COMMA) | |
if self.curr_token.type!=RSPAREN: | |
jump = self.parse() | |
else: | |
jump = NumLiteral(1) | |
else: | |
jump = NumLiteral(1) | |
self.check_type(RSPAREN) | |
else: | |
end = None | |
jump = None | |
return list_Slicing(c, start, end, jump) | |
def parse_inc(self): | |
self.check_type(INC) | |
self.check_type(LPAREN) | |
c = self.parse() | |
self.check_type(RPAREN) | |
return Increment(c) | |
def parse_dec(self): | |
self.check_type(DEC) | |
self.check_type(LPAREN) | |
c = self.parse() | |
self.check_type(RPAREN) | |
return Decrement(c) | |
def parse_len(self): | |
self.check_type(LPAREN) | |
c = self.parse() | |
self.check_type(RPAREN) | |
return length(c) | |
def parse_head(self): | |
self.check_type(LPAREN) | |
c = self.parse() | |
self.check_type(RPAREN) | |
return list_head(c) | |
def parse_tail(self): | |
self.check_type(LPAREN) | |
c = self.parse() | |
self.check_type(RPAREN) | |
return list_tail(c) | |
def parse_isempty(self): | |
self.check_type(LPAREN) | |
c = self.parse() | |
self.check_type(RPAREN) | |
return list_isempty(c) | |
def parse_slice(self, c): | |
self.check_type(LSPAREN) | |
if self.curr_token.type==COMMA: | |
# self.check_type(COMMA) | |
start = NumLiteral(0) | |
else: | |
start = self.parse() | |
if self.curr_token.type==RSPAREN: | |
index_type = True | |
self.check_type(RSPAREN) | |
elif self.curr_token.type==COMMA: | |
index_type = False | |
self.check_type(COMMA) | |
if self.curr_token.type!=COMMA: | |
end = self.parse() | |
else: | |
end = None | |
else: | |
index_type = False | |
end = self.parse() | |
if index_type==False: | |
if self.curr_token.type==COMMA: | |
self.check_type(COMMA) | |
if self.curr_token.type!=RSPAREN: | |
jump = self.parse() | |
else: | |
jump = NumLiteral(1) | |
else: | |
jump = NumLiteral(1) | |
self.check_type(RSPAREN) | |
else: | |
end = None | |
jump = None | |
return Slicing(c, start, end, jump) | |
def parse_print(self): | |
self.check_type(PRINT) | |
self.check_type(LPAREN) | |
if self.curr_token.type != RPAREN: | |
e = self.logical() | |
else: | |
e = None | |
# print(e) | |
self.check_type(RPAREN) | |
# if self.curr_token.type != END: | |
# e = self.logical() | |
# else: | |
# e = None | |
# # print(e) | |
# self.check_type(END) | |
return Statement("print", e) | |
def parse_return(self): | |
self.check_type(RETURN) | |
e = self.logical() | |
return Statement("return", e) | |
def parse_list(self, Type): | |
if Type != LSPAREN: | |
# print("ENTER") | |
self.check_type(COLON) | |
token = self.curr_token | |
self.check_type(INTEGER) | |
Type = token.type | |
datatype = Type | |
# print(datatype) | |
else: | |
datatype = NONE | |
self.check_type(LSPAREN) | |
ele = self.parse() | |
value =[ele] | |
token = self.curr_token | |
Type = token.type | |
while Type!= RSPAREN: | |
self.check_type(COMMA) | |
ele = self.parse() | |
value.append(ele) | |
token = self.curr_token | |
# print(token) | |
Type = token.type | |
self.check_type(RSPAREN) | |
# print(type(datatype)) | |
# print("done and dusted") | |
return Listing(value, datatype) | |
def parse_func(self): | |
self.check_type(FUNCTION) | |
# name = self.variable("Variable") | |
name = self.variable() | |
self.check_type(LPAREN) | |
# var = self.variable("Variable") | |
var = self.variable() | |
token = self.curr_token | |
Type = token.type | |
params = [var] if var != None else [] | |
while Type != RPAREN: | |
self.check_type(COMMA) | |
if self.curr_token.type == RPAREN: | |
break | |
# var = self.variable("Variable") | |
var = self.variable() | |
params.append(var) | |
token = self.curr_token | |
Type = token.type | |
self.check_type(RPAREN) | |
if self.curr_token.type == BEGIN: | |
body = self.parse() | |
else: | |
self.check_type(BEGIN) | |
return Function(name, params, body) | |
def parse_func_call(self, n): | |
node = n | |
self.check_type(LPAREN) | |
if self.curr_token.type == RPAREN: | |
self.check_type(RPAREN) | |
if self.curr_token.type == LPAREN: | |
return self.parse_func_call(FunCall(node, [])) | |
return FunCall(node, []) | |
var = self.logical() | |
token = self.curr_token | |
Type = token.type | |
params = [var] if var != None else [] | |
while Type != RPAREN: | |
self.check_type(COMMA) | |
if self.curr_token.type == RPAREN: | |
break | |
var = self.logical() | |
params.append(var) | |
token = self.curr_token | |
Type = token.type | |
self.check_type(RPAREN) | |
if self.curr_token.type == LPAREN: | |
return self.parse_func_call(FunCall(node, params)) | |
return FunCall(node, params) | |
def variable(self, ASTtype=None): | |
token = self.curr_token | |
Type = token.type | |
if Type == ID: | |
self.check_type(ID) | |
if ASTtype=="Variable": | |
token = self.curr_token | |
Type = token.type | |
#self.parse_slice(Variable(token.value), Type) | |
return Variable(token.value) | |
else: | |
return MutVar(token.value) | |
def precedence3(self): | |
'''precedence3 : INTEGER | LPAREN precedence1 RPAREN | BoolLiteral | Indentifier| (+/-)precedence3 | StringLiteral''' | |
token = self.curr_token | |
Type = token.type | |
if Type == PLUS: | |
self.check_type(PLUS) | |
node = UnOp(operator=token.value, mid=self.precedence3()) | |
return node | |
elif Type == MINUS: | |
self.check_type(MINUS) | |
node = UnOp(operator=token.value, mid=self.precedence3()) | |
return node | |
elif Type == LPAREN: | |
self.check_type(LPAREN) | |
# node = self.precedence1() | |
node = self.logical() | |
self.check_type(RPAREN) | |
return node | |
elif Type == FRACTION_CONST: | |
self.check_type(FRACTION_CONST) | |
return NumLiteral(token.value) | |
elif Type == REAL_CONST: | |
self.check_type(REAL_CONST) | |
return FloatLiteral(token.value) | |
elif Type == INTEGER_CONST: | |
self.check_type(INTEGER_CONST) | |
return IntLiteral(token.value) | |
elif Type == TRUE or Type == FALSE: | |
self.check_type(Type) | |
return BoolLiteral(token.value) | |
elif Type == LEN: | |
self.check_type(LEN) | |
return self.parse_len() | |
elif Type == HEAD: | |
self.check_type(HEAD) | |
return self.parse_head | |
elif Type == TAIL: | |
self.check_type(TAIL) | |
return self.parse_tail | |
elif Type == ISEMPTY: | |
self.check_type(ISEMPTY) | |
return self.parse_isempty | |
elif Type == LIST: | |
self.check_type(LIST) | |
if self.curr_token.type == COLON: | |
return self.parse_list(self.curr_token.type) | |
return self.parse_list(self.curr_token.type) | |
elif Type == ID: | |
self.check_type(ID) | |
if self.curr_token.type == LPAREN: | |
return self.parse_func_call(MutVar(token.value)) | |
elif self.curr_token.type == LSPAREN: | |
return self.parse_slice(MutVar(token.value)) | |
return (MutVar(token.value)) | |
elif Type == STRING: | |
# Nothing new here, just eat the STRING token and return the String() AST. | |
self.check_type(STRING) | |
return StringLiteral(token.value) | |
else: | |
# if Type == END: | |
# self.check_type(END) | |
# return | |
print("None of the suggested tokens found:", INTEGER_CONST, ID, LPAREN, STRING, TRUE, FALSE, "...") | |
self.check_type(INTEGER_CONST) | |
def exponential(self): | |
"""exponential : precedence3 | precedence3 POWER precedence3""" | |
node = self.precedence3() | |
token = self.curr_token | |
Type = token.type | |
l = [node] | |
if Type == POWER: | |
while (Type == POWER): | |
token = self.curr_token | |
if token.type == POWER: | |
self.check_type(POWER) | |
e = self.precedence3() | |
# print(e) | |
l.append(e) | |
Type = self.curr_token.type | |
# e = self.precedence3() | |
# print(l) | |
i = 1 | |
while len(l) > 0 : | |
e = l.pop() | |
if i==1: | |
node = BinOp(left=l.pop(), operator=token.value, right=e) | |
else: | |
node = BinOp(left=e, operator=token.value, right=node) | |
i+=1 | |
return node | |
def precedence2(self): | |
"""precedence2 : precedence3 | precedence3 MUL/DIV precedence3""" | |
node = self.exponential() | |
token = self.curr_token | |
Type = token.type | |
while (Type == MUL or Type ==FLOAT_DIV or Type == MODULO or Type == INT_DIV): | |
token = self.curr_token | |
if token.type == MUL: | |
self.check_type(MUL) | |
elif token.type == FLOAT_DIV: | |
self.check_type(FLOAT_DIV) | |
elif token.type == INT_DIV: | |
self.check_type(INT_DIV) | |
elif token.type == MODULO: | |
self.check_type(MODULO) | |
elif token.type == INT_DIV: | |
self.check_type(INT_DIV) | |
node = BinOp(left=node, operator=token.value, right=self.exponential()) | |
Type = self.curr_token.type | |
return node | |
def precedence1(self): | |
"""precedence1 : precedence2 | precedence2 PLUS/MINUS precedence2""" | |
node = self.precedence2() | |
Type = self.curr_token.type | |
while (Type == PLUS or Type ==MINUS): | |
token = self.curr_token | |
if token.type == PLUS: | |
self.check_type(PLUS) | |
elif token.type == MINUS: | |
self.check_type(MINUS) | |
node = BinOp(left=node, operator=token.value, right=self.precedence2()) | |
Type = self.curr_token.type | |
return node | |
# def parse(self): | |
# return self.precedence1() | |
def relational(self, n=None): | |
"""relational : precedence1 | precedence1 relationalOperator precedence1""" | |
if n == None: | |
node = self.precedence1() | |
else: | |
node = n | |
Type = self.curr_token.type | |
# print(Type) | |
# while(Type == GT or Type == GTEQ or Type == LT or Type == LTEQ): | |
if(Type == GT or Type == GTEQ or Type == LT or Type == LTEQ or Type == EQEQ or Type == NOTEQ): | |
token = self.curr_token | |
if token.type == GT: | |
self.check_type(GT) | |
elif token.type == GTEQ: | |
self.check_type(GTEQ) | |
elif token.type == LT: | |
self.check_type(LT) | |
elif token.type == LTEQ: | |
self.check_type(LTEQ) | |
elif token.type == EQEQ: | |
self.check_type(EQEQ) | |
elif token.type == NOTEQ: | |
self.check_type(NOTEQ) | |
node = BinOp(left=node, operator=token.value, right=self.precedence1()) | |
# Type = self.curr_token.type | |
return node | |
def logical(self, n=None): | |
"""logical : relational | relational logicalOperator relational""" | |
if n == None: | |
node = self.relational() | |
else: | |
node = n | |
# node = self.relational() | |
Type = self.curr_token.type | |
if(Type == OR or Type == AND): | |
token = self.curr_token | |
if token.type == AND: | |
self.check_type(AND) | |
elif token.type == OR: | |
self.check_type(OR) | |
node = BinOp(left=node, operator= token.value, right=self.relational()) | |
return node | |
def assignment(self, n=None): | |
"""assignment : variable ASSIGN relational""" | |
if n == None: | |
node = self.variable() | |
else: | |
node = n | |
Type = self.curr_token.type | |
# token = self.curr_token | |
# print(Type) | |
# if Type == ASSIGN: | |
# self.check_type(ASSIGN) | |
# token = self.curr_token | |
# node = BinOp(left=node, operator=token.value, right=self.logical()) | |
# else: | |
# if isinstance(node,MutVar): | |
# node = self.logical(Get(node)) | |
# else: | |
# node = self.logical() | |
if(Type == ASSIGN or Type == PLUSEQ or Type == MINUSEQ or Type == FLOAT_DIVEQ or Type == MULEQ or Type == POWEREQ): | |
token = self.curr_token | |
if Type == ASSIGN: | |
self.check_type(ASSIGN) | |
node = BinOp(left=node, operator= token.value, right=self.logical()) | |
elif Type == MULEQ: | |
self.check_type(MULEQ) | |
# print(self.curr_token) | |
node = BinOp(left=node, operator= token.value, right=self.logical()) | |
elif Type == MINUSEQ: | |
self.check_type(MINUSEQ) | |
# print(self.curr_token) | |
node = BinOp(left=node, operator= token.value, right=self.logical()) | |
elif Type == FLOAT_DIVEQ: | |
self.check_type(FLOAT_DIVEQ) | |
# print(self.curr_token) | |
node = BinOp(left=node, operator= token.value, right=self.logical()) | |
elif Type == PLUSEQ: | |
self.check_type(PLUSEQ) | |
# print(self.curr_token) | |
node = BinOp(left=node, operator= token.value, right=self.logical()) | |
elif Type == POWEREQ: | |
self.check_type(POWEREQ) | |
# print(self.curr_token) | |
node = BinOp(left=node, operator= token.value, right=self.logical()) | |
else: | |
if isinstance(node,MutVar): | |
node = self.logical(node) | |
else: | |
node = self.logical() | |
return node | |
def parse(self): | |
"""parse : parse_if | parse_print | parse_begin | assignment""" | |
match self.curr_token.type: | |
case 'IF': | |
return self.parse_if() | |
case 'WHILE': | |
return self.parse_while() | |
case 'FOR': | |
return self.parse_for() | |
case 'PRINT': | |
return self.parse_print() | |
case 'RETURN': | |
return self.parse_return() | |
case 'BEGIN': | |
return self.parse_begin() | |
case 'FUNCTION': | |
return self.parse_func() | |
case 'BREAK': | |
self.check_type(BREAK) | |
return Statement("break",NumLiteral(0)) | |
case 'INC': | |
return self.parse_inc() | |
case 'DEC': | |
return self.parse_dec() | |
case 'APPEND': | |
return self.parse_list_append() | |
# case 'SEMI': | |
# return | |
# return self.parse() | |
case _: | |
node = self.variable() | |
if self.curr_token.type == LPAREN: | |
return self.parse_func_call(node) | |
# node = MutVar(node.name) | |
return self.assignment(node) | |