rley 0.5.01 → 0.5.02

Sign up to get free protection for your applications and to get access to all the features.
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