aboutsummaryrefslogtreecommitdiffstats
path: root/tool/lrama/lib/lrama/grammar/code.rb
blob: 712cb1ad5a95cbef90c5fac1cbe8f2f97e17968b (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
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
require "forwardable"

module Lrama
  class Grammar
    class Code < Struct.new(:type, :token_code, keyword_init: true)
      extend Forwardable

      def_delegators "token_code", :s_value, :line, :column, :references

      # $$, $n, @$, @n is translated to C code
      def translated_code
        case type
        when :user_code
          translated_user_code
        when :initial_action
          translated_initial_action_code
        end
      end

      # * ($1) error
      # * ($$) *yyvaluep
      # * (@1) error
      # * (@$) *yylocationp
      def translated_printer_code(tag)
        t_code = s_value.dup

        references.reverse.each do |ref|
          first_column = ref.first_column
          last_column = ref.last_column

          case
          when ref.value == "$" && ref.type == :dollar # $$
            # Omit "<>"
            member = tag.s_value[1..-2]
            str = "((*yyvaluep).#{member})"
          when ref.value == "$" && ref.type == :at # @$
            str = "(*yylocationp)"
          when ref.type == :dollar # $n
            raise "$#{ref.value} can not be used in %printer."
          when ref.type == :at # @n
            raise "@#{ref.value} can not be used in %printer."
          else
            raise "Unexpected. #{self}, #{ref}"
          end

          t_code[first_column..last_column] = str
        end

        return t_code
      end
      alias :translated_error_token_code :translated_printer_code

      private

      # * ($1) yyvsp[i]
      # * ($$) yyval
      # * (@1) yylsp[i]
      # * (@$) yyloc
      def translated_user_code
        t_code = s_value.dup

        references.reverse.each do |ref|
          first_column = ref.first_column
          last_column = ref.last_column

          case
          when ref.value == "$" && ref.type == :dollar # $$
            # Omit "<>"
            member = ref.tag.s_value[1..-2]
            str = "(yyval.#{member})"
          when ref.value == "$" && ref.type == :at # @$
            str = "(yyloc)"
          when ref.type == :dollar # $n
            i = -ref.position_in_rhs + ref.value
            # Omit "<>"
            member = ref.tag.s_value[1..-2]
            str = "(yyvsp[#{i}].#{member})"
          when ref.type == :at # @n
            i = -ref.position_in_rhs + ref.value
            str = "(yylsp[#{i}])"
          else
            raise "Unexpected. #{self}, #{ref}"
          end

          t_code[first_column..last_column] = str
        end

        return t_code
      end

      # * ($1) error
      # * ($$) yylval
      # * (@1) error
      # * (@$) yylloc
      def translated_initial_action_code
        t_code = s_value.dup

        references.reverse.each do |ref|
          first_column = ref.first_column
          last_column = ref.last_column

          case
          when ref.value == "$" && ref.type == :dollar # $$
            str = "yylval"
          when ref.value == "$" && ref.type == :at # @$
            str = "yylloc"
          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."
          else
            raise "Unexpected. #{self}, #{ref}"
          end

          t_code[first_column..last_column] = str
        end

        return t_code
      end
    end
  end
end