140 lines
3.0 KiB
Python
140 lines
3.0 KiB
Python
# ------------------------------------------------------------
|
|
# Grammar of the TRIPLA language
|
|
# ------------------------------------------------------------
|
|
|
|
import ply.yacc as yacc
|
|
import syntax as ast
|
|
from triplalex import tokens
|
|
|
|
# Operator precedence
|
|
precedence = (
|
|
('left', 'COMP'),
|
|
('left', 'EQOP'),
|
|
('left', 'AOP'),
|
|
)
|
|
|
|
start = 'E'
|
|
|
|
# ------------------------------------------------------------
|
|
# Rules for E
|
|
# ------------------------------------------------------------
|
|
|
|
def p_E_let(p):
|
|
'E : LET D IN E'
|
|
p[0] = ast.LET(p[2], p[4])
|
|
|
|
def p_E_id(p):
|
|
'E : ID'
|
|
p[0] = ast.ID(p[1])
|
|
|
|
def p_E_call(p):
|
|
'E : ID LPAREN A RPAREN'
|
|
# E : ID(A)
|
|
p[0] = ast.CALL(p[1], p[3])
|
|
|
|
def p_E_aop(p):
|
|
'E : E AOP E'
|
|
p[0] = ast.AOP(p[2], p[1], p[3])
|
|
|
|
def p_E_paren(p):
|
|
'E : LPAREN E RPAREN'
|
|
# E : (E)
|
|
p[0] = p[2]
|
|
|
|
def p_E_const(p):
|
|
'E : CONST'
|
|
p[0] = ast.CONST(p[1])
|
|
|
|
def p_E_assign(p):
|
|
'E : ID ASSIGN E'
|
|
p[0] = ast.ASSIGN(ast.ID(p[1]), p[3])
|
|
|
|
def p_E_seq(p):
|
|
'E : E SEMICOLON E'
|
|
p[0] = ast.SEQ(p[1], p[3])
|
|
|
|
def p_E_if(p):
|
|
'E : IF LPAREN B RPAREN THEN E ELSE E'
|
|
p[0] = ast.IF(p[3], p[6], p[8])
|
|
|
|
def p_E_while(p):
|
|
'E : WHILE LPAREN B RPAREN DO LBRACE E RBRACE'
|
|
p[0] = ast.WHILE(p[3], p[7])
|
|
|
|
# ------------------------------------------------------------
|
|
# Rules for A
|
|
# ------------------------------------------------------------
|
|
|
|
def p_A_single(p):
|
|
'A : E'
|
|
p[0] = [p[1]]
|
|
|
|
def p_A_multiple(p):
|
|
'A : A COMMA E'
|
|
p[0] = p[1] + [p[3]]
|
|
|
|
# ------------------------------------------------------------
|
|
# Rules for D
|
|
# ------------------------------------------------------------
|
|
|
|
def p_D_single(p):
|
|
'D : ID LPAREN V RPAREN LBRACE E RBRACE'
|
|
p[0] = [ast.DECL(p[1], p[3], p[6])]
|
|
|
|
def p_D_concat(p):
|
|
'D : D D'
|
|
p[0] = p[1] + p[2]
|
|
|
|
# ------------------------------------------------------------
|
|
# Rules for V
|
|
# ------------------------------------------------------------
|
|
|
|
def p_V_single(p):
|
|
'V : ID'
|
|
p[0] = [p[1]]
|
|
|
|
def p_V_multiple(p):
|
|
'V : V COMMA ID'
|
|
p[0] = p[1] + [p[3]]
|
|
|
|
# ------------------------------------------------------------
|
|
# Rules for B
|
|
# ------------------------------------------------------------
|
|
|
|
def p_B_eqop_E(p):
|
|
'B : E EQOP E'
|
|
p[0] = ast.EQOP(p[2], p[1], p[3])
|
|
|
|
def p_B_comp(p):
|
|
'B : E COMP E'
|
|
p[0] = ast.COMP(p[2], p[1], p[3])
|
|
|
|
def p_B_eqop_B(p):
|
|
'B : B EQOP B'
|
|
p[0] = ast.EQOP(p[2], p[1], p[3])
|
|
|
|
def p_B_lop(p):
|
|
'B : B LOP B'
|
|
p[0] = ast.LOP(p[2], p[1], p[3])
|
|
|
|
def p_B_true(p):
|
|
'B : TRUE'
|
|
p[0] = ast.CONST(True)
|
|
|
|
def p_B_false(p):
|
|
'B : FALSE'
|
|
p[0] = ast.CONST(False)
|
|
|
|
def p_B_paren(p):
|
|
'B : LPAREN B RPAREN'
|
|
# B : (B)
|
|
p[0] = p[2]
|
|
|
|
# Error handling
|
|
def p_error(p):
|
|
if p:
|
|
print("Syntax error at token:", p.type, "value:", p.value)
|
|
else:
|
|
print("Syntax error at EOF")
|
|
|
|
parser = yacc.yacc() |