Skip to content

Commit c504583

Browse files
committed
Lrama v0.6.4
1 parent b4d73e9 commit c504583

17 files changed

+340
-107
lines changed

tool/lrama/NEWS.md

+67-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,69 @@
11
# NEWS for Lrama
22

3+
## Lrama 0.6.4 (2024-03-22)
4+
5+
### Parameterizing rules (preceded, terminated, delimited)
6+
7+
Support `preceded`, `terminated` and `delimited` rules.
8+
9+
```
10+
program: preceded(opening, X)
11+
12+
// Expanded to
13+
14+
program: preceded_opening_X
15+
preceded_opening_X: opening X
16+
```
17+
18+
```
19+
program: terminated(X, closing)
20+
21+
// Expanded to
22+
23+
program: terminated_X_closing
24+
terminated_X_closing: X closing
25+
```
26+
27+
```
28+
program: delimited(opening, X, closing)
29+
30+
// Expanded to
31+
32+
program: delimited_opening_X_closing
33+
delimited_opening_X_closing: opening X closing
34+
```
35+
36+
https://github.com/ruby/lrama/pull/382
37+
38+
### Support `%destructor` declaration
39+
40+
User can set codes for freeing semantic value resources by using `%destructor`.
41+
In general, these resources are freed by actions or after parsing.
42+
However if syntax error happens in parsing, these codes may not be executed.
43+
Codes associated to `%destructor` are executed when semantic value is popped from the stack by an error.
44+
45+
```
46+
%token <val1> NUM
47+
%type <val2> expr2
48+
%type <val3> expr
49+
50+
%destructor {
51+
printf("destructor for val1: %d\n", $$);
52+
} <val1> // printer for TAG
53+
54+
%destructor {
55+
printf("destructor for val2: %d\n", $$);
56+
} <val2>
57+
58+
%destructor {
59+
printf("destructor for expr: %d\n", $$);
60+
} expr // printer for symbol
61+
```
62+
63+
Bison supports this feature from 1.75b.
64+
65+
https://github.com/ruby/lrama/pull/385
66+
367
## Lrama 0.6.3 (2024-02-15)
468

569
### Bring Your Own Stack
@@ -34,6 +98,8 @@ primary: k_if expr_value then compstmt if_tail k_end
3498
}
3599
```
36100

101+
https://github.com/ruby/lrama/pull/367
102+
37103
## Lrama 0.6.2 (2024-01-27)
38104

39105
### %no-stdlib directive
@@ -51,7 +117,7 @@ Allow to pass an instantiated rule to other parameterizing rules.
51117

52118
```
53119
%rule constant(X) : X
54-
;
120+
;
55121
56122
%rule option(Y) : /* empty */
57123
| Y

tool/lrama/lib/lrama/grammar.rb

+8-1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
require "lrama/grammar/binding"
44
require "lrama/grammar/code"
55
require "lrama/grammar/counter"
6+
require "lrama/grammar/destructor"
67
require "lrama/grammar/error_token"
78
require "lrama/grammar/parameterizing_rule"
89
require "lrama/grammar/percent_code"
@@ -34,7 +35,7 @@ class Grammar
3435
def_delegators "@symbols_resolver", :symbols, :nterms, :terms, :add_nterm, :add_term,
3536
:find_symbol_by_number!, :find_symbol_by_id!, :token_to_symbol,
3637
:find_symbol_by_s_value!, :fill_symbol_number, :fill_nterm_type,
37-
:fill_printer, :fill_error_token, :sort_by_number!
38+
:fill_printer, :fill_destructor, :fill_error_token, :sort_by_number!
3839

3940

4041
def initialize(rule_counter)
@@ -43,6 +44,7 @@ def initialize(rule_counter)
4344
# Code defined by "%code"
4445
@percent_codes = []
4546
@printers = []
47+
@destructors = []
4648
@error_tokens = []
4749
@symbols_resolver = Grammar::Symbols::Resolver.new
4850
@types = []
@@ -65,6 +67,10 @@ def add_percent_code(id:, code:)
6567
@percent_codes << PercentCode.new(id.s_value, code.s_value)
6668
end
6769

70+
def add_destructor(ident_or_tags:, token_code:, lineno:)
71+
@destructors << Destructor.new(ident_or_tags: ident_or_tags, token_code: token_code, lineno: lineno)
72+
end
73+
6874
def add_printer(ident_or_tags:, token_code:, lineno:)
6975
@printers << Printer.new(ident_or_tags: ident_or_tags, token_code: token_code, lineno: lineno)
7076
end
@@ -345,6 +351,7 @@ def fill_symbols
345351
fill_symbol_number
346352
fill_nterm_type(@types)
347353
fill_printer(@printers)
354+
fill_destructor(@destructors)
348355
fill_error_token(@error_tokens)
349356
sort_by_number!
350357
end

tool/lrama/lib/lrama/grammar/code.rb

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
require "forwardable"
2+
require "lrama/grammar/code/destructor_code"
23
require "lrama/grammar/code/initial_action_code"
34
require "lrama/grammar/code/no_reference_code"
45
require "lrama/grammar/code/printer_code"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
module Lrama
2+
class Grammar
3+
class Code
4+
class DestructorCode < Code
5+
def initialize(type:, token_code:, tag:)
6+
super(type: type, token_code: token_code)
7+
@tag = tag
8+
end
9+
10+
private
11+
12+
# * ($$) *yyvaluep
13+
# * (@$) *yylocationp
14+
# * ($:$) error
15+
# * ($1) error
16+
# * (@1) error
17+
# * ($:1) error
18+
def reference_to_c(ref)
19+
case
20+
when ref.type == :dollar && ref.name == "$" # $$
21+
member = @tag.member
22+
"((*yyvaluep).#{member})"
23+
when ref.type == :at && ref.name == "$" # @$
24+
"(*yylocationp)"
25+
when ref.type == :index && ref.name == "$" # $:$
26+
raise "$:#{ref.value} can not be used in #{type}."
27+
when ref.type == :dollar # $n
28+
raise "$#{ref.value} can not be used in #{type}."
29+
when ref.type == :at # @n
30+
raise "@#{ref.value} can not be used in #{type}."
31+
when ref.type == :index # $:n
32+
raise "$:#{ref.value} can not be used in #{type}."
33+
else
34+
raise "Unexpected. #{self}, #{ref}"
35+
end
36+
end
37+
end
38+
end
39+
end
40+
end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
module Lrama
2+
class Grammar
3+
class Destructor < Struct.new(:ident_or_tags, :token_code, :lineno, keyword_init: true)
4+
def translated_code(tag)
5+
Code::DestructorCode.new(type: :destructor, token_code: token_code, tag: tag).translated_code
6+
end
7+
end
8+
end
9+
end

tool/lrama/lib/lrama/grammar/rule_builder.rb

+2-2
Original file line numberDiff line numberDiff line change
@@ -115,12 +115,12 @@ def process_rhs(parameterizing_rule_resolver)
115115
@replaced_rhs << lhs_token
116116
parameterizing_rule_resolver.created_lhs_list << lhs_token
117117
parameterizing_rule.rhs_list.each do |r|
118-
rule_builder = RuleBuilder.new(@rule_counter, @midrule_action_counter, i, lhs_tag: token.lhs_tag, skip_preprocess_references: true)
118+
rule_builder = RuleBuilder.new(@rule_counter, @midrule_action_counter, lhs_tag: token.lhs_tag, skip_preprocess_references: true)
119119
rule_builder.lhs = lhs_token
120120
r.symbols.each { |sym| rule_builder.add_rhs(bindings.resolve_symbol(sym)) }
121121
rule_builder.line = line
122-
rule_builder.user_code = r.user_code
123122
rule_builder.precedence_sym = r.precedence_sym
123+
rule_builder.user_code = r.user_code
124124
rule_builder.complete_input
125125
rule_builder.setup_rules(parameterizing_rule_resolver)
126126
@rule_builders_for_parameterizing_rules << rule_builder

tool/lrama/lib/lrama/grammar/stdlib.y

+42
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@
88
99
**********************************************************************/
1010

11+
// -------------------------------------------------------------------
12+
// Options
13+
1114
/*
1215
* program: option(number)
1316
*
@@ -21,6 +24,45 @@
2124
| X
2225
;
2326

27+
// -------------------------------------------------------------------
28+
// Sequences
29+
30+
/*
31+
* program: preceded(opening, X)
32+
*
33+
* =>
34+
*
35+
* program: preceded_opening_X
36+
* preceded_opening_X: opening X
37+
*/
38+
%rule preceded(opening, X): opening X { $$ = $2; }
39+
;
40+
41+
/*
42+
* program: terminated(X, closing)
43+
*
44+
* =>
45+
*
46+
* program: terminated_X_closing
47+
* terminated_X_closing: X closing
48+
*/
49+
%rule terminated(X, closing): X closing { $$ = $1; }
50+
;
51+
52+
/*
53+
* program: delimited(opening, X, closing)
54+
*
55+
* =>
56+
*
57+
* program: delimited_opening_X_closing
58+
* delimited_opening_X_closing: opening X closing
59+
*/
60+
%rule delimited(opening, X, closing): opening X closing { $$ = $2; }
61+
;
62+
63+
// -------------------------------------------------------------------
64+
// Lists
65+
2466
/*
2567
* program: list(number)
2668
*

tool/lrama/lib/lrama/grammar/symbol.rb

+4-2
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,12 @@
77
module Lrama
88
class Grammar
99
class Symbol
10-
attr_accessor :id, :alias_name, :tag, :number, :token_id, :nullable, :precedence, :printer, :error_token, :first_set, :first_set_bitmap
10+
attr_accessor :id, :alias_name, :tag, :number, :token_id, :nullable, :precedence,
11+
:printer, :destructor, :error_token, :first_set, :first_set_bitmap
1112
attr_reader :term
1213
attr_writer :eof_symbol, :error_symbol, :undef_symbol, :accept_symbol
1314

14-
def initialize(id:, term:, alias_name: nil, number: nil, tag: nil, token_id: nil, nullable: nil, precedence: nil, printer: nil)
15+
def initialize(id:, term:, alias_name: nil, number: nil, tag: nil, token_id: nil, nullable: nil, precedence: nil, printer: nil, destructor: nil)
1516
@id = id
1617
@alias_name = alias_name
1718
@number = number
@@ -21,6 +22,7 @@ def initialize(id:, term:, alias_name: nil, number: nil, tag: nil, token_id: nil
2122
@nullable = nullable
2223
@precedence = precedence
2324
@printer = printer
25+
@destructor = destructor
2426
end
2527

2628
def term?

tool/lrama/lib/lrama/grammar/symbols/resolver.rb

+21-4
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ def find_symbol_by_s_value(s_value)
5858
end
5959

6060
def find_symbol_by_s_value!(s_value)
61-
find_symbol_by_s_value(s_value) || (raise "Symbol not found: #{s_value}")
61+
find_symbol_by_s_value(s_value) || (raise "Symbol not found. value: `#{s_value}`")
6262
end
6363

6464
def find_symbol_by_id(id)
@@ -68,7 +68,7 @@ def find_symbol_by_id(id)
6868
end
6969

7070
def find_symbol_by_id!(id)
71-
find_symbol_by_id(id) || (raise "Symbol not found: #{id}")
71+
find_symbol_by_id(id) || (raise "Symbol not found. #{id}")
7272
end
7373

7474
def find_symbol_by_token_id(token_id)
@@ -78,7 +78,7 @@ def find_symbol_by_token_id(token_id)
7878
def find_symbol_by_number!(number)
7979
sym = symbols[number]
8080

81-
raise "Symbol not found: #{number}" unless sym
81+
raise "Symbol not found. number: `#{number}`" unless sym
8282
raise "[BUG] Symbol number mismatch. #{number}, #{sym}" if sym.number != number
8383

8484
sym
@@ -118,6 +118,23 @@ def fill_printer(printers)
118118
end
119119
end
120120

121+
def fill_destructor(destructors)
122+
symbols.each do |sym|
123+
destructors.each do |destructor|
124+
destructor.ident_or_tags.each do |ident_or_tag|
125+
case ident_or_tag
126+
when Lrama::Lexer::Token::Ident
127+
sym.destructor = destructor if sym.id == ident_or_tag
128+
when Lrama::Lexer::Token::Tag
129+
sym.destructor = destructor if sym.tag == ident_or_tag
130+
else
131+
raise "Unknown token type. #{destructor}"
132+
end
133+
end
134+
end
135+
end
136+
end
137+
121138
def fill_error_token(error_tokens)
122139
symbols.each do |sym|
123140
error_tokens.each do |token|
@@ -154,7 +171,7 @@ def validate!
154171
def find_nterm_by_id!(id)
155172
@nterms.find do |s|
156173
s.id == id
157-
end || (raise "Symbol not found: #{id}")
174+
end || (raise "Symbol not found. #{id}")
158175
end
159176

160177
def fill_terms_number

tool/lrama/lib/lrama/lexer.rb

+1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ class Lexer
2121
%define
2222
%require
2323
%printer
24+
%destructor
2425
%lex-param
2526
%parse-param
2627
%initial-action

tool/lrama/lib/lrama/lexer/token.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ def initialize(s_value:, alias_name: nil, location: nil)
1818
end
1919

2020
def to_s
21-
"#{super} location: #{location}"
21+
"value: `#{s_value}`, location: #{location}"
2222
end
2323

2424
def referred_by?(string)

0 commit comments

Comments
 (0)