blob: d3c0eab64a9177de3386fa01845940fb10fbd947 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
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
|