From 08ea85aa0330e63bf071fbec0b8dfe1cf5838712 Mon Sep 17 00:00:00 2001 From: yui-knk Date: Fri, 8 Sep 2023 18:33:54 +0900 Subject: [PATCH] Support Named References for location --- lib/lrama/lexer.rb | 2 + spec/lrama/integration_spec.rb | 92 ++++++++++++++++++++++++++++++++-- 2 files changed, 90 insertions(+), 4 deletions(-) diff --git a/lib/lrama/lexer.rb b/lib/lrama/lexer.rb index c591684a..d047994a 100644 --- a/lib/lrama/lexer.rb +++ b/lib/lrama/lexer.rb @@ -226,6 +226,8 @@ def lex_user_code(ss, line, column, lines) references << [:at, "$", nil, str.length, str.length + ss[0].length - 1] when ss.scan(/@(\d+)/) # @1 references << [:at, Integer(ss[1]), nil, str.length, str.length + ss[0].length - 1] + when ss.scan(/@([a-zA-Z_.][-a-zA-Z0-9_.]*)/) # @foo, @expr + references << [:at, ss[1], nil, str.length, str.length + ss[0].length - 1] when ss.scan(/{/) brace_count += 1 when ss.scan(/}/) diff --git a/spec/lrama/integration_spec.rb b/spec/lrama/integration_spec.rb index f102a57e..5f83c3db 100644 --- a/spec/lrama/integration_spec.rb +++ b/spec/lrama/integration_spec.rb @@ -212,8 +212,46 @@ def test_rules(rules, input, expected, command_args: [], debug: false) %w[NUM val 2], %w['+'], ] + cases = generate_lexer_body(input) + + test_grammar(<<~Grammar, "expr[left]: 0.0-0.1. expr[right]: 1.0-1.1. line: 0.0-2.1. => 3") + %{ + #include + + #include "test.h" + + typedef struct code_location { + int first_line; + int first_column; + int last_line; + int last_column; + } code_location_t; + + #define YYLTYPE code_location_t + #define YYLLOC_DEFAULT(Current, Rhs, N) \ + do \ + if (N) \ + { \ + (Current).first_line = YYRHSLOC(Rhs, 1).first_line; \ + (Current).first_column = YYRHSLOC(Rhs, 1).first_column; \ + (Current).last_line = YYRHSLOC(Rhs, N).last_line; \ + (Current).last_column = YYRHSLOC(Rhs, N).last_column; \ + } \ + else \ + { \ + (Current).first_line = YYRHSLOC(Rhs, 0).last_line; \ + (Current).first_column = YYRHSLOC(Rhs, 0).last_column; \ + (Current).last_line = YYRHSLOC(Rhs, 0).last_line; \ + (Current).last_column = YYRHSLOC(Rhs, 0).last_column; \ + } \ + while (0) + + static int yylex(YYSTYPE *val, YYLTYPE *loc); + static void print_location(YYLTYPE *loc); + static int yyerror(YYLTYPE *loc, const char *str); + + %} - test_rules(<<~Rules, input, "=> 3") %union { int val; } @@ -223,16 +261,62 @@ def test_rules(rules, input, expected, command_args: [], debug: false) %% line: expr - { (void)yynerrs; printf("=> %d", $expr); } + { + (void)yynerrs; + + printf("line: "); + print_location(&@expr); + + printf("=> %d", $expr); + } ; expr[result]: NUM | expr[left] expr[right] '+' - { $result = $left + $right; } + { + printf("expr[left]: "); + print_location(&@left); + + printf("expr[right]: "); + print_location(&@right); + + $result = $left + $right; + } ; %% - Rules + + int c = 0; + + static int yylex(YYSTYPE *yylval, YYLTYPE *loc) { + loc->first_line = c; + loc->first_column = 0; + loc->last_line = c; + loc->last_column = 1; + + switch (c++) { + #{cases} + default: + // End of Input + return -1; + } + } + + static void print_location(YYLTYPE *loc) { + printf("%d.%d-%d.%d. ", loc->first_line, loc->first_column, loc->last_line, loc->last_column); + } + + static int yyerror(YYLTYPE *loc, const char *str) { + fprintf(stderr, "parse error: %s\\n", str); + return 0; + } + + int main() { + yyparse(); + return 0; + } + + Grammar end end