%{ #include #define NODE(type, data, n_children, children...) node_init(malloc(sizeof(node_t)), type, data, n_children, ##children) %} %define api.value.type {node_t} %token FUNC PRINT RETURN CONTINUE IF THEN ELSE WHILE DO OPENBLOCK CLOSEBLOCK %token VAR NUMBER IDENTIFIER STRING %left '|' '&' '^' %left '+' '-' %left '*' '/' %nonassoc UMINUS %right '~' //%expect 1 %nonassoc IF THEN %nonassoc ELSE /* Tried fixing vscode complaining about the type for the non-terminals, didn't work %union { node_t* node; } %type global_list global %type statement_list print_list expression_list variable_list argument_list parameter_list declaration_list %type function statement block %type assignment_statement return_statement print_statement null_statement if_statement while_statement %type relation expression declaration print_item identifier number string */ %% program: global_list { root = NODE(PROGRAM, NULL, 1, $1); } ; global_list: global { $$ = NODE(GLOBAL_LIST, NULL, 1, $1); } | global_list global { $$ = NODE(GLOBAL_LIST, NULL, 2, $1, $2); } ; global: function { $$ = NODE(GLOBAL, NULL, 1, $1); } | declaration { $$ = NODE(GLOBAL, NULL, 1, $1); } ; statement_list: statement { $$ = NODE(STATEMENT_LIST, NULL, 1, $1); } | statement_list statement { $$ = NODE(STATEMENT_LIST, NULL, 2, $1, $2); } ; print_list: print_item { $$ = NODE(PRINT_LIST, NULL, 1, $1); } | print_list ',' print_item { $$ = NODE(PRINT_LIST, NULL, 2, $1, $3); } ; expression_list: expression { $$ = NODE(EXPRESSION_LIST, NULL, 1, $1); } | expression_list ',' expression { $$ = NODE(EXPRESSION_LIST, NULL, 2, $1, $3); } ; variable_list: identifier { $$ = NODE(VARIABLE_LIST, NULL, 1, $1); } | variable_list ',' identifier { $$ = NODE(VARIABLE_LIST, NULL, 2, $1, $3); } ; argument_list: expression_list { $$ = NODE(ARGUMENT_LIST, NULL, 1, $1); } | /* epsilon */ { $$ = NODE(ARGUMENT_LIST, NULL, 0); } ; parameter_list: variable_list { $$ = NODE(PARAMETER_LIST, NULL, 1, $1); } | /* epsilon */ { $$ = NODE(PARAMETER_LIST, NULL, 0); } ; declaration_list: declaration { $$ = NODE(DECLARATION_LIST, NULL, 1, $1); } | declaration_list declaration { $$ = NODE(DECLARATION_LIST, NULL, 2, $1, $2); } ; function: FUNC identifier '(' parameter_list ')' statement { $$ = NODE(FUNCTION, NULL, 3, $2, $4, $6); } ; statement: assignment_statement { $$ = NODE(STATEMENT, NULL, 1, $1); } | return_statement { $$ = NODE(STATEMENT, NULL, 1, $1); } | print_statement { $$ = NODE(STATEMENT, NULL, 1, $1); } | if_statement { $$ = NODE(STATEMENT, NULL, 1, $1); } | while_statement { $$ = NODE(STATEMENT, NULL, 1, $1); } | null_statement { $$ = NODE(STATEMENT, NULL, 1, $1); } | block { $$ = NODE(STATEMENT, NULL, 1, $1); } ; block: OPENBLOCK declaration_list statement_list CLOSEBLOCK { $$ = NODE(BLOCK, NULL, 2, $2, $3); } | OPENBLOCK statement_list CLOSEBLOCK { $$ = NODE(BLOCK, NULL, 1, $2); } ; assignment_statement: identifier ':' '=' expression { $$ = NODE(ASSIGNMENT_STATEMENT, NULL, 2, $1, $4); } | identifier '+' '=' expression { $$ = NODE(ADD_STATEMENT, NULL, 2, $1, $4); } | identifier '-' '=' expression { $$ = NODE(SUBTRACT_STATEMENT, NULL, 2, $1, $4); } | identifier '*' '=' expression { $$ = NODE(MULTIPLY_STATEMENT, NULL, 2, $1, $4); } | identifier '/' '=' expression { $$ = NODE(DIVIDE_STATEMENT, NULL, 2, $1, $4); } ; return_statement: RETURN expression { $$ = NODE(RETURN_STATEMENT, NULL, 1, $2); } ; print_statement: PRINT print_list { $$ = NODE(PRINT_STATEMENT, NULL, 1, $2); } ; null_statement: CONTINUE { $$ = NODE(NULL_STATEMENT, NULL, 0); } ; if_statement: IF relation THEN statement { $$ = NODE(IF_STATEMENT, NULL, 2, $2, $4); } | IF relation THEN statement ELSE statement { $$ = NODE(IF_STATEMENT, NULL, 3, $2, $4, $6); } ; while_statement: WHILE relation DO statement { $$ = NODE(WHILE_STATEMENT, NULL, 2, $2, $4); } ; relation: expression '=' expression { $$ = NODE(RELATION, strdup("="), 2, $1, $3); } | expression '<' expression { $$ = NODE(RELATION, strdup("<"), 2, $1, $3); } | expression '>' expression { $$ = NODE(RELATION, strdup(">"), 2, $1, $3); } /* This can actually be extented with the following (with some minor tweaks to the generator.c) | expression { $$ = NODE(RELATION, NULL, 1, $1); } That will allow to have "if 1 then" or "while 1 do" */ ; expression: expression '|' expression { $$ = NODE(EXPRESSION, strdup("|"), 2, $1, $3); } | expression '^' expression { $$ = NODE(EXPRESSION, strdup("^"), 2, $1, $3); } | expression '&' expression { $$ = NODE(EXPRESSION, strdup("&"), 2, $1, $3); } | expression '+' expression { $$ = NODE(EXPRESSION, strdup("+"), 2, $1, $3); } | expression '-' expression { $$ = NODE(EXPRESSION, strdup("-"), 2, $1, $3); } | expression '*' expression { $$ = NODE(EXPRESSION, strdup("*"), 2, $1, $3); } | expression '/' expression { $$ = NODE(EXPRESSION, strdup("/"), 2, $1, $3); } | '-' expression %prec UMINUS { $$ = NODE(EXPRESSION, strdup("-"), 1, $2); } | '~' expression { $$ = NODE(EXPRESSION, strdup("~"), 1, $2); } | '(' expression ')' { $$ = NODE(EXPRESSION, NULL /*strdup("group")*/, 1, $2); } | number { $$ = NODE(EXPRESSION, NULL /*strdup("number")*/, 1, $1); } | identifier { $$ = NODE(EXPRESSION, NULL /*strdup("identifier")*/, 1, $1); } | identifier '(' argument_list ')' { $$ = NODE(EXPRESSION, /*NULL*/ strdup("function_call"), 2, $1, $3); } ; declaration: VAR variable_list { $$ = NODE(DECLARATION, NULL, 1, $2); } ; print_item: expression { $$ = NODE(PRINT_ITEM, NULL, 1, $1); } | string { $$ = NODE(PRINT_ITEM, NULL, 1, $1); } ; identifier: IDENTIFIER { $$ = NODE(IDENTIFIER_DATA, strdup(yytext), 0); // Zero children } ; number: NUMBER { uint64_t* p_number = malloc(sizeof(uint64_t)); *p_number = strtol(yytext, NULL, 10); $$ = NODE(NUMBER_DATA, p_number, 0); // Zero children } ; string: STRING { $$ = NODE(STRING_DATA, strdup(yytext), 0); // Zero children } ; %% int yyerror ( const char *error ) { fprintf ( stderr, "%s on line %d\n", error, yylineno ); exit ( EXIT_FAILURE ); }