Skip to content

Commit

Permalink
Lrama v0.6.4
Browse files Browse the repository at this point in the history
  • Loading branch information
yui-knk committed Mar 22, 2024
1 parent b4d73e9 commit c504583
Show file tree
Hide file tree
Showing 17 changed files with 340 additions and 107 deletions.
68 changes: 67 additions & 1 deletion tool/lrama/NEWS.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,69 @@
# NEWS for Lrama

## Lrama 0.6.4 (2024-03-22)

### Parameterizing rules (preceded, terminated, delimited)

Support `preceded`, `terminated` and `delimited` rules.

```
program: preceded(opening, X)
// Expanded to
program: preceded_opening_X
preceded_opening_X: opening X
```

```
program: terminated(X, closing)
// Expanded to
program: terminated_X_closing
terminated_X_closing: X closing
```

```
program: delimited(opening, X, closing)
// Expanded to
program: delimited_opening_X_closing
delimited_opening_X_closing: opening X closing
```

https://github.com/ruby/lrama/pull/382

### Support `%destructor` declaration

User can set codes for freeing semantic value resources by using `%destructor`.
In general, these resources are freed by actions or after parsing.
However if syntax error happens in parsing, these codes may not be executed.
Codes associated to `%destructor` are executed when semantic value is popped from the stack by an error.

```
%token <val1> NUM
%type <val2> expr2
%type <val3> expr
%destructor {
printf("destructor for val1: %d\n", $$);
} <val1> // printer for TAG
%destructor {
printf("destructor for val2: %d\n", $$);
} <val2>
%destructor {
printf("destructor for expr: %d\n", $$);
} expr // printer for symbol
```

Bison supports this feature from 1.75b.

https://github.com/ruby/lrama/pull/385

## Lrama 0.6.3 (2024-02-15)

### Bring Your Own Stack
Expand Down Expand Up @@ -34,6 +98,8 @@ primary: k_if expr_value then compstmt if_tail k_end
}
```

https://github.com/ruby/lrama/pull/367

## Lrama 0.6.2 (2024-01-27)

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

```
%rule constant(X) : X
;
;
%rule option(Y) : /* empty */
| Y
Expand Down
9 changes: 8 additions & 1 deletion tool/lrama/lib/lrama/grammar.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
require "lrama/grammar/binding"
require "lrama/grammar/code"
require "lrama/grammar/counter"
require "lrama/grammar/destructor"
require "lrama/grammar/error_token"
require "lrama/grammar/parameterizing_rule"
require "lrama/grammar/percent_code"
Expand Down Expand Up @@ -34,7 +35,7 @@ class Grammar
def_delegators "@symbols_resolver", :symbols, :nterms, :terms, :add_nterm, :add_term,
:find_symbol_by_number!, :find_symbol_by_id!, :token_to_symbol,
:find_symbol_by_s_value!, :fill_symbol_number, :fill_nterm_type,
:fill_printer, :fill_error_token, :sort_by_number!
:fill_printer, :fill_destructor, :fill_error_token, :sort_by_number!


def initialize(rule_counter)
Expand All @@ -43,6 +44,7 @@ def initialize(rule_counter)
# Code defined by "%code"
@percent_codes = []
@printers = []
@destructors = []
@error_tokens = []
@symbols_resolver = Grammar::Symbols::Resolver.new
@types = []
Expand All @@ -65,6 +67,10 @@ def add_percent_code(id:, code:)
@percent_codes << PercentCode.new(id.s_value, code.s_value)
end

def add_destructor(ident_or_tags:, token_code:, lineno:)
@destructors << Destructor.new(ident_or_tags: ident_or_tags, token_code: token_code, lineno: lineno)
end

def add_printer(ident_or_tags:, token_code:, lineno:)
@printers << Printer.new(ident_or_tags: ident_or_tags, token_code: token_code, lineno: lineno)
end
Expand Down Expand Up @@ -345,6 +351,7 @@ def fill_symbols
fill_symbol_number
fill_nterm_type(@types)
fill_printer(@printers)
fill_destructor(@destructors)
fill_error_token(@error_tokens)
sort_by_number!
end
Expand Down
1 change: 1 addition & 0 deletions tool/lrama/lib/lrama/grammar/code.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
require "forwardable"
require "lrama/grammar/code/destructor_code"
require "lrama/grammar/code/initial_action_code"
require "lrama/grammar/code/no_reference_code"
require "lrama/grammar/code/printer_code"
Expand Down
40 changes: 40 additions & 0 deletions tool/lrama/lib/lrama/grammar/code/destructor_code.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
module Lrama
class Grammar
class Code
class DestructorCode < Code
def initialize(type:, token_code:, tag:)
super(type: type, token_code: token_code)
@tag = tag
end

private

# * ($$) *yyvaluep
# * (@$) *yylocationp
# * ($:$) error
# * ($1) error
# * (@1) error
# * ($:1) error
def reference_to_c(ref)
case
when ref.type == :dollar && ref.name == "$" # $$
member = @tag.member
"((*yyvaluep).#{member})"
when ref.type == :at && ref.name == "$" # @$
"(*yylocationp)"
when ref.type == :index && ref.name == "$" # $:$
raise "$:#{ref.value} can not be used in #{type}."
when ref.type == :dollar # $n
raise "$#{ref.value} can not be used in #{type}."
when ref.type == :at # @n
raise "@#{ref.value} can not be used in #{type}."
when ref.type == :index # $:n
raise "$:#{ref.value} can not be used in #{type}."
else
raise "Unexpected. #{self}, #{ref}"
end
end
end
end
end
end
9 changes: 9 additions & 0 deletions tool/lrama/lib/lrama/grammar/destructor.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
module Lrama
class Grammar
class Destructor < Struct.new(:ident_or_tags, :token_code, :lineno, keyword_init: true)
def translated_code(tag)
Code::DestructorCode.new(type: :destructor, token_code: token_code, tag: tag).translated_code
end
end
end
end
4 changes: 2 additions & 2 deletions tool/lrama/lib/lrama/grammar/rule_builder.rb
Original file line number Diff line number Diff line change
Expand Up @@ -115,12 +115,12 @@ def process_rhs(parameterizing_rule_resolver)
@replaced_rhs << lhs_token
parameterizing_rule_resolver.created_lhs_list << lhs_token
parameterizing_rule.rhs_list.each do |r|
rule_builder = RuleBuilder.new(@rule_counter, @midrule_action_counter, i, lhs_tag: token.lhs_tag, skip_preprocess_references: true)
rule_builder = RuleBuilder.new(@rule_counter, @midrule_action_counter, lhs_tag: token.lhs_tag, skip_preprocess_references: true)
rule_builder.lhs = lhs_token
r.symbols.each { |sym| rule_builder.add_rhs(bindings.resolve_symbol(sym)) }
rule_builder.line = line
rule_builder.user_code = r.user_code
rule_builder.precedence_sym = r.precedence_sym
rule_builder.user_code = r.user_code
rule_builder.complete_input
rule_builder.setup_rules(parameterizing_rule_resolver)
@rule_builders_for_parameterizing_rules << rule_builder
Expand Down
42 changes: 42 additions & 0 deletions tool/lrama/lib/lrama/grammar/stdlib.y
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@
**********************************************************************/

// -------------------------------------------------------------------
// Options

/*
* program: option(number)
*
Expand All @@ -21,6 +24,45 @@
| X
;

// -------------------------------------------------------------------
// Sequences

/*
* program: preceded(opening, X)
*
* =>
*
* program: preceded_opening_X
* preceded_opening_X: opening X
*/
%rule preceded(opening, X): opening X { $$ = $2; }
;

/*
* program: terminated(X, closing)
*
* =>
*
* program: terminated_X_closing
* terminated_X_closing: X closing
*/
%rule terminated(X, closing): X closing { $$ = $1; }
;

/*
* program: delimited(opening, X, closing)
*
* =>
*
* program: delimited_opening_X_closing
* delimited_opening_X_closing: opening X closing
*/
%rule delimited(opening, X, closing): opening X closing { $$ = $2; }
;

// -------------------------------------------------------------------
// Lists

/*
* program: list(number)
*
Expand Down
6 changes: 4 additions & 2 deletions tool/lrama/lib/lrama/grammar/symbol.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,12 @@
module Lrama
class Grammar
class Symbol
attr_accessor :id, :alias_name, :tag, :number, :token_id, :nullable, :precedence, :printer, :error_token, :first_set, :first_set_bitmap
attr_accessor :id, :alias_name, :tag, :number, :token_id, :nullable, :precedence,
:printer, :destructor, :error_token, :first_set, :first_set_bitmap
attr_reader :term
attr_writer :eof_symbol, :error_symbol, :undef_symbol, :accept_symbol

def initialize(id:, term:, alias_name: nil, number: nil, tag: nil, token_id: nil, nullable: nil, precedence: nil, printer: nil)
def initialize(id:, term:, alias_name: nil, number: nil, tag: nil, token_id: nil, nullable: nil, precedence: nil, printer: nil, destructor: nil)
@id = id
@alias_name = alias_name
@number = number
Expand All @@ -21,6 +22,7 @@ def initialize(id:, term:, alias_name: nil, number: nil, tag: nil, token_id: nil
@nullable = nullable
@precedence = precedence
@printer = printer
@destructor = destructor
end

def term?
Expand Down
25 changes: 21 additions & 4 deletions tool/lrama/lib/lrama/grammar/symbols/resolver.rb
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ def find_symbol_by_s_value(s_value)
end

def find_symbol_by_s_value!(s_value)
find_symbol_by_s_value(s_value) || (raise "Symbol not found: #{s_value}")
find_symbol_by_s_value(s_value) || (raise "Symbol not found. value: `#{s_value}`")
end

def find_symbol_by_id(id)
Expand All @@ -68,7 +68,7 @@ def find_symbol_by_id(id)
end

def find_symbol_by_id!(id)
find_symbol_by_id(id) || (raise "Symbol not found: #{id}")
find_symbol_by_id(id) || (raise "Symbol not found. #{id}")
end

def find_symbol_by_token_id(token_id)
Expand All @@ -78,7 +78,7 @@ def find_symbol_by_token_id(token_id)
def find_symbol_by_number!(number)
sym = symbols[number]

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

sym
Expand Down Expand Up @@ -118,6 +118,23 @@ def fill_printer(printers)
end
end

def fill_destructor(destructors)
symbols.each do |sym|
destructors.each do |destructor|
destructor.ident_or_tags.each do |ident_or_tag|
case ident_or_tag
when Lrama::Lexer::Token::Ident
sym.destructor = destructor if sym.id == ident_or_tag
when Lrama::Lexer::Token::Tag
sym.destructor = destructor if sym.tag == ident_or_tag
else
raise "Unknown token type. #{destructor}"
end
end
end
end
end

def fill_error_token(error_tokens)
symbols.each do |sym|
error_tokens.each do |token|
Expand Down Expand Up @@ -154,7 +171,7 @@ def validate!
def find_nterm_by_id!(id)
@nterms.find do |s|
s.id == id
end || (raise "Symbol not found: #{id}")
end || (raise "Symbol not found. #{id}")
end

def fill_terms_number
Expand Down
1 change: 1 addition & 0 deletions tool/lrama/lib/lrama/lexer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ class Lexer
%define
%require
%printer
%destructor
%lex-param
%parse-param
%initial-action
Expand Down
2 changes: 1 addition & 1 deletion tool/lrama/lib/lrama/lexer/token.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ def initialize(s_value:, alias_name: nil, location: nil)
end

def to_s
"#{super} location: #{location}"
"value: `#{s_value}`, location: #{location}"
end

def referred_by?(string)
Expand Down
Loading

0 comments on commit c504583

Please sign in to comment.