%{ #include "ast.h" #include "lexer.h" #include #include struct Node* program_root = NULL; void yyerror(const char* message); %} %union { char character; struct Name name; struct Node* node; } %token TOK_COLONCOLON %token TOK_EMIT %token TOK_STATIC_ASSERT %token TOK_COMMIT %token TOK_DECLARE %token TOK_UNDECLARE %token TOK_ENABLE_IF %token TOK_REPEAT %token TOK_DEFINE %token TOK_PARAMETERS %token TOK_RETURN %token TOK_INVOKE_RESULT %token TOK_ARGUMENTS %token TOK_SEQUENCE %token TOK_NAME %token TOK_VALUE_OF %token TOK_DECLVAL %token TOK_VOID %token TOK_INT32 %token TOK_BYTE %token TOK_SIZE_T %token TOK_CHAR_T %token TOK_TUPLE %token TOK_REMOVE_CV %token TOK_DECLTYPE %token TOK_DIFFERENCE %token TOK_SUM %token TOK_PRODUCT %token TOK_QUOTIENT %token TOK_ARRAY %token TOK_EXTENT %token TOK_TUPLE_SIZE %token TOK_INTEGRAL_CONSTANT %token TOK_VALUE %token TOK_CONDITIONAL_T %token TOK_CONDITIONAL %token TOK_TRUE_TYPE %token TOK_FALSE_TYPE %token TOK_IS_SAME %token TOK_EQUAL %token TOK_LESS %token TOK_CHAR %type name char_list %type statements statement sequence sequence_items parameters name_list %type type type_list value condition %% program : statements { program_root = $1; } ; statements : /* nothing */ { $$ = NULL; } | statements statement ';' { $$ = node_append($1, $2); } ; statement : TOK_COLONCOLON TOK_EMIT '<' type '>' TOK_COLONCOLON TOK_COMMIT { $$ = node_unary(STMT_EMIT, $4); } | TOK_COLONCOLON TOK_STATIC_ASSERT '<' condition '>' TOK_COLONCOLON TOK_COMMIT { $$ = node_unary(STMT_STATIC_ASSERT, $4); } | TOK_COLONCOLON TOK_DECLARE '<' name ',' type '>' TOK_COLONCOLON TOK_COMMIT { $$ = node_named(STMT_DECLARE, &$4, $6); } | TOK_COLONCOLON TOK_UNDECLARE '<' name '>' TOK_COLONCOLON TOK_COMMIT { $$ = node_named(STMT_UNDECLARE, &$4, NULL); } | TOK_COLONCOLON TOK_ENABLE_IF '<' condition ',' sequence '>' TOK_COLONCOLON TOK_COMMIT { $$ = node_block(STMT_ENABLE_IF, $4, $6); } | TOK_COLONCOLON TOK_REPEAT '<' value ',' sequence '>' TOK_COLONCOLON TOK_COMMIT { $$ = node_block(STMT_REPEAT, $4, $6); } | TOK_COLONCOLON TOK_DEFINE '<' name ',' parameters ',' sequence '>' TOK_COLONCOLON TOK_COMMIT { $$ = node_named(STMT_DEFINE, &$4, $6); $$->body = $8; } | TOK_COLONCOLON TOK_RETURN '<' type '>' TOK_COLONCOLON TOK_COMMIT { $$ = node_unary(STMT_RETURN, $4); } ; sequence : TOK_COLONCOLON TOK_SEQUENCE '<' sequence_items '>' { $$ = $4; } ; sequence_items : /* nothing */ { $$ = NULL; } | statement { $$ = $1; } | sequence_items ',' statement { $$ = node_append($1, $3); } ; parameters : TOK_COLONCOLON TOK_PARAMETERS '<' name_list '>' { $$ = $4; } ; name_list : /* nothing */ { $$ = NULL; } | name { $$ = node_named(NODE_PARAMETER, &$1, NULL); } | name_list ',' name { $$ = node_append($1, node_named(NODE_PARAMETER, &$3, NULL)); } ; name : TOK_COLONCOLON TOK_NAME '<' char_list '>' { $$ = $4; } ; char_list : TOK_CHAR { name_init(&$$); (void)name_push(&$$, $1); } | char_list ',' TOK_CHAR { $$ = $1; if (!name_push(&$$, $3)) { yyerror("that name is too long, who are you"); YYERROR; } } ; type : TOK_COLONCOLON TOK_VOID { $$ = node_leaf(TYPE_VOID); } | TOK_COLONCOLON TOK_INT32 { $$ = node_leaf(TYPE_INT32); } | TOK_COLONCOLON TOK_BYTE { $$ = node_leaf(TYPE_BYTE); } | TOK_COLONCOLON TOK_SIZE_T { $$ = node_leaf(TYPE_SIZE); } | TOK_COLONCOLON TOK_REMOVE_CV '<' type '>' { $$ = node_unary(TYPE_REMOVE_CV, $4); } | TOK_COLONCOLON TOK_ARRAY '<' type ',' value '>' { $$ = node_binary(TYPE_ARRAY, $4, $6); } | TOK_COLONCOLON TOK_CONDITIONAL_T '<' condition ',' type ',' type '>' { $$ = node_ternary(TYPE_CONDITIONAL, $4, $6, $8); } | TOK_COLONCOLON TOK_DECLTYPE '(' value ')' { $$ = node_unary(TYPE_DECLTYPE, $4); } | TOK_COLONCOLON TOK_CHAR_T { $$ = node_leaf(TYPE_CHAR); } | TOK_COLONCOLON TOK_INTEGRAL_CONSTANT '<' TOK_COLONCOLON TOK_CHAR_T ',' value '>' { $$ = node_unary(TYPE_CHAR_CONSTANT, $7); } | TOK_COLONCOLON TOK_TUPLE '<' type_list '>' { $$ = node_unary(TYPE_TUPLE, $4); } | TOK_COLONCOLON TOK_INVOKE_RESULT '<' name ',' TOK_COLONCOLON TOK_ARGUMENTS '<' type_list '>' '>' { $$ = node_named(TYPE_INVOKE, &$4, $9); } ; type_list : /* nothing */ { $$ = NULL; } | type { $$ = $1; } | type_list ',' type { $$ = node_append($1, $3); } ; value : TOK_COLONCOLON TOK_DIFFERENCE '<' TOK_CHAR ',' TOK_CHAR '>' { $$ = node_binary(VALUE_DIFFERENCE, node_char($4), node_char($6)); } | TOK_COLONCOLON TOK_SUM '<' value ',' value '>' { $$ = node_binary(VALUE_SUM, $4, $6); } | TOK_COLONCOLON TOK_PRODUCT '<' value ',' value '>' { $$ = node_binary(VALUE_PRODUCT, $4, $6); } | TOK_COLONCOLON TOK_QUOTIENT '<' value ',' value '>' { $$ = node_binary(VALUE_QUOTIENT, $4, $6); } | TOK_COLONCOLON TOK_VALUE_OF '<' name '>' { $$ = node_named(VALUE_VARIABLE, &$4, NULL); } | TOK_COLONCOLON TOK_DECLVAL '<' type '>' '(' ')' { $$ = node_unary(VALUE_DECLVAL, $4); } | TOK_COLONCOLON TOK_EXTENT '<' type '>' TOK_COLONCOLON TOK_VALUE { $$ = node_unary(VALUE_EXTENT, $4); } | TOK_COLONCOLON TOK_TUPLE_SIZE '<' type '>' TOK_COLONCOLON TOK_VALUE { $$ = node_unary(VALUE_TUPLE_SIZE, $4); } | TOK_COLONCOLON TOK_INTEGRAL_CONSTANT '<' TOK_COLONCOLON TOK_SIZE_T ',' value '>' TOK_COLONCOLON TOK_VALUE { $$ = node_unary(VALUE_INTEGRAL_CONSTANT, $7); } | TOK_COLONCOLON TOK_CONDITIONAL '<' condition ',' value ',' value '>' { $$ = node_ternary(VALUE_CONDITIONAL, $4, $6, $8); } ; condition : TOK_COLONCOLON TOK_TRUE_TYPE TOK_COLONCOLON TOK_VALUE { $$ = node_leaf(COND_TRUE); } | TOK_COLONCOLON TOK_FALSE_TYPE TOK_COLONCOLON TOK_VALUE { $$ = node_leaf(COND_FALSE); } | TOK_COLONCOLON TOK_IS_SAME '<' type ',' type '>' TOK_COLONCOLON TOK_VALUE { $$ = node_binary(COND_IS_SAME, $4, $6); } | TOK_COLONCOLON TOK_EQUAL '<' value ',' value '>' TOK_COLONCOLON TOK_VALUE { $$ = node_binary(COND_EQUAL, $4, $6); } | TOK_COLONCOLON TOK_LESS '<' value ',' value '>' TOK_COLONCOLON TOK_VALUE { $$ = node_binary(COND_LESS, $4, $6); } ; %% void yyerror(const char* message) { if (!lexer_failed()) { (void)fprintf(stderr, "line %d: %s%s\n", yylineno, message, strcmp(message, "syntax error") == 0 ? ", did you forget to commit" : ""); } }