diff --git a/lib/lrama/command.rb b/lib/lrama/command.rb index 17aad1a1..db5dcd8f 100644 --- a/lib/lrama/command.rb +++ b/lib/lrama/command.rb @@ -74,6 +74,19 @@ def merge_stdlib(grammar) ).parse grammar.prepend_parameterized_rules(stdlib_grammar.parameterized_rules) + + if stdlib_grammar.aux.prologue + if grammar.aux.prologue + grammar.aux.prologue = stdlib_grammar.aux.prologue + "\n" + grammar.aux.prologue + else + grammar.aux.prologue = stdlib_grammar.aux.prologue + grammar.aux.prologue_first_lineno = stdlib_grammar.aux.prologue_first_lineno + end + end + + stdlib_grammar.percent_codes.each do |percent_code| + grammar.percent_codes.unshift(percent_code) + end end def prepare_grammar(grammar) diff --git a/lib/lrama/grammar/stdlib.y b/lib/lrama/grammar/stdlib.y index dd397c9e..2dd218a0 100644 --- a/lib/lrama/grammar/stdlib.y +++ b/lib/lrama/grammar/stdlib.y @@ -8,6 +8,92 @@ **********************************************************************/ +%code requires { +#ifndef LRAMA_STDLIB_LIST_H +#define LRAMA_STDLIB_LIST_H + +#include +#include + +typedef struct lrama_list_node { + void *val; + struct lrama_list_node *next; +} lrama_list_node_t; + +/* Create a new list node with a single value */ +__attribute__((unused)) +static lrama_list_node_t* lrama_list_new(void *val) { + lrama_list_node_t *node = (lrama_list_node_t*)malloc(sizeof(lrama_list_node_t)); + if (node == NULL) { + return NULL; + } + node->val = val; + node->next = NULL; + return node; +} + +/* Append a value to the end of the list */ +__attribute__((unused)) +static lrama_list_node_t* lrama_list_append(lrama_list_node_t *list, void *val) { + lrama_list_node_t *new_node = lrama_list_new(val); + if (new_node == NULL) { + return list; + } + + if (list == NULL) { + return new_node; + } + + lrama_list_node_t *current = list; + while (current->next != NULL) { + current = current->next; + } + current->next = new_node; + return list; +} + +/* Free all nodes in the list (does not free the values themselves) */ +__attribute__((unused)) +static void lrama_list_free(lrama_list_node_t *list) { + lrama_list_node_t *current = list; + while (current != NULL) { + lrama_list_node_t *next = current->next; + free(current); + current = next; + } +} + +/* Count the number of elements in the list */ +__attribute__((unused)) +static size_t lrama_list_length(const lrama_list_node_t *list) { + size_t count = 0; + const lrama_list_node_t *current = list; + while (current != NULL) { + count++; + current = current->next; + } + return count; +} + +/* Get the nth element (0-indexed), returns NULL if out of bounds */ +__attribute__((unused)) +static void* lrama_list_get(const lrama_list_node_t *list, size_t index) { + const lrama_list_node_t *current = list; + size_t i = 0; + while (current != NULL) { + if (i == index) { + return current->val; + } + i++; + current = current->next; + } + return NULL; +} + +#endif /* LRAMA_STDLIB_LIST_H */ + +} + %% // ------------------------------------------------------------------- @@ -94,7 +180,7 @@ */ %rule list(X) : /* empty */ - | list(X) X + | list(X) X { $$ = lrama_list_append($1, (void*)$2); } ; /* @@ -107,8 +193,8 @@ * nonempty_list_X: nonempty_list_X X */ %rule nonempty_list(X) - : X - | nonempty_list(X) X + : X { $$ = lrama_list_new((void*)$1); } + | nonempty_list(X) X { $$ = lrama_list_append($1, (void*)$2); } ; /* @@ -121,8 +207,8 @@ * separated_nonempty_list_separator_X: separated_nonempty_list_separator_X separator X */ %rule separated_nonempty_list(separator, X) - : X - | separated_nonempty_list(separator, X) separator X + : X { $$ = lrama_list_new((void*)$1); } + | separated_nonempty_list(separator, X) separator X { $$ = lrama_list_append($1, (void*)$3); } ; /* @@ -131,12 +217,12 @@ * => * * program: separated_list_separator_X - * separated_list_separator_X: option_separated_nonempty_list_separator_X - * option_separated_nonempty_list_separator_X: %empty - * option_separated_nonempty_list_separator_X: separated_nonempty_list_separator_X - * separated_nonempty_list_separator_X: X - * separated_nonempty_list_separator_X: separator separated_nonempty_list_separator_X X + * separated_list_separator_X: %empty + * separated_list_separator_X: X + * separated_list_separator_X: separated_list_separator_X separator X */ %rule separated_list(separator, X) - : option(separated_nonempty_list(separator, X)) + : /* empty */ + | X { $$ = lrama_list_new((void*)$1); } + | separated_list(separator, X) separator X { $$ = lrama_list_append($1, (void*)$3); } ; diff --git a/spec/fixtures/integration/parameterized.y b/spec/fixtures/integration/parameterized.y index f2627962..752cf188 100644 --- a/spec/fixtures/integration/parameterized.y +++ b/spec/fixtures/integration/parameterized.y @@ -3,6 +3,7 @@ #define YYDEBUG 1 #include +#include #include "parameterized.h" #include "parameterized-lexer.h" @@ -16,25 +17,32 @@ static int yyerror(YYLTYPE *loc, const char *str); %union { int num; char* str; + void* ptr; + lrama_list_node_t* list; } %token ODD EVEN %type stmt +%type stmt_wrapped %type opt_nl +%type stmts %locations %% -program: stmts +program: stmts { lrama_list_free($1);} ; -stmts: stmt+ +stmts: stmt_wrapped+ { $$ = $1; } ; -stmt: ODD opt_nl { printf("odd: %d\n", $1); } - | EVEN opt_semicolon { printf("even: %d\n", $1); } +stmt_wrapped: stmt { $$ = (void*)(intptr_t)$1; } + ; + +stmt: ODD opt_nl { printf("odd: %d\n", $1); $$ = $1; } + | EVEN opt_semicolon { printf("even: %d\n", $1); $$ = $1; } ; opt_nl: '\n'?[nl] { $$ = $nl; } diff --git a/spec/fixtures/integration/user_defined_parameterized.y b/spec/fixtures/integration/user_defined_parameterized.y index 190c59e7..cc6f8e21 100644 --- a/spec/fixtures/integration/user_defined_parameterized.y +++ b/spec/fixtures/integration/user_defined_parameterized.y @@ -3,6 +3,7 @@ #define YYDEBUG 1 #include +#include #include "user_defined_parameterized.h" #include "user_defined_parameterized-lexer.h" @@ -15,11 +16,15 @@ static int yyerror(YYLTYPE *loc, const char *str); %union { int num; + void* ptr; + lrama_list_node_t* list; } %token ODD EVEN %type stmt +%type stmt_wrapped +%type stmts %rule pair(X, Y): X Y { @@ -34,14 +39,17 @@ static int yyerror(YYLTYPE *loc, const char *str); %% -program: stmts +program: stmts { lrama_list_free($1);} ; -stmts: separated_list(';', stmt) +stmts: separated_list(';', stmt_wrapped) { $$ = $1; } ; -stmt: pair(ODD, EVEN) { printf("pair odd even: %d\n", $1); } - | pair(EVEN, ODD)[result] { printf("pair even odd: %d\n", $result); } +stmt_wrapped: stmt { $$ = (void*)(intptr_t)$1; } + ; + +stmt: pair(ODD, EVEN) { printf("pair odd even: %d\n", $1); $$ = $1; } + | pair(EVEN, ODD)[result] { printf("pair even odd: %d\n", $result); $$ = $result; } ; %% diff --git a/spec/lrama/parser_spec.rb b/spec/lrama/parser_spec.rb index 9b2365ab..4bc45a2b 100644 --- a/spec/lrama/parser_spec.rb +++ b/spec/lrama/parser_spec.rb @@ -1474,7 +1474,7 @@ rhs: [ grammar.find_symbol_by_s_value!("number"), ], - token_code: nil, + token_code: Lrama::Lexer::Token::UserCode.new(s_value: " $$ = lrama_list_new((void*)$1); "), nullable: false, precedence_sym: grammar.find_symbol_by_s_value!("number"), lineno: 20, @@ -1486,7 +1486,7 @@ grammar.find_symbol_by_s_value!("nonempty_list_number"), grammar.find_symbol_by_s_value!("number"), ], - token_code: nil, + token_code: Lrama::Lexer::Token::UserCode.new(s_value: " $$ = lrama_list_append($1, (void*)$2); "), nullable: false, precedence_sym: grammar.find_symbol_by_s_value!("number"), lineno: 20, @@ -1508,6 +1508,7 @@ rhs: [ grammar.find_symbol_by_s_value!("number_alias"), ], + token_code: Lrama::Lexer::Token::UserCode.new(s_value: " $$ = lrama_list_new((void*)$1); "), nullable: false, precedence_sym: grammar.find_symbol_by_s_value!("number_alias"), lineno: 23, @@ -1519,6 +1520,7 @@ grammar.find_symbol_by_s_value!("nonempty_list_number_alias"), grammar.find_symbol_by_s_value!("number_alias"), ], + token_code: Lrama::Lexer::Token::UserCode.new(s_value: " $$ = lrama_list_append($1, (void*)$2); "), nullable: false, precedence_sym: grammar.find_symbol_by_s_value!("number_alias"), lineno: 23, @@ -1578,7 +1580,7 @@ grammar.find_symbol_by_s_value!("list_number"), grammar.find_symbol_by_s_value!("number"), ], - token_code: nil, + token_code: Lrama::Lexer::Token::UserCode.new(s_value: " $$ = lrama_list_append($1, (void*)$2); "), nullable: false, precedence_sym: grammar.find_symbol_by_s_value!("number"), lineno: 20, @@ -1609,6 +1611,7 @@ grammar.find_symbol_by_s_value!("list_number_alias"), grammar.find_symbol_by_s_value!("number_alias"), ], + token_code: Lrama::Lexer::Token::UserCode.new(s_value: " $$ = lrama_list_append($1, (void*)$2); "), nullable: false, precedence_sym: grammar.find_symbol_by_s_value!("number_alias"), lineno: 23, @@ -1656,7 +1659,7 @@ rhs: [ grammar.find_symbol_by_s_value!("number"), ], - token_code: nil, + token_code: Lrama::Lexer::Token::UserCode.new(s_value: " $$ = lrama_list_new((void*)$1); "), nullable: false, precedence_sym: grammar.find_symbol_by_s_value!("number"), lineno: 19, @@ -1669,7 +1672,7 @@ grammar.find_symbol_by_number!(4), grammar.find_symbol_by_s_value!("number"), ], - token_code: nil, + token_code: Lrama::Lexer::Token::UserCode.new(s_value: " $$ = lrama_list_append($1, (void*)$3); "), nullable: false, precedence_sym: grammar.find_symbol_by_s_value!("number"), lineno: 19, @@ -1695,10 +1698,8 @@ it "expands parameterized rules" do expect(grammar.nterms.sort_by(&:number)).to match_symbols([ Sym.new(id: T::Ident.new(s_value: "$accept"), alias_name: nil, number: 5, tag: nil, term: false, token_id: 0, nullable: false), - Sym.new(id: T::Ident.new(s_value: "option_separated_nonempty_list_','_number"), alias_name: nil, number: 6, tag: nil, term: false, token_id: 1, nullable: true), - Sym.new(id: T::Ident.new(s_value: "separated_nonempty_list_','_number"), alias_name: nil, number: 7, tag: nil, term: false, token_id: 2, nullable: false), - Sym.new(id: T::Ident.new(s_value: "separated_list_','_number"), alias_name: nil, number: 8, tag: nil, term: false, token_id: 3, nullable: true), - Sym.new(id: T::Ident.new(s_value: "program"), alias_name: nil, number: 9, tag: nil, term: false, token_id: 4, nullable: true), + Sym.new(id: T::Ident.new(s_value: "separated_list_','_number"), alias_name: nil, number: 6, tag: nil, term: false, token_id: 1, nullable: true), + Sym.new(id: T::Ident.new(s_value: "program"), alias_name: nil, number: 7, tag: nil, term: false, token_id: 2, nullable: true), ]) expect(grammar.rules).to eq([ @@ -1716,7 +1717,7 @@ ), Rule.new( id: 1, - lhs: grammar.find_symbol_by_s_value!("option_separated_nonempty_list_','_number"), + lhs: grammar.find_symbol_by_s_value!("separated_list_','_number"), rhs: [], token_code: nil, nullable: true, @@ -1725,52 +1726,30 @@ ), Rule.new( id: 2, - lhs: grammar.find_symbol_by_s_value!("separated_nonempty_list_','_number"), + lhs: grammar.find_symbol_by_s_value!("separated_list_','_number"), rhs: [ grammar.find_symbol_by_s_value!("number"), ], - token_code: nil, + token_code: Lrama::Lexer::Token::UserCode.new(s_value: " $$ = lrama_list_new((void*)$1); "), nullable: false, precedence_sym: grammar.find_symbol_by_s_value!("number"), lineno: 19, ), Rule.new( id: 3, - lhs: grammar.find_symbol_by_s_value!("separated_nonempty_list_','_number"), + lhs: grammar.find_symbol_by_s_value!("separated_list_','_number"), rhs: [ - grammar.find_symbol_by_s_value!("separated_nonempty_list_','_number"), + grammar.find_symbol_by_s_value!("separated_list_','_number"), grammar.find_symbol_by_number!(4), grammar.find_symbol_by_s_value!("number"), ], - token_code: nil, + token_code: Lrama::Lexer::Token::UserCode.new(s_value: " $$ = lrama_list_append($1, (void*)$3); "), nullable: false, precedence_sym: grammar.find_symbol_by_s_value!("number"), lineno: 19, ), Rule.new( id: 4, - lhs: grammar.find_symbol_by_s_value!("option_separated_nonempty_list_','_number"), - rhs: [ - grammar.find_symbol_by_s_value!("separated_nonempty_list_','_number"), - ], - token_code: nil, - nullable: false, - precedence_sym: nil, - lineno: 19, - ), - Rule.new( - id: 5, - lhs: grammar.find_symbol_by_s_value!("separated_list_','_number"), - rhs: [ - grammar.find_symbol_by_s_value!("option_separated_nonempty_list_','_number"), - ], - token_code: nil, - nullable: true, - precedence_sym: nil, - lineno: 19, - ), - Rule.new( - id: 6, lhs: grammar.find_symbol_by_s_value!("program"), rhs: [ grammar.find_symbol_by_s_value!("separated_list_','_number"), @@ -2406,7 +2385,7 @@ rhs: [ grammar.find_symbol_by_s_value!("' '") ], - token_code: nil, + token_code: Lrama::Lexer::Token::UserCode.new(s_value: " $$ = lrama_list_new((void*)$1); "), nullable: false, precedence_sym: grammar.find_symbol_by_s_value!("' '"), lineno: 23, @@ -2418,7 +2397,7 @@ grammar.find_symbol_by_s_value!("nonempty_list_' '"), grammar.find_symbol_by_s_value!("' '") ], - token_code: nil, + token_code: Lrama::Lexer::Token::UserCode.new(s_value: " $$ = lrama_list_append($1, (void*)$2); "), nullable: false, precedence_sym: grammar.find_symbol_by_s_value!("' '"), lineno: 23,