rley 0.5.01 → 0.5.02

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +5 -0
  3. data/examples/data_formats/JSON/cli_options.rb +25 -9
  4. data/examples/data_formats/JSON/json_ast_builder.rb +152 -0
  5. data/examples/data_formats/JSON/json_ast_nodes.rb +141 -0
  6. data/examples/data_formats/JSON/json_demo.rb +24 -8
  7. data/examples/general/calc_iter1/calc_ast_builder.rb +142 -0
  8. data/examples/general/calc_iter1/calc_ast_nodes.rb +151 -0
  9. data/examples/general/calc_iter1/calc_demo.rb +38 -0
  10. data/examples/general/calc_iter1/calc_grammar.rb +25 -0
  11. data/examples/general/calc_iter1/calc_lexer.rb +81 -0
  12. data/examples/general/{calc → calc_iter1}/calc_parser.rb +0 -0
  13. data/examples/general/calc_iter1/spec/calculator_spec.rb +73 -0
  14. data/examples/general/calc_iter2/calc_ast_builder.rb +186 -0
  15. data/examples/general/calc_iter2/calc_ast_nodes.rb +151 -0
  16. data/examples/general/{calc → calc_iter2}/calc_demo.rb +3 -2
  17. data/examples/general/{calc → calc_iter2}/calc_grammar.rb +0 -0
  18. data/examples/general/calc_iter2/calc_lexer.rb +81 -0
  19. data/examples/general/calc_iter2/calc_parser.rb +24 -0
  20. data/lib/rley.rb +1 -0
  21. data/lib/rley/constants.rb +1 -1
  22. data/lib/rley/parser/cst_builder.rb +5 -225
  23. data/lib/rley/parser/gfg_parsing.rb +2 -2
  24. data/lib/rley/parser/parse_forest_factory.rb +1 -1
  25. data/lib/rley/parser/parse_rep_creator.rb +2 -2
  26. data/lib/rley/parser/parse_tree_builder.rb +161 -104
  27. data/lib/rley/parser/parse_tree_factory.rb +6 -2
  28. data/spec/rley/parser/ast_builder_spec.rb +395 -0
  29. data/spec/rley/support/grammar_arr_int_helper.rb +21 -11
  30. metadata +20 -9
  31. data/examples/general/calc/calc_lexer.rb +0 -90
  32. data/spec/rley/parser/parse_tree_builder_spec.rb +0 -249
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: fe660cf0bb663508b71cc2e40461b571d4caa6ed
4
- data.tar.gz: 5217bf9f6757f849bdd0fe471b8d5aa0c2283cb5
3
+ metadata.gz: 638178eefcf2e673a801018aeee17ff0ef7ed16b
4
+ data.tar.gz: 894a767a871ba958b61047369e989783ae5fe88d
5
5
  SHA512:
6
- metadata.gz: 67fa745c86ccb6e14fe8689f4a0b94fc756b1a9f9dd8be50b77e5506671038f49a85f65bbef4e986f27f8d709afb6ad02896157b0b455b580c37aa6f8d011a47
7
- data.tar.gz: 37df7d6e3519396a4198ecedc42d9e45d98bc71cedf4aaeba9fdff8f88ec13891da0168ace662c23e551de3cc80fefef004ed4b7be8bf6f97c2fb9452c60a334
6
+ metadata.gz: 23571e5b06645c427ee3ac06e662d93a3aca87d64d1cb7b57ea133ee14fd9f6a0ac0d4bebde44dd8d70cefcbb8e4614d3e49752c76e4545ed8e0923c2cbdb1dc
7
+ data.tar.gz: 47bdc2e63a242463221143098758c0cfc2ff65b64789c9b46ca6e5073d5dc9a8b07317b29a6edac79056cea7c3c41d334d9a5ad7b697780e4ba17258624a7526
@@ -1,3 +1,8 @@
1
+ ### 0.5.02 / 2017-10-08
2
+ * [NEW] Addedsupport for ASTs (Abstract Syntax Tree)
3
+ * [CHANGE] File `examples/data_formats/JSON/JSON_demo.rb` Added New command-line switches for details use --help option
4
+ * [CHANGE] File `examples/general/calc_iter1/calc_demo.rb` Calculator now computes the value of a parsed expression
5
+
1
6
  ### 0.5.01 / 2017-08-20
2
7
  * [CHANGE] File `appveyor.yml`: Added Ruby 2.4 build environment in Appveyor CI
3
8
 
@@ -7,12 +7,13 @@ class CLIOptions < Hash
7
7
  # parse trees from LBN output.
8
8
  def initialize(progName, progVersion, args)
9
9
  super()
10
-
10
+
11
11
  # Default values
12
12
  self[:prog_name] = progName
13
13
  self[:prog_version] = progVersion
14
14
  self[:format] = :ascii_tree
15
-
15
+ self[:rep] = :cst
16
+
16
17
  options = build_option_parser
17
18
  options.parse!(args)
18
19
  end
@@ -23,29 +24,44 @@ class CLIOptions < Hash
23
24
  OptionParser.new do |opts|
24
25
  opts.banner = <<-END_BANNER
25
26
  #{self[:prog_name]}: a demo utility that parses a JSON file
26
- and renders its parse tree to the standard output
27
+ and renders its parse tree to the standard output
27
28
  in the format specified in the command-line.
28
29
 
29
30
  Usage: json_demo.rb [options] FILE
30
31
 
31
32
  Examples:
32
33
  json_demo --format ascii_tree sample01.json
34
+ json_demo --rep ast --format ruby sample01.json
33
35
  END_BANNER
34
36
 
35
37
  opts.separator ''
36
38
 
37
39
  format_help = <<-END_TEXT
38
40
  Select the output format (default: ascii_tree). Available formats:
39
- ascii_tree Simple text representation of parse trees
40
- minify Strip all unnecessary whitespace in the input json file
41
- labelled Labelled square notation (LBN)
42
- Use online tools (e.g. http://yohasebe.com/rsyntaxtree/)
43
- to visualize parse trees from LBN output.
41
+ ascii_tree [cst, ast] Simple text representation of parse trees
42
+ minify [cst] Strip all unnecessary whitespace in input json file
43
+ labelled [cst, ast] Labelled square notation (LBN)
44
+ Use online tools (e.g. http://yohasebe.com/rsyntaxtree/)
45
+ to visualize parse trees from LBN output.
46
+ ruby [ast] A Ruby representation of the JSON input.
44
47
  END_TEXT
45
- formats = %i[ascii_tree labelled minify]
48
+ formats = %i[ascii_tree labelled minify ruby]
46
49
  opts.on('-f', '--format FORMAT', formats, format_help) do |frm|
47
50
  self[:format] = frm
48
51
  end
52
+ opts.separator ''
53
+
54
+ rep_help = <<-END_TEXT
55
+ Set the parse tree representation (default: cst)
56
+ cst Concrete Syntax Tree. The out-of-the-box parse tree
57
+ representation.
58
+ ast Abstract Syntaxt Tree. A customized parse tree for JSON.
59
+ It is a more compact and practical representation.
60
+ END_TEXT
61
+ representations = %i[cst ast]
62
+ opts.on('-r', '--rep REP', representations, rep_help) do |rep|
63
+ self[:rep] = rep
64
+ end
49
65
 
50
66
  opts.separator ''
51
67
  opts.separator ' **** Utility ****'
@@ -0,0 +1,152 @@
1
+ require_relative 'json_ast_nodes'
2
+
3
+ # The purpose of a JSONASTBuilder is to build piece by piece an AST
4
+ # (Abstract Syntax Tree) from a sequence of input tokens and
5
+ # visit events produced by walking over a GFGParsing object.
6
+ # Uses the Builder GoF pattern.
7
+ # The Builder pattern creates a complex object
8
+ # (say, a parse tree) from simpler objects (terminal and non-terminal
9
+ # nodes) and using a step by step approach.
10
+ class JSONASTBuilder < Rley::Parser::ParseTreeBuilder
11
+ Terminal2NodeClass = {
12
+ 'false' => JSONBooleanNode,
13
+ 'true' => JSONBooleanNode,
14
+ 'null' => JSONNullNode,
15
+ 'string' => JSONStringNode,
16
+ 'number' => JSONNumberNode,
17
+ }
18
+
19
+ protected
20
+
21
+ def return_first_child(_range, _tokens, theChildren)
22
+ return theChildren[0]
23
+ end
24
+
25
+ def return_second_child(_range, _tokens, theChildren)
26
+ return theChildren[1]
27
+ end
28
+
29
+ # Overriding method.
30
+ # Create a parse tree object with given
31
+ # node as root node.
32
+ def create_tree(aRootNode)
33
+ return Rley::PTree::ParseTree.new(aRootNode)
34
+ end
35
+
36
+ # Overriding method.
37
+ # Factory method for creating a node object for the given
38
+ # input token.
39
+ # @param terminal [Terminal] Terminal symbol associated with the token
40
+ # @param aTokenPosition [Integer] Position of token in the input stream
41
+ # @param aToken [Token] The input token
42
+ def new_leaf_node(terminal, aTokenPosition, aToken)
43
+ klass = Terminal2NodeClass.fetch(terminal.name, JSONTerminalNode)
44
+ return klass.new(aToken, aTokenPosition)
45
+ end
46
+
47
+
48
+ # Method to override.
49
+ # Factory method for creating a parent node object.
50
+ # @param aProduction [Production] Production rule
51
+ # @param aRange [Range] Range of tokens matched by the rule
52
+ # @param theTokens [Array] The input tokens
53
+ # @param theChildren [Array] Children nodes (one per rhs symbol)
54
+ def new_parent_node(aProduction, aRange, theTokens, theChildren)
55
+ node = case aProduction.name
56
+ when 'JSON-text[0]' # rule 'JSON-text' => 'value'
57
+ return_first_child(aRange, theTokens, theChildren)
58
+
59
+ when /value\[\d\]/
60
+ return_first_child(aRange, theTokens, theChildren)
61
+
62
+ when 'object[0]'
63
+ reduce_object_0(aProduction, aRange, theTokens, theChildren)
64
+
65
+ when 'object[1]'
66
+ reduce_object_1(aRange, theTokens, theChildren)
67
+
68
+ when 'member-list[0]'
69
+ reduce_member_list_0(aRange, theTokens, theChildren)
70
+
71
+ when 'member-list[1]'
72
+ reduce_member_list_1(aProduction, aRange, theTokens, theChildren)
73
+
74
+ when 'member[0]'
75
+ reduce_member_0(aProduction, aRange, theTokens, theChildren)
76
+
77
+ when 'array[0]'
78
+ reduce_array_0(aProduction, aRange, theTokens, theChildren)
79
+
80
+ when 'array[1]'
81
+ reduce_array_1(aRange, theTokens, theChildren)
82
+
83
+ when 'array-items[0]'
84
+ reduce_array_items_0(aRange, theTokens, theChildren)
85
+
86
+ when 'array-items[1]'
87
+ reduce_array_items_1(aProduction, aRange, theTokens, theChildren)
88
+ else
89
+ raise StandardError, "Don't know production #{aProduction.name}"
90
+ end
91
+
92
+ return node
93
+ end
94
+
95
+ # rule 'object' => %w[begin-object member-list end-object]
96
+ def reduce_object_0(aProduction, aRange, theTokens, theChildren)
97
+ second_child = theChildren[1]
98
+ second_child.symbol = aProduction.lhs
99
+ return second_child
100
+ end
101
+
102
+ # rule 'object' => %w[begin-object end-object]
103
+ def reduce_object_1(aRange, theTokens, theChildren)
104
+ return JSONObjectNode.new(aProduction.lhs)
105
+ end
106
+
107
+ # rule 'member-list' => %w[member-list value-separator member]
108
+ def reduce_member_list_0(aRange, theTokens, theChildren)
109
+ node = theChildren[0]
110
+ node.members << theChildren.last
111
+ return node
112
+ end
113
+
114
+ # rule 'member-list' => 'member'
115
+ def reduce_member_list_1(aProduction, aRange, theTokens, theChildren)
116
+ node = JSONObjectNode.new(aProduction.lhs)
117
+ node.members << theChildren[0]
118
+ return node
119
+ end
120
+
121
+ # rule 'member' => %w[string name-separator value]
122
+ def reduce_member_0(aProduction, aRange, theTokens, theChildren)
123
+ return JSONPair.new(theChildren[0], theChildren[2], aProduction.lhs)
124
+ end
125
+
126
+ # rule 'object' => %w[begin-object member-list end-object]
127
+ def reduce_array_0(aProduction, aRange, theTokens, theChildren)
128
+ second_child = theChildren[1]
129
+ second_child.symbol = aProduction.lhs
130
+ return second_child
131
+ end
132
+
133
+
134
+ # rule 'array' => %w[begin-array end-array]
135
+ def reduce_array_1(aRange, theTokens, theChildren)
136
+ return JSONArrayNode.new
137
+ end
138
+
139
+ # rule 'array-items' => %w[array-items value-separator value]
140
+ def reduce_array_items_0(aRange, theTokens, theChildren)
141
+ node = theChildren[0]
142
+ node.children << theChildren[2]
143
+ return node
144
+ end
145
+
146
+ # rule 'array-items' => %w[value]
147
+ def reduce_array_items_1(aProduction, aRange, theTokens, theChildren)
148
+ node = JSONArrayNode.new(aProduction.lhs)
149
+ node.children << theChildren[0]
150
+ return node
151
+ end
152
+ end # class
@@ -0,0 +1,141 @@
1
+ # Classes that implement nodes of Abstract Syntax Trees (AST) representing
2
+ # JSON parse results.
3
+
4
+
5
+ JSONTerminalNode = Struct.new(:token, :value, :position) do
6
+ def initialize(aToken, aPosition)
7
+ self.token = aToken
8
+ self.position = aPosition
9
+ init_value(aToken.lexeme)
10
+ end
11
+
12
+ # This method can be overriden
13
+ def init_value(aLiteral)
14
+ self.value = aLiteral.dup
15
+ end
16
+
17
+ def symbol()
18
+ self.token.terminal
19
+ end
20
+
21
+ def to_ruby()
22
+ return value
23
+ end
24
+
25
+ # Part of the 'visitee' role in Visitor design pattern.
26
+ # @param aVisitor[ParseTreeVisitor] the visitor
27
+ def accept(aVisitor)
28
+ aVisitor.visit_terminal(self)
29
+ end
30
+ end
31
+
32
+
33
+ class JSONNullNode < JSONTerminalNode
34
+ def init_value(_aLiteral)
35
+ self.value = nil
36
+ end
37
+ end
38
+
39
+ class JSONBooleanNode < JSONTerminalNode
40
+ def init_value(aLiteral)
41
+ self.value = aLiteral == 'true'
42
+ end
43
+ end
44
+
45
+ class JSONStringNode < JSONTerminalNode
46
+ end
47
+
48
+ class JSONNumberNode < JSONTerminalNode
49
+ def init_value(aLiteral)
50
+ case aLiteral
51
+ when /^[+-]?\d+$/
52
+ self.value = aLiteral.to_i
53
+
54
+ when /^[+-]?\d+(\.\d+)?([eE][+-]?\d+)?$/
55
+ self.value = aLiteral.to_f
56
+ end
57
+ end
58
+ end
59
+
60
+ class JSONCompositeNode
61
+ attr_accessor(:children)
62
+ attr_accessor(:symbol)
63
+
64
+ def initialize(aSymbol)
65
+ @symbol = aSymbol
66
+ @children = []
67
+ end
68
+
69
+ # Part of the 'visitee' role in Visitor design pattern.
70
+ # @param aVisitor[ParseTreeVisitor] the visitor
71
+ def accept(aVisitor)
72
+ aVisitor.visit_nonterminal(self)
73
+ end
74
+
75
+ alias subnodes children
76
+
77
+ end # class
78
+
79
+
80
+ class JSONArrayNode < JSONCompositeNode
81
+ def initialize(aSymbol)
82
+ super(aSymbol)
83
+ end
84
+
85
+ # Convert this tree node in a simpler Ruby representation.
86
+ # Basically a JSON object corresponds to a Ruhy Hash
87
+ def to_ruby()
88
+ rep = []
89
+ children.each do |child|
90
+ rep << child.to_ruby
91
+ end
92
+
93
+ return rep
94
+ end
95
+ end # class
96
+
97
+ class JSONPair
98
+ attr_reader(:name)
99
+ attr_reader(:value)
100
+ attr_reader(:symbol)
101
+
102
+ def initialize(aName, aValue, aSymbol)
103
+ @name = aName
104
+ @value = aValue
105
+ @symbol = aSymbol
106
+ end
107
+
108
+ def children()
109
+ return [name, value]
110
+ end
111
+
112
+ alias subnodes children
113
+
114
+ # Part of the 'visitee' role in Visitor design pattern.
115
+ # @param aVisitor[ParseTreeVisitor] the visitor
116
+ def accept(aVisitor)
117
+ aVisitor.visit_nonterminal(self)
118
+ end
119
+
120
+ end # class
121
+
122
+ class JSONObjectNode < JSONCompositeNode
123
+ def initialize(aSymbol)
124
+ super(aSymbol)
125
+ end
126
+
127
+ # Convert this tree node in a simpler Ruby representation.
128
+ # Basically a JSON object corresponds to a Ruhy Hash
129
+ def to_ruby()
130
+ rep = {}
131
+ members.each do |pair|
132
+ rep[pair.name.to_ruby] = pair.value.to_ruby
133
+ end
134
+
135
+ return rep
136
+ end
137
+
138
+ alias members children
139
+ end # class
140
+
141
+
@@ -1,9 +1,10 @@
1
1
  require_relative 'cli_options'
2
2
  require_relative 'json_parser'
3
3
  require_relative 'json_minifier'
4
+ require_relative 'json_ast_builder'
4
5
 
5
6
  prog_name = 'json_demo'
6
- prog_version = '0.2.0'
7
+ prog_version = '0.3.0'
7
8
 
8
9
  cli_options = CLIOptions.new(prog_name, prog_version, ARGV)
9
10
  if ARGV.empty?
@@ -24,8 +25,8 @@ unless result.success?
24
25
  exit(1)
25
26
  end
26
27
 
27
- # Generate a parse tree from the parse result
28
- ptree = result.parse_tree
28
+ tree_rep = cli_options[:rep]
29
+ renderer = nil
29
30
 
30
31
  # Select the output format
31
32
  case cli_options[:format]
@@ -34,12 +35,27 @@ case cli_options[:format]
34
35
  when :labelled
35
36
  renderer = Rley::Formatter::BracketNotation.new($stdout)
36
37
  when :minify
37
- renderer = JSONMinifier.new($stdout)
38
+ msg = "minify format works for 'cst' representation only"
39
+ raise StandardError, msg if tree_rep == :ast
40
+ renderer = JSONMinifier.new($stdout)
41
+ when :ruby
42
+ msg = "ruby format works for 'ast' representation only"
43
+ raise StandardError, msg if tree_rep == :cst
38
44
  end
39
45
 
40
- # Let's create a parse tree visitor
41
- visitor = Rley::ParseTreeVisitor.new(ptree)
46
+ tree_builder = (tree_rep == :ast)? JSONASTBuilder : nil
47
+
48
+ # Generate a parse tree from the parse result
49
+ ptree = result.parse_tree(tree_builder)
42
50
 
43
- # Now output formatted parse tree
44
- renderer.render(visitor)
51
+ if renderer
52
+ # Let's create a parse tree visitor
53
+ visitor = Rley::ParseTreeVisitor.new(ptree)
54
+
55
+ # Now output formatted parse tree
56
+ renderer.render(visitor)
57
+ else
58
+ root = ptree.root
59
+ p(root.to_ruby) # Output the Ruby representation of the JSON input
60
+ end
45
61
  # End of file
@@ -0,0 +1,142 @@
1
+ require_relative 'calc_ast_nodes'
2
+
3
+ # The purpose of a CalcASTBuilder is to build piece by piece an AST
4
+ # (Abstract Syntax Tree) from a sequence of input tokens and
5
+ # visit events produced by walking over a GFGParsing object.
6
+ # Uses the Builder GoF pattern.
7
+ # The Builder pattern creates a complex object
8
+ # (say, a parse tree) from simpler objects (terminal and non-terminal
9
+ # nodes) and using a step by step approach.
10
+ class CalcASTBuilder < Rley::Parser::ParseTreeBuilder
11
+ Terminal2NodeClass = {
12
+ 'NUMBER' => CalcNumberNode
13
+ }
14
+
15
+ protected
16
+
17
+ def return_first_child(_range, _tokens, theChildren)
18
+ return theChildren[0]
19
+ end
20
+
21
+ def return_second_child(_range, _tokens, theChildren)
22
+ return theChildren[1]
23
+ end
24
+
25
+ def return_last_child(_range, _tokens, theChildren)
26
+ return theChildren[-1]
27
+ end
28
+
29
+ # Overriding method.
30
+ # Create a parse tree object with given
31
+ # node as root node.
32
+ def create_tree(aRootNode)
33
+ return Rley::PTree::ParseTree.new(aRootNode)
34
+ end
35
+
36
+ # Overriding method.
37
+ # Factory method for creating a node object for the given
38
+ # input token.
39
+ # @param aTerminal [Terminal] Terminal symbol associated with the token
40
+ # @param aTokenPosition [Integer] Position of token in the input stream
41
+ # @param aToken [Token] The input token
42
+ def new_leaf_node(aProduction, aTerminal, aTokenPosition, aToken)
43
+ klass = Terminal2NodeClass.fetch(aTerminal.name, CalcTerminalNode)
44
+ if klass
45
+ node = klass.new(aToken, aTokenPosition)
46
+ else
47
+ node = PTree::TerminalNode.new(aToken, aTokenPosition)
48
+ end
49
+
50
+ return node
51
+ end
52
+
53
+
54
+ # Method to override.
55
+ # Factory method for creating a parent node object.
56
+ # @param aProduction [Production] Production rule
57
+ # @param aRange [Range] Range of tokens matched by the rule
58
+ # @param theTokens [Array] The input tokens
59
+ # @param theChildren [Array] Children nodes (one per rhs symbol)
60
+ def new_parent_node(aProduction, aRange, theTokens, theChildren)
61
+ node = case aProduction.name
62
+ when 'expression[0]' # rule 'expression' => 'simple_expression'
63
+ return_first_child(aRange, theTokens, theChildren)
64
+
65
+ when 'simple_expression[0]' # rule 'simple_expression' => 'term'
66
+ return_first_child(aRange, theTokens, theChildren)
67
+
68
+ when 'simple_expression[1]'
69
+ # rule 'simple_expression' => %w[simple_expression add_operator term]
70
+ reduce_simple_expression_1(aProduction, aRange, theTokens, theChildren)
71
+
72
+ when 'term[0]' # rule 'term' => 'factor'
73
+ return_first_child(aRange, theTokens, theChildren)
74
+
75
+ when 'term[1]' # rule 'term' => %w[term mul_operator factor]
76
+ reduce_term_1(aProduction, aRange, theTokens, theChildren)
77
+
78
+ when 'factor[0]' # rule 'factor' => 'NUMBER'
79
+ return_first_child(aRange, theTokens, theChildren)
80
+
81
+ when 'factor[1]' # rule 'factor' => %w[LPAREN expression RPAREN]
82
+ return_second_child(aRange, theTokens, theChildren)
83
+
84
+ when 'add_operator[0]' # rule 'add_operator' => 'PLUS'
85
+ reduce_add_operator_0(aProduction, aRange, theTokens, theChildren)
86
+
87
+ when 'add_operator[1]' # rule 'add_operator' => 'MINUS'
88
+ reduce_add_operator_1(aProduction, aRange, theTokens, theChildren)
89
+
90
+ when 'mul_operator[0]' # rule 'mul_operator' => 'STAR'
91
+ reduce_mul_operator_0(aProduction, aRange, theTokens, theChildren)
92
+
93
+ when 'mul_operator[1]' # rule 'mul_operator' => 'DIVIDE'
94
+ reduce_mul_operator_1(aProduction, aRange, theTokens, theChildren)
95
+
96
+ else
97
+ raise StandardError, "Don't know production #{aProduction.name}"
98
+ end
99
+
100
+ return node
101
+ end
102
+
103
+ def reduce_binary_operator(theChildren)
104
+ operator_node = theChildren[1]
105
+ operator_node.children << theChildren[0]
106
+ operator_node.children << theChildren[2]
107
+ return operator_node
108
+ end
109
+
110
+ # rule 'simple_expression' => %w[simple_expression add_operator term]
111
+ def reduce_simple_expression_1(aProduction, aRange, theTokens, theChildren)
112
+ reduce_binary_operator(theChildren)
113
+ end
114
+
115
+
116
+ # rule 'term' => %w[term mul_operator factor]
117
+ def reduce_term_1(aProduction, aRange, theTokens, theChildren)
118
+ reduce_binary_operator(theChildren)
119
+ end
120
+
121
+ # rule 'add_operator' => 'PLUS'
122
+ def reduce_add_operator_0(aProduction, aRange, theTokens, theChildren)
123
+ return CalcAddNode.new(theChildren[0].symbol)
124
+ end
125
+
126
+ # rule 'add_operator' => 'MINUS'
127
+ def reduce_add_operator_1(aProduction, aRange, theTokens, theChildren)
128
+ return CalcSubtractNode.new(theChildren[0].symbol)
129
+ end
130
+
131
+ # rule 'mul_operator' => 'STAR'
132
+ def reduce_mul_operator_0(aProduction, aRange, theTokens, theChildren)
133
+ return CalcMultiplyNode.new(theChildren[0].symbol)
134
+ end
135
+
136
+ # rule 'mul_operator' => 'DIVIDE'
137
+ def reduce_mul_operator_1(aProduction, aRange, theTokens, theChildren)
138
+ return CalcDivideNode.new(theChildren[0].symbol)
139
+ end
140
+
141
+
142
+ end # class