diff --git a/lib/lrama/grammar/inline/resolver.rb b/lib/lrama/grammar/inline/resolver.rb new file mode 100644 index 00000000..267bd1f5 --- /dev/null +++ b/lib/lrama/grammar/inline/resolver.rb @@ -0,0 +1,21 @@ +module Lrama + class Grammar + class Inline + class Resolver + attr_accessor :rules + + def initialize + @rules = [] + end + + def add_inline_rule(rule) + @rules << rule + end + + def find(token) + @rules.select { |rule| rule.name == token.s_value }.last + end + end + end + end +end diff --git a/lib/lrama/grammar/inline/rhs.rb b/lib/lrama/grammar/inline/rhs.rb new file mode 100644 index 00000000..94a6060b --- /dev/null +++ b/lib/lrama/grammar/inline/rhs.rb @@ -0,0 +1,15 @@ +module Lrama + class Grammar + class Inline + class Rhs + attr_accessor :symbols, :user_code, :precedence_sym + + def initialize + @symbols = [] + @user_code = nil + @precedence_sym = nil + end + end + end + end +end diff --git a/lib/lrama/grammar/inline/rule.rb b/lib/lrama/grammar/inline/rule.rb new file mode 100644 index 00000000..00371b0b --- /dev/null +++ b/lib/lrama/grammar/inline/rule.rb @@ -0,0 +1,14 @@ +module Lrama + class Grammar + class Inline + class Rule + attr_reader :name, :rhs_list + + def initialize(name, rhs_list) + @name = name + @rhs_list = rhs_list + end + end + end + end +end diff --git a/lib/lrama/lexer.rb b/lib/lrama/lexer.rb index b94fad57..64121100 100644 --- a/lib/lrama/lexer.rb +++ b/lib/lrama/lexer.rb @@ -31,6 +31,7 @@ class Lexer %code %rule %no-stdlib + %inline ) def initialize(grammar_file) diff --git a/parser.y b/parser.y index f5b9f402..ca5177a0 100644 --- a/parser.y +++ b/parser.y @@ -30,6 +30,7 @@ rule bison_declaration: grammar_declaration | rule_declaration + | inline_declarations | "%expect" INTEGER { @grammar.expect = val[1] } | "%define" variable value | "%param" params @@ -283,6 +284,70 @@ rule result = builder } + inline_declarations: "%inline" IDENTIFIER ":" inline_rhs_list + { + rule = Grammar::Inline::Rule.new(val[1].s_value, val[3]) + @grammar.add_inline_rule(rule) + } + + inline_rhs_list: inline_rhs + { + builder = val[0] + result = [builder] + } + | inline_rhs_list "|" inline_rhs + { + builder = val[2] + result = val[0].append(builder) + } + + inline_rhs: /* empty */ + { + reset_precs + result = Grammar::Inline::Rhs.new + } + | "%empty" + { + reset_precs + result = Grammar::Inline::Rhs.new + } + | inline_rhs symbol named_ref_opt + { + token = val[1] + token.alias_name = val[2] + builder = val[0] + builder.symbols << token + result = builder + } + | inline_rhs "{" + { + if @prec_seen + on_action_error("multiple User_code after %prec", val[0]) if @code_after_prec + @code_after_prec = true + end + begin_c_declaration("}") + } + C_DECLARATION + { + end_c_declaration + } + "}" named_ref_opt + { + user_code = val[3] + user_code.alias_name = val[6] + builder = val[0] + builder.user_code = user_code + result = builder + } + | inline_rhs "%prec" symbol + { + sym = @grammar.find_symbol_by_id!(val[2]) + @prec_seen = true + builder = val[0] + builder.precedence_sym = sym + result = builder + } + int_opt: # empty | INTEGER