#define LOC (let pstart = $startpos in \ let pend = $endpos in ( \ pstart.pos_fname, \ pstart.pos_lnum, \ pend.pos_lnum, \ (pstart.pos_cnum - pstart.pos_bol + 1), \ (pend.pos_cnum - pend.pos_bol) \ )) %{ open Lexing open Ast %} /* Tokens */ %token LPAREN RPAREN LBRACK RBRACK LBRACE RBRACE SEMICOL COMMA %token NOT ADD SUB MUL DIV MOD %token EQ NE LT LE GT GE %token AND OR %token ASSIGN IF ELSE WHILE DO FOR RETURN EXTERN EXPORT %token INT BOOL FLOAT VOID %token EOF %token BOOL_CONST %token FLOAT_CONST %token INT_CONST %token ID /* Precedence */ %right ASSIGN %left OR %left AND %left EQ NE %left LT LE GT GE %left ADD SUB %left MUL DIV MOD %right NOT NEG CAST %nonassoc IF %nonassoc ELSE /* Start symbol */ %type program %start program %% basic_type : FLOAT { Float } | INT { Int } | BOOL { Bool } program : decl*; EOF { Program ($1, LOC) } decl : EXTERN; fun_header; SEMICOL { let (t, n, p) = $2 in FunDec(t, n, p, LOC) } | boption(EXPORT); fun_header; LBRACE; fun_body; RBRACE { let (t, n, p) = $2 in FunDef ($1, t, n, p, Block $4, LOC) } | EXTERN; basic_type; ID; SEMICOL { GlobalDec ($2, $3, LOC) } | EXTERN; t=basic_type; LBRACK; d=separated_list(COMMA, ID); RBRACK; n=ID; SEMICOL { GlobalDec (ArrayDec (t, d), n, LOC) } | boption(EXPORT); basic_type; ID; SEMICOL { GlobalDef ($1, $2, $3, None, LOC) } | boption(EXPORT); basic_type; ID; ASSIGN; expr; SEMICOL { GlobalDef ($1, $2, $3, Some $5, LOC) } | e=boption(EXPORT); t=basic_type; LBRACK; d=separated_list(COMMA, expr); RBRACK; n=ID; SEMICOL { GlobalDef (e, ArrayDef (t, d), n, None, LOC) } | e=boption(EXPORT); t=basic_type; LBRACK; d=separated_list(COMMA, expr); RBRACK; n=ID; ASSIGN; v=expr; SEMICOL { GlobalDef (e, ArrayDef (t, d), n, Some v, LOC) } fun_header : ret=basic_type; name=ID; LPAREN; params=separated_list(COMMA, param); RPAREN { (ret, name, params) } | VOID; name=ID; LPAREN; params=separated_list(COMMA, param); RPAREN { (Void, name, params) } param : basic_type; ID { Param ($1, $2, LOC) } fun_body : var_dec* local_fun_dec* statement* loption(return_statement) { $1 @ $2 @ $3 @ $4 } local_fun_dec : fun_header; LBRACE; fun_body; RBRACE { let (t, n, p) = $1 in FunDef (false, t, n, p, Block $3, LOC) } var_dec : basic_type; ID; SEMICOL { VarDec ($1, $2, None, LOC) } | basic_type; ID; ASSIGN; expr; SEMICOL { VarDec ($1, $2, Some $4, LOC) } | t=basic_type; LBRACK; d=separated_list(COMMA, expr); RBRACK; n=ID; SEMICOL { VarDec (ArrayDef (t, d), n, None, LOC) } | t=basic_type; LBRACK; d=separated_list(COMMA, expr); RBRACK; n=ID; ASSIGN; v=expr; SEMICOL { VarDec (ArrayDef (t, d), n, Some v, LOC) } statement : ID; ASSIGN; expr; SEMICOL { Assign ($1, $3, LOC) } | name=ID; LPAREN; params=separated_list(COMMA, expr); RPAREN; SEMICOL { Expr (FunCall (name, params, LOC)) } | IF; LPAREN; expr; RPAREN; block { If ($3, Block $5, LOC) } %prec IF | IF; LPAREN; expr; RPAREN; block; ELSE; block { IfElse ($3, Block $5, Block $7, LOC) } %prec ELSE | WHILE; LPAREN; expr; RPAREN; block { While ($3, Block $5, LOC) } | DO; block; WHILE; LPAREN; expr; RPAREN; SEMICOL { DoWhile ($5, Block $2, LOC) } | FOR; LPAREN; INT; id=ID; ASSIGN; start=expr; COMMA; stop=expr; RPAREN; body=block { For (id, start, stop, IntConst (1, noloc), Block body, LOC) } | FOR; LPAREN; INT; id=ID; ASSIGN; start=expr; COMMA; stop=expr; COMMA; step=expr; RPAREN; body=block { For (id, start, stop, step, Block body, LOC) } return_statement : RETURN; expr; SEMICOL { [Return ($2, LOC)] } block : LBRACE; statement*; RBRACE { $2 } | statement { [$1] } expr : LPAREN; expr; RPAREN { $2 } | name=ID; LPAREN; params=separated_list(COMMA, expr); RPAREN { FunCall (name, params, LOC) } | ID { Var ($1, LOC) } | l=expr; op=binop; r=expr { Binop (op, l, r, LOC) } | SUB; expr { Monop (Neg, $2, LOC) } %prec NEG | NOT; expr { Monop (Not, $2, LOC) } | LPAREN; basic_type; RPAREN; expr { TypeCast ($2, $4, LOC) } %prec CAST | FLOAT_CONST { FloatConst ($1, LOC) } | INT_CONST { IntConst ($1, LOC) } | BOOL_CONST { BoolConst ($1, LOC) } | ID; array_const { Deref ($1, $2, LOC) } | array_const { ArrayConst ($1, LOC) } array_const : LBRACK; values=separated_list(COMMA, expr); RBRACK { values } %inline binop : ADD { Add } | SUB { Sub } | MUL { Mul } | DIV { Div } | MOD { Mod } | EQ { Eq } | NE { Ne } | LT { Lt } | LE { Le } | GT { Gt } | GE { Ge } | AND { And } | OR { Or } %%