%{ #include #include #include #include "types.h" #include "ast.h" #include "codegen.h" int yyparse(void); int yylex(void); extern int yylineno; char *yytext; /* XXX */ extern FILE *binout; extern FILE *yyin; void yyerror(const char * str) { fprintf(stderr, "\n%s on line %d before '%s'\n", str, yylineno, yytext); } int yywrap() { return 1; } int main(int argc, char *argv[]) { int rv; argv++; /* skip over program name */ argc--; if (argc > 0) { char *outfile; int len; outfile = strdup(argv[0]); if (outfile == NULL) err(1, "Failed to allocate memory"); len = strlen(outfile); if ((len < 3) || (outfile[len-1] != 's') || (outfile[len-2] != 'l') || (outfile[len-3] != '.')) errx(1, "Can only compile .ls files"); outfile[len-1] = 'c'; yyin = fopen(argv[0], "r"); if (yyin == NULL) err(1, "%s: Failed to open input file", argv[0]); binout = fopen(outfile, "w"); if (binout == NULL) err(1, "%s: Failed to open output file", outfile); free(outfile); } else { yyin = stdin; binout = fopen("out.lc", "w"); if (binout == NULL) err(1, "%s: Failed to open output file", "out.lc"); } rv = yyparse(); fclose(binout); fclose(yyin); return rv; } %} %token TOKFUNCTION TOKFNDEFINT TOKFNDEFINT_V TOKFNDEFEXT TOKCONSTANT %token TOKWHILE TOKIF TOKELSE TOKSWITCH TOKCASE TOKDEFAULT %token TOKBREAK TOKRETURN TOKEQ TOKNE TOKAND TOKOR STRING %union { ast* Tast; ast_list* Tast_list; char * Tstring; long Tinteger; float Treal; } %type argument %type constant %type function %type fndefint %type fndefext %type statement %type fndefint_v %type assignment %type expression %type realconstant %type statement_if %type statement_case %type statement_while %type statement_break %type statement_switch %type statement_return %type statement_default %type stmt_list_inner %type exp_list_inner %type arg_list_inner %type fn_list_inner %type assign_list %type stmt_list %type exp_list %type arg_list %type fn_list %token IDENTIFIER %token STRING %token NUMBER %token REAL %left '+' %left '-' %left '*' %left '/' %left TOKAND %left TOKOR %nonassoc '<' %nonassoc '>' %nonassoc TOKLE %nonassoc TOKGE %nonassoc TOKEQ %nonassoc TOKNE %start start %% start: fn_list { codegen(make_list_node($1)); output_code(); } ; fn_list: fn_list_inner { $$ = reverse_list($1); } ; fn_list_inner: fn_list_inner function { $$ = make_list($2, $1); } | fn_list_inner fndefint { $$ = make_list($2, $1); } | fn_list_inner fndefint_v { $$ = make_list($2, $1); } | fn_list_inner fndefext { $$ = make_list($2, $1); } | fn_list_inner constant { $$ = make_list($2, $1); } | fn_list_inner realconstant { $$ = make_list($2, $1); } | { $$ = NULL; } ; function: TOKFUNCTION IDENTIFIER '(' arg_list ')' '{' stmt_list '}' { $$ = make_function($2, $4, $7); } ; fndefint: TOKFNDEFINT IDENTIFIER NUMBER ';' { $$ = make_fndefint($2, $3); } ; fndefint_v: TOKFNDEFINT_V IDENTIFIER NUMBER ';' { $$ = make_fndefint_v($2, $3); } ; constant: TOKCONSTANT IDENTIFIER NUMBER ';' { $$ = make_constant($2, $3); } ; realconstant: TOKCONSTANT IDENTIFIER REAL ';' { $$ = make_realconstant($2, $3); } ; fndefext: TOKFNDEFEXT IDENTIFIER ';' { $$ = make_fndefext($2); } ; argument: IDENTIFIER { $$ = make_variable($1); } ; arg_list: arg_list_inner { $$ = reverse_list($1); } ; arg_list_inner: arg_list_inner ',' argument { $$ = make_list($3, $1); } | argument { $$ = make_list($1, NULL); } | { $$ = NULL; } ; stmt_list: stmt_list_inner { $$ = reverse_list($1); } ; stmt_list_inner: stmt_list_inner statement { $$ = make_list($2, $1); } | { $$ = NULL; } ; statement: statement_if | statement_while | statement_switch | statement_case | statement_default | statement_break ';' | assignment ';' | expression ';' { $$ = make_assignment(NULL, $1); } | statement_return ';' ; assignment: assign_list '=' expression { $$ = make_assignment($1, $3); } ; assign_list: assign_list ',' IDENTIFIER { $$ = make_list(make_variable($3), $1); } | IDENTIFIER { $$ = make_list(make_variable($1), NULL); } | assign_list ',' IDENTIFIER '[' expression ']' { $$ = make_list(make_array($3, $5), $1); } | IDENTIFIER '[' expression ']' { $$ = make_list(make_array($1, $3), NULL); } ; expression: expression '+' expression { $$ = make_binary_op(op_plus, $1, $3); } | expression '-' expression { $$ = make_binary_op(op_minus, $1, $3); } | expression '*' expression { $$ = make_binary_op(op_times, $1, $3); } | expression '/' expression { $$ = make_binary_op(op_divide, $1, $3); } | expression '<' expression { $$ = make_binary_op(op_lt, $1, $3); } | expression '>' expression { $$ = make_binary_op(op_gt, $1, $3); } | expression TOKLE expression { $$ = make_binary_op(op_le, $1, $3); } | expression TOKGE expression { $$ = make_binary_op(op_ge, $1, $3); } | expression TOKEQ expression { $$ = make_binary_op(op_eq, $1, $3); } | expression TOKNE expression { $$ = make_binary_op(op_ne, $1, $3); } | expression TOKAND expression { $$ = make_binary_op(op_and, $1, $3); } | expression TOKOR expression { $$ = make_binary_op(op_or, $1, $3); } | '-' expression { $$ = make_unary_op(op_minus, $2); } | '(' expression ')' { $$ = $2; } | IDENTIFIER '(' exp_list ')' { $$ = make_call($1, $3); } | IDENTIFIER '[' expression ']' { $$ = make_array($1, $3); } | IDENTIFIER { $$ = make_variable($1); } | NUMBER { $$ = make_integer($1); } | REAL { $$ = make_real($1); } | STRING { $$ = make_string($1); } ; exp_list: exp_list_inner { $$ = reverse_list($1); } ; exp_list_inner: exp_list_inner ',' expression { $$ = make_list($3, $1); } | expression { $$ = make_list($1, NULL); } | { $$ = NULL; } ; statement_if: TOKIF '(' expression ')' '{' stmt_list '}' { $$ = make_statement(stmt_if, $3, $6, NULL); } | TOKIF '(' expression ')' '{' stmt_list '}' TOKELSE '{' stmt_list '}' { $$ = make_statement(stmt_if, $3, $6, $10); } ; statement_while: TOKWHILE '(' expression ')' '{' stmt_list '}' { $$ = make_statement(stmt_while, $3, $6, NULL); } ; statement_switch: TOKSWITCH '(' expression ')' '{' stmt_list '}' { $$ = make_statement(stmt_switch, $3, $6, NULL); } ; statement_case: TOKCASE NUMBER ':' { $$ = make_case_statement_number($2); } | TOKCASE IDENTIFIER ':' { $$ = make_case_statement_variable($2); } ; statement_return: TOKRETURN expression { $$ = make_return_statement($2); } | TOKRETURN { $$ = make_return_statement(NULL); } ; statement_break: TOKBREAK { $$ = make_break_statement(); } ; statement_default: TOKDEFAULT ':' { $$ = make_default_statement(); } ;