summaryrefslogtreecommitdiff
path: root/tool/lrama/lib/lrama/grammar/code
diff options
context:
space:
mode:
Diffstat (limited to 'tool/lrama/lib/lrama/grammar/code')
-rw-r--r--tool/lrama/lib/lrama/grammar/code/destructor_code.rb40
-rw-r--r--tool/lrama/lib/lrama/grammar/code/initial_action_code.rb34
-rw-r--r--tool/lrama/lib/lrama/grammar/code/no_reference_code.rb28
-rw-r--r--tool/lrama/lib/lrama/grammar/code/printer_code.rb40
-rw-r--r--tool/lrama/lib/lrama/grammar/code/rule_action.rb88
5 files changed, 230 insertions, 0 deletions
diff --git a/tool/lrama/lib/lrama/grammar/code/destructor_code.rb b/tool/lrama/lib/lrama/grammar/code/destructor_code.rb
new file mode 100644
index 0000000000..70360eb90f
--- /dev/null
+++ b/tool/lrama/lib/lrama/grammar/code/destructor_code.rb
@@ -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
diff --git a/tool/lrama/lib/lrama/grammar/code/initial_action_code.rb b/tool/lrama/lib/lrama/grammar/code/initial_action_code.rb
new file mode 100644
index 0000000000..a694f193cb
--- /dev/null
+++ b/tool/lrama/lib/lrama/grammar/code/initial_action_code.rb
@@ -0,0 +1,34 @@
+module Lrama
+ class Grammar
+ class Code
+ class InitialActionCode < Code
+ private
+
+ # * ($$) yylval
+ # * (@$) yylloc
+ # * ($:$) error
+ # * ($1) error
+ # * (@1) error
+ # * ($:1) error
+ def reference_to_c(ref)
+ case
+ when ref.type == :dollar && ref.name == "$" # $$
+ "yylval"
+ when ref.type == :at && ref.name == "$" # @$
+ "yylloc"
+ when ref.type == :index && ref.name == "$" # $:$
+ raise "$:#{ref.value} can not be used in initial_action."
+ when ref.type == :dollar # $n
+ raise "$#{ref.value} can not be used in initial_action."
+ when ref.type == :at # @n
+ raise "@#{ref.value} can not be used in initial_action."
+ when ref.type == :index # $:n
+ raise "$:#{ref.value} can not be used in initial_action."
+ else
+ raise "Unexpected. #{self}, #{ref}"
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/tool/lrama/lib/lrama/grammar/code/no_reference_code.rb b/tool/lrama/lib/lrama/grammar/code/no_reference_code.rb
new file mode 100644
index 0000000000..6e614cc64a
--- /dev/null
+++ b/tool/lrama/lib/lrama/grammar/code/no_reference_code.rb
@@ -0,0 +1,28 @@
+module Lrama
+ class Grammar
+ class Code
+ class NoReferenceCode < Code
+ private
+
+ # * ($$) error
+ # * (@$) error
+ # * ($:$) error
+ # * ($1) error
+ # * (@1) error
+ # * ($:1) error
+ def reference_to_c(ref)
+ case
+ 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
diff --git a/tool/lrama/lib/lrama/grammar/code/printer_code.rb b/tool/lrama/lib/lrama/grammar/code/printer_code.rb
new file mode 100644
index 0000000000..ffccd89395
--- /dev/null
+++ b/tool/lrama/lib/lrama/grammar/code/printer_code.rb
@@ -0,0 +1,40 @@
+module Lrama
+ class Grammar
+ class Code
+ class PrinterCode < 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
diff --git a/tool/lrama/lib/lrama/grammar/code/rule_action.rb b/tool/lrama/lib/lrama/grammar/code/rule_action.rb
new file mode 100644
index 0000000000..d3c0eab64a
--- /dev/null
+++ b/tool/lrama/lib/lrama/grammar/code/rule_action.rb
@@ -0,0 +1,88 @@
+module Lrama
+ class Grammar
+ class Code
+ class RuleAction < Code
+ def initialize(type:, token_code:, rule:)
+ super(type: type, token_code: token_code)
+ @rule = rule
+ end
+
+ private
+
+ # * ($$) yyval
+ # * (@$) yyloc
+ # * ($:$) error
+ # * ($1) yyvsp[i]
+ # * (@1) yylsp[i]
+ # * ($:1) i - 1
+ #
+ #
+ # Consider a rule like
+ #
+ # class: keyword_class { $1 } tSTRING { $2 + $3 } keyword_end { $class = $1 + $keyword_end }
+ #
+ # For the semantic action of original rule:
+ #
+ # "Rule" class: keyword_class { $1 } tSTRING { $2 + $3 } keyword_end { $class = $1 + $keyword_end }
+ # "Position in grammar" $1 $2 $3 $4 $5
+ # "Index for yyvsp" -4 -3 -2 -1 0
+ # "$:n" $:1 $:2 $:3 $:4 $:5
+ # "index of $:n" -5 -4 -3 -2 -1
+ #
+ #
+ # For the first midrule action:
+ #
+ # "Rule" class: keyword_class { $1 } tSTRING { $2 + $3 } keyword_end { $class = $1 + $keyword_end }
+ # "Position in grammar" $1
+ # "Index for yyvsp" 0
+ # "$:n" $:1
+ def reference_to_c(ref)
+ case
+ when ref.type == :dollar && ref.name == "$" # $$
+ tag = ref.ex_tag || lhs.tag
+ raise_tag_not_found_error(ref) unless tag
+ "(yyval.#{tag.member})"
+ when ref.type == :at && ref.name == "$" # @$
+ "(yyloc)"
+ when ref.type == :index && ref.name == "$" # $:$
+ raise "$:$ is not supported"
+ when ref.type == :dollar # $n
+ i = -position_in_rhs + ref.index
+ tag = ref.ex_tag || rhs[ref.index - 1].tag
+ raise_tag_not_found_error(ref) unless tag
+ "(yyvsp[#{i}].#{tag.member})"
+ when ref.type == :at # @n
+ i = -position_in_rhs + ref.index
+ "(yylsp[#{i}])"
+ when ref.type == :index # $:n
+ i = -position_in_rhs + ref.index
+ "(#{i} - 1)"
+ else
+ raise "Unexpected. #{self}, #{ref}"
+ end
+ end
+
+ def position_in_rhs
+ # If rule is not derived rule, User Code is only action at
+ # the end of rule RHS. In such case, the action is located on
+ # `@rule.rhs.count`.
+ @rule.position_in_original_rule_rhs || @rule.rhs.count
+ end
+
+ # If this is midrule action, RHS is a RHS of the original rule.
+ def rhs
+ (@rule.original_rule || @rule).rhs
+ end
+
+ # Unlike `rhs`, LHS is always a LHS of the rule.
+ def lhs
+ @rule.lhs
+ end
+
+ def raise_tag_not_found_error(ref)
+ raise "Tag is not specified for '$#{ref.value}' in '#{@rule}'"
+ end
+ end
+ end
+ end
+end