antelope 0.2.0 → 0.2.2
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.
- checksums.yaml +4 -4
- data/.gitignore +25 -23
- data/.rspec +3 -3
- data/.travis.yml +10 -9
- data/.yardopts +7 -7
- data/CONTRIBUTING.md +38 -38
- data/GENERATORS.md +124 -124
- data/Gemfile +7 -7
- data/LICENSE.txt +22 -22
- data/README.md +104 -104
- data/Rakefile +2 -2
- data/TODO.md +58 -58
- data/antelope.gemspec +28 -28
- data/bin/antelope +7 -7
- data/examples/deterministic.ace +35 -35
- data/examples/example.ace +51 -50
- data/examples/example.err +192 -0
- data/examples/{example.output → example.inf} +384 -385
- data/examples/liquidscript.ace +233 -162
- data/examples/simple.ace +22 -22
- data/lib/antelope/ace/compiler.rb +334 -334
- data/lib/antelope/ace/errors.rb +48 -48
- data/lib/antelope/ace/grammar/generation.rb +80 -80
- data/lib/antelope/ace/grammar/loading.rb +53 -53
- data/lib/antelope/ace/grammar/precedences.rb +68 -65
- data/lib/antelope/ace/grammar/productions.rb +156 -150
- data/lib/antelope/ace/grammar/symbols.rb +66 -66
- data/lib/antelope/ace/grammar.rb +69 -69
- data/lib/antelope/ace/precedence.rb +61 -61
- data/lib/antelope/ace/production.rb +57 -57
- data/lib/antelope/ace/scanner/argument.rb +57 -57
- data/lib/antelope/ace/scanner/first.rb +89 -89
- data/lib/antelope/ace/scanner/second.rb +177 -177
- data/lib/antelope/ace/scanner/third.rb +27 -27
- data/lib/antelope/ace/scanner.rb +134 -134
- data/lib/antelope/ace/token/epsilon.rb +24 -24
- data/lib/antelope/ace/token/error.rb +26 -26
- data/lib/antelope/ace/token/nonterminal.rb +17 -17
- data/lib/antelope/ace/token/terminal.rb +17 -17
- data/lib/antelope/ace/token.rb +238 -238
- data/lib/antelope/ace.rb +53 -53
- data/lib/antelope/cli.rb +55 -55
- data/lib/antelope/errors.rb +8 -8
- data/lib/antelope/generation/constructor/first.rb +88 -88
- data/lib/antelope/generation/constructor/follow.rb +103 -103
- data/lib/antelope/generation/constructor/nullable.rb +64 -64
- data/lib/antelope/generation/constructor.rb +126 -126
- data/lib/antelope/generation/errors.rb +17 -17
- data/lib/antelope/generation/null.rb +13 -13
- data/lib/antelope/generation/recognizer/rule.rb +216 -216
- data/lib/antelope/generation/recognizer/state.rb +130 -130
- data/lib/antelope/generation/recognizer.rb +180 -180
- data/lib/antelope/generation/tableizer.rb +175 -154
- data/lib/antelope/generation.rb +15 -15
- data/lib/antelope/generator/base.rb +264 -264
- data/lib/antelope/generator/c.rb +11 -11
- data/lib/antelope/generator/c_header.rb +105 -105
- data/lib/antelope/generator/c_source.rb +39 -39
- data/lib/antelope/generator/error.rb +34 -0
- data/lib/antelope/generator/group.rb +57 -57
- data/lib/antelope/generator/html.rb +51 -0
- data/lib/antelope/generator/info.rb +47 -0
- data/lib/antelope/generator/null.rb +18 -18
- data/lib/antelope/generator/output.rb +17 -49
- data/lib/antelope/generator/ruby.rb +79 -79
- data/lib/antelope/generator/templates/c_header.ant +36 -36
- data/lib/antelope/generator/templates/c_source.ant +202 -202
- data/lib/antelope/generator/templates/error.ant +33 -0
- data/lib/antelope/generator/templates/html/antelope.css +1 -0
- data/lib/antelope/generator/templates/html/antelope.html +1 -0
- data/lib/antelope/generator/templates/html/antelope.js +1 -0
- data/lib/antelope/generator/templates/html/css.ant +53 -0
- data/lib/antelope/generator/templates/html/html.ant +82 -0
- data/lib/antelope/generator/templates/html/js.ant +9 -0
- data/lib/antelope/generator/templates/info.ant +53 -0
- data/lib/antelope/generator/templates/ruby.ant +178 -146
- data/lib/antelope/generator.rb +66 -63
- data/lib/antelope/template/compiler.rb +78 -78
- data/lib/antelope/template/errors.rb +9 -9
- data/lib/antelope/template/scanner.rb +109 -109
- data/lib/antelope/template.rb +65 -60
- data/lib/antelope/version.rb +6 -6
- data/lib/antelope.rb +13 -13
- data/optimizations.txt +42 -0
- data/spec/antelope/ace/compiler_spec.rb +60 -60
- data/spec/antelope/ace/scanner_spec.rb +27 -27
- data/spec/antelope/constructor_spec.rb +133 -136
- data/spec/antelope/template_spec.rb +50 -49
- data/spec/fixtures/simple.ace +22 -22
- data/spec/spec_helper.rb +39 -39
- data/spec/support/benchmark_helper.rb +5 -5
- data/spec/support/grammar_helper.rb +15 -15
- data/subl/Ace (Ruby).JSON-tmLanguage +94 -94
- data/subl/Ace (Ruby).tmLanguage +153 -153
- metadata +17 -6
- data/lib/antelope/generator/templates/output.ant +0 -68
@@ -1,264 +1,264 @@
|
|
1
|
-
require 'hashie/mash'
|
2
|
-
|
3
|
-
module Antelope
|
4
|
-
module Generator
|
5
|
-
|
6
|
-
# Generates a parser. This is normally the parent class, and the
|
7
|
-
# specific implementations inherit from this. The generated
|
8
|
-
# parser should, ideally, be completely independent (not requiring
|
9
|
-
# any external source code), as well as be under a permissive
|
10
|
-
# license.
|
11
|
-
#
|
12
|
-
# @abstract Subclass and redefine {#generate} to create a
|
13
|
-
# generator.
|
14
|
-
class Base
|
15
|
-
Boolean = Object.new
|
16
|
-
# The modifiers that were applied to the grammar.
|
17
|
-
#
|
18
|
-
# @return [Hash<(Symbol, Object)>]
|
19
|
-
attr_reader :mods
|
20
|
-
|
21
|
-
# The file name (not including the extension) that the grammar
|
22
|
-
# should output to.
|
23
|
-
#
|
24
|
-
# @return [String]
|
25
|
-
attr_reader :file
|
26
|
-
|
27
|
-
# The grammar that the generator is for.
|
28
|
-
#
|
29
|
-
# @return [Ace::Grammar]
|
30
|
-
attr_reader :grammar
|
31
|
-
|
32
|
-
# The source root directory for templates. Overwrite to change.
|
33
|
-
#
|
34
|
-
# @return [Pathname]
|
35
|
-
def self.source_root
|
36
|
-
Pathname.new("../templates").expand_path(__FILE__)
|
37
|
-
end
|
38
|
-
|
39
|
-
def self.register_as(*names)
|
40
|
-
Generator.register_generator(self, *names)
|
41
|
-
end
|
42
|
-
|
43
|
-
# Called by ruby on subclassing.
|
44
|
-
#
|
45
|
-
# @param subclass [Class]
|
46
|
-
# @return [void]
|
47
|
-
def self.inherited(subclass)
|
48
|
-
directives.each do |name, (_, type)|
|
49
|
-
subclass.has_directive(name, type)
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
|
-
# Allows a directive for this generator. This is checked in
|
54
|
-
# the compiler to allow the option. If the compiler encounters
|
55
|
-
# a bad directive, it'll error (to give the developer a warning).
|
56
|
-
#
|
57
|
-
# @param directive [Symbol, String]
|
58
|
-
# @param type [Object] used to define how the value should be
|
59
|
-
# coerced.
|
60
|
-
# @see #directives
|
61
|
-
# @see #coerce_directive_value
|
62
|
-
# @return [void]
|
63
|
-
def self.has_directive(directive, type = nil)
|
64
|
-
directive = directive.to_s
|
65
|
-
directives[directive] = [self, type]
|
66
|
-
end
|
67
|
-
|
68
|
-
# The directives in the class.
|
69
|
-
#
|
70
|
-
# @see .has_directive
|
71
|
-
# @return [Hash]
|
72
|
-
def self.directives
|
73
|
-
@_directives ||= {}
|
74
|
-
end
|
75
|
-
|
76
|
-
class << self
|
77
|
-
alias_method :has_directives, :has_directive
|
78
|
-
end
|
79
|
-
|
80
|
-
# Initialize the generator.
|
81
|
-
#
|
82
|
-
# @param grammar [Grammar]
|
83
|
-
# @param mods [Hash<(Symbol, Object)>]
|
84
|
-
def initialize(grammar, mods)
|
85
|
-
@file = grammar.name
|
86
|
-
@grammar = grammar
|
87
|
-
@mods = mods
|
88
|
-
end
|
89
|
-
|
90
|
-
# Actually does the generation. A subclass should implement this.
|
91
|
-
#
|
92
|
-
# @raise [NotImplementedError]
|
93
|
-
# @return [void]
|
94
|
-
def generate
|
95
|
-
raise NotImplementedError
|
96
|
-
end
|
97
|
-
|
98
|
-
protected
|
99
|
-
|
100
|
-
# Retrieves all directives from the grammar, and giving them the
|
101
|
-
# proper values for this instance.
|
102
|
-
#
|
103
|
-
# @see .has_directive
|
104
|
-
# @see #coerce_directive_value
|
105
|
-
# @return [Hash]
|
106
|
-
def directives
|
107
|
-
@_directives ||= begin
|
108
|
-
hash = Hashie::Mash.new
|
109
|
-
|
110
|
-
self.class.directives.each do |key, dict|
|
111
|
-
value = [grammar.options.key?(key), grammar.options[key]]
|
112
|
-
hash.deep_merge! coerce_nested_hash(key,
|
113
|
-
coerce_directive_value(*value, dict[1]))
|
114
|
-
end
|
115
|
-
|
116
|
-
hash
|
117
|
-
end
|
118
|
-
end
|
119
|
-
|
120
|
-
def coerce_nested_hash(key, value)
|
121
|
-
parts = key.split('.').map { |p| p.gsub(/-/, "_") }
|
122
|
-
top = {}
|
123
|
-
hash = top
|
124
|
-
parts.each_with_index do |part, i|
|
125
|
-
hash[part] = if parts.last == part
|
126
|
-
value
|
127
|
-
else
|
128
|
-
{}
|
129
|
-
end
|
130
|
-
hash = hash[part]
|
131
|
-
end
|
132
|
-
|
133
|
-
top[key] = value
|
134
|
-
top
|
135
|
-
end
|
136
|
-
|
137
|
-
# Coerce the given directive value to the given type. For the
|
138
|
-
# type `nil`, it checks the size of the values; for no values,
|
139
|
-
# it returns true; for one value, it returns that one value; for
|
140
|
-
# any other size value, it returns the values. For the type
|
141
|
-
# `Boolean`, if no values were given, or if the first value isn't
|
142
|
-
# "false", it returns true. For the type `:single` (or `:one`),
|
143
|
-
# it returns the first value. For the type `Array`, it returns
|
144
|
-
# the values. For any other type that is a class, it tries to
|
145
|
-
# initialize the class with the given arguments.
|
146
|
-
def coerce_directive_value(defined, values, type)
|
147
|
-
return nil unless defined || Array === type
|
148
|
-
case type
|
149
|
-
when nil
|
150
|
-
case values.size
|
151
|
-
when 0
|
152
|
-
true
|
153
|
-
when 1
|
154
|
-
values[0]
|
155
|
-
else
|
156
|
-
values
|
157
|
-
end
|
158
|
-
when :single, :one
|
159
|
-
values[0]
|
160
|
-
when Boolean
|
161
|
-
# For bool, if there were no arguments, then return true;
|
162
|
-
# otherwise, if the first argument isn't "false", return
|
163
|
-
# true.
|
164
|
-
|
165
|
-
values[0].to_s != "false"
|
166
|
-
when Array
|
167
|
-
values.zip(type).map do |value, t|
|
168
|
-
coerce_directive_value(defined, [value], t)
|
169
|
-
end
|
170
|
-
when Class
|
171
|
-
if type == Array
|
172
|
-
values
|
173
|
-
elsif type == String
|
174
|
-
values[0].to_s
|
175
|
-
elsif [Fixnum, Integer, Numeric].include?(type)
|
176
|
-
values[0].to_i
|
177
|
-
elsif type == Float
|
178
|
-
values[0].to_f
|
179
|
-
else
|
180
|
-
type.new(*values)
|
181
|
-
end
|
182
|
-
else
|
183
|
-
raise UnknownTypeError, "unknown type #{type}"
|
184
|
-
end
|
185
|
-
end
|
186
|
-
|
187
|
-
# Copies a template from the source, runs it through erb (in the
|
188
|
-
# context of this class), and then outputs it at the destination.
|
189
|
-
# If given a block, it will call the block after the template is
|
190
|
-
# run through erb with the content from erb; the result of the
|
191
|
-
# block is then used as the content instead.
|
192
|
-
#
|
193
|
-
# @param source [String] the source file. This should be in
|
194
|
-
# {.source_root}.
|
195
|
-
# @param destination [String] the destination file. This will be
|
196
|
-
# in {Ace::Grammar#output}.
|
197
|
-
# @yieldparam [String] content The content that ERB created.
|
198
|
-
# @yieldreturn [String] The new content to write to the output.
|
199
|
-
# @return [void]
|
200
|
-
def template(source, destination)
|
201
|
-
src = Pathname.new("#{source}.ant").
|
202
|
-
expand_path(self.class.source_root)
|
203
|
-
|
204
|
-
template = Template.new(src)
|
205
|
-
content = template.result(instance_eval('binding'))
|
206
|
-
content.gsub!(/[ \t]+\n/, "\n")
|
207
|
-
|
208
|
-
if block_given?
|
209
|
-
content = yield content
|
210
|
-
end
|
211
|
-
|
212
|
-
dest = Pathname.new(destination).
|
213
|
-
expand_path(grammar.output)
|
214
|
-
|
215
|
-
dest.open("w") do |file|
|
216
|
-
file.write(content)
|
217
|
-
end
|
218
|
-
end
|
219
|
-
|
220
|
-
# The actual table that is used for parsing. This returns an
|
221
|
-
# array of hashes; the array index corresponds to the state
|
222
|
-
# number, and the hash keys correspond to the lookahead tokens.
|
223
|
-
# The hash values are an array; the first element of that array
|
224
|
-
# is the action to be taken, and the second element of the
|
225
|
-
# array is the argument for that action. Possible actions
|
226
|
-
# include `:accept`, `:reduce`, and `:state`; `:accept` means
|
227
|
-
# to accept the string; `:reduce` means to perform the given
|
228
|
-
# reduction; and `:state` means to transition to the given
|
229
|
-
# state.
|
230
|
-
#
|
231
|
-
# @return [Array<Hash<Symbol => Array<(Symbol, Numeric)>>>]
|
232
|
-
def table
|
233
|
-
if mods[:tableizer].is_a? Generation::Tableizer
|
234
|
-
mods[:tableizer].table
|
235
|
-
else
|
236
|
-
[]
|
237
|
-
end
|
238
|
-
end
|
239
|
-
|
240
|
-
# Returns an array of the production information of each
|
241
|
-
# production needed by the parser. The first element of any
|
242
|
-
# element in the array is an {Ace::Token::Nonterminal} that
|
243
|
-
# that specific production reduces to; the second element
|
244
|
-
# is a number describing the number of items in the right hand
|
245
|
-
# side of the production; the string represents the action
|
246
|
-
# that should be taken on reduction.
|
247
|
-
#
|
248
|
-
# This information is used for `:reduce` actions in the parser;
|
249
|
-
# the value of the `:reduce` action corresponds to the array
|
250
|
-
# index of the production in this array.
|
251
|
-
#
|
252
|
-
# @return [Array<Array<(Ace::Token::Nonterminal, Numeric, String)>]
|
253
|
-
def productions
|
254
|
-
grammar.all_productions.map do |production|
|
255
|
-
[production[:label],
|
256
|
-
production[:items].size,
|
257
|
-
production[:block]]
|
258
|
-
end
|
259
|
-
end
|
260
|
-
|
261
|
-
|
262
|
-
end
|
263
|
-
end
|
264
|
-
end
|
1
|
+
require 'hashie/mash'
|
2
|
+
|
3
|
+
module Antelope
|
4
|
+
module Generator
|
5
|
+
|
6
|
+
# Generates a parser. This is normally the parent class, and the
|
7
|
+
# specific implementations inherit from this. The generated
|
8
|
+
# parser should, ideally, be completely independent (not requiring
|
9
|
+
# any external source code), as well as be under a permissive
|
10
|
+
# license.
|
11
|
+
#
|
12
|
+
# @abstract Subclass and redefine {#generate} to create a
|
13
|
+
# generator.
|
14
|
+
class Base
|
15
|
+
Boolean = Object.new
|
16
|
+
# The modifiers that were applied to the grammar.
|
17
|
+
#
|
18
|
+
# @return [Hash<(Symbol, Object)>]
|
19
|
+
attr_reader :mods
|
20
|
+
|
21
|
+
# The file name (not including the extension) that the grammar
|
22
|
+
# should output to.
|
23
|
+
#
|
24
|
+
# @return [String]
|
25
|
+
attr_reader :file
|
26
|
+
|
27
|
+
# The grammar that the generator is for.
|
28
|
+
#
|
29
|
+
# @return [Ace::Grammar]
|
30
|
+
attr_reader :grammar
|
31
|
+
|
32
|
+
# The source root directory for templates. Overwrite to change.
|
33
|
+
#
|
34
|
+
# @return [Pathname]
|
35
|
+
def self.source_root
|
36
|
+
Pathname.new("../templates").expand_path(__FILE__)
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.register_as(*names)
|
40
|
+
Generator.register_generator(self, *names)
|
41
|
+
end
|
42
|
+
|
43
|
+
# Called by ruby on subclassing.
|
44
|
+
#
|
45
|
+
# @param subclass [Class]
|
46
|
+
# @return [void]
|
47
|
+
def self.inherited(subclass)
|
48
|
+
directives.each do |name, (_, type)|
|
49
|
+
subclass.has_directive(name, type)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
# Allows a directive for this generator. This is checked in
|
54
|
+
# the compiler to allow the option. If the compiler encounters
|
55
|
+
# a bad directive, it'll error (to give the developer a warning).
|
56
|
+
#
|
57
|
+
# @param directive [Symbol, String]
|
58
|
+
# @param type [Object] used to define how the value should be
|
59
|
+
# coerced.
|
60
|
+
# @see #directives
|
61
|
+
# @see #coerce_directive_value
|
62
|
+
# @return [void]
|
63
|
+
def self.has_directive(directive, type = nil)
|
64
|
+
directive = directive.to_s
|
65
|
+
directives[directive] = [self, type]
|
66
|
+
end
|
67
|
+
|
68
|
+
# The directives in the class.
|
69
|
+
#
|
70
|
+
# @see .has_directive
|
71
|
+
# @return [Hash]
|
72
|
+
def self.directives
|
73
|
+
@_directives ||= {}
|
74
|
+
end
|
75
|
+
|
76
|
+
class << self
|
77
|
+
alias_method :has_directives, :has_directive
|
78
|
+
end
|
79
|
+
|
80
|
+
# Initialize the generator.
|
81
|
+
#
|
82
|
+
# @param grammar [Grammar]
|
83
|
+
# @param mods [Hash<(Symbol, Object)>]
|
84
|
+
def initialize(grammar, mods)
|
85
|
+
@file = grammar.name
|
86
|
+
@grammar = grammar
|
87
|
+
@mods = mods
|
88
|
+
end
|
89
|
+
|
90
|
+
# Actually does the generation. A subclass should implement this.
|
91
|
+
#
|
92
|
+
# @raise [NotImplementedError]
|
93
|
+
# @return [void]
|
94
|
+
def generate
|
95
|
+
raise NotImplementedError
|
96
|
+
end
|
97
|
+
|
98
|
+
protected
|
99
|
+
|
100
|
+
# Retrieves all directives from the grammar, and giving them the
|
101
|
+
# proper values for this instance.
|
102
|
+
#
|
103
|
+
# @see .has_directive
|
104
|
+
# @see #coerce_directive_value
|
105
|
+
# @return [Hash]
|
106
|
+
def directives
|
107
|
+
@_directives ||= begin
|
108
|
+
hash = Hashie::Mash.new
|
109
|
+
|
110
|
+
self.class.directives.each do |key, dict|
|
111
|
+
value = [grammar.options.key?(key), grammar.options[key]]
|
112
|
+
hash.deep_merge! coerce_nested_hash(key,
|
113
|
+
coerce_directive_value(*value, dict[1]))
|
114
|
+
end
|
115
|
+
|
116
|
+
hash
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
def coerce_nested_hash(key, value)
|
121
|
+
parts = key.split('.').map { |p| p.gsub(/-/, "_") }
|
122
|
+
top = {}
|
123
|
+
hash = top
|
124
|
+
parts.each_with_index do |part, i|
|
125
|
+
hash[part] = if parts.last == part
|
126
|
+
value
|
127
|
+
else
|
128
|
+
{}
|
129
|
+
end
|
130
|
+
hash = hash[part]
|
131
|
+
end
|
132
|
+
|
133
|
+
top[key] = value
|
134
|
+
top
|
135
|
+
end
|
136
|
+
|
137
|
+
# Coerce the given directive value to the given type. For the
|
138
|
+
# type `nil`, it checks the size of the values; for no values,
|
139
|
+
# it returns true; for one value, it returns that one value; for
|
140
|
+
# any other size value, it returns the values. For the type
|
141
|
+
# `Boolean`, if no values were given, or if the first value isn't
|
142
|
+
# "false", it returns true. For the type `:single` (or `:one`),
|
143
|
+
# it returns the first value. For the type `Array`, it returns
|
144
|
+
# the values. For any other type that is a class, it tries to
|
145
|
+
# initialize the class with the given arguments.
|
146
|
+
def coerce_directive_value(defined, values, type)
|
147
|
+
return nil unless defined || Array === type
|
148
|
+
case type
|
149
|
+
when nil
|
150
|
+
case values.size
|
151
|
+
when 0
|
152
|
+
true
|
153
|
+
when 1
|
154
|
+
values[0]
|
155
|
+
else
|
156
|
+
values
|
157
|
+
end
|
158
|
+
when :single, :one
|
159
|
+
values[0]
|
160
|
+
when Boolean
|
161
|
+
# For bool, if there were no arguments, then return true;
|
162
|
+
# otherwise, if the first argument isn't "false", return
|
163
|
+
# true.
|
164
|
+
|
165
|
+
values[0].to_s != "false"
|
166
|
+
when Array
|
167
|
+
values.zip(type).map do |value, t|
|
168
|
+
coerce_directive_value(defined, [value], t)
|
169
|
+
end
|
170
|
+
when Class
|
171
|
+
if type == Array
|
172
|
+
values
|
173
|
+
elsif type == String
|
174
|
+
values[0].to_s
|
175
|
+
elsif [Fixnum, Integer, Numeric].include?(type)
|
176
|
+
values[0].to_i
|
177
|
+
elsif type == Float
|
178
|
+
values[0].to_f
|
179
|
+
else
|
180
|
+
type.new(*values)
|
181
|
+
end
|
182
|
+
else
|
183
|
+
raise UnknownTypeError, "unknown type #{type}"
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
# Copies a template from the source, runs it through erb (in the
|
188
|
+
# context of this class), and then outputs it at the destination.
|
189
|
+
# If given a block, it will call the block after the template is
|
190
|
+
# run through erb with the content from erb; the result of the
|
191
|
+
# block is then used as the content instead.
|
192
|
+
#
|
193
|
+
# @param source [String] the source file. This should be in
|
194
|
+
# {.source_root}.
|
195
|
+
# @param destination [String] the destination file. This will be
|
196
|
+
# in {Ace::Grammar#output}.
|
197
|
+
# @yieldparam [String] content The content that ERB created.
|
198
|
+
# @yieldreturn [String] The new content to write to the output.
|
199
|
+
# @return [void]
|
200
|
+
def template(source, destination)
|
201
|
+
src = Pathname.new("#{source}.ant").
|
202
|
+
expand_path(self.class.source_root)
|
203
|
+
|
204
|
+
template = Template.new(src)
|
205
|
+
content = template.result(instance_eval('binding'))
|
206
|
+
content.gsub!(/[ \t]+\n/, "\n")
|
207
|
+
|
208
|
+
if block_given?
|
209
|
+
content = yield content
|
210
|
+
end
|
211
|
+
|
212
|
+
dest = Pathname.new(destination).
|
213
|
+
expand_path(grammar.output)
|
214
|
+
|
215
|
+
dest.open("w") do |file|
|
216
|
+
file.write(content)
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
# The actual table that is used for parsing. This returns an
|
221
|
+
# array of hashes; the array index corresponds to the state
|
222
|
+
# number, and the hash keys correspond to the lookahead tokens.
|
223
|
+
# The hash values are an array; the first element of that array
|
224
|
+
# is the action to be taken, and the second element of the
|
225
|
+
# array is the argument for that action. Possible actions
|
226
|
+
# include `:accept`, `:reduce`, and `:state`; `:accept` means
|
227
|
+
# to accept the string; `:reduce` means to perform the given
|
228
|
+
# reduction; and `:state` means to transition to the given
|
229
|
+
# state.
|
230
|
+
#
|
231
|
+
# @return [Array<Hash<Symbol => Array<(Symbol, Numeric)>>>]
|
232
|
+
def table
|
233
|
+
if mods[:tableizer].is_a? Generation::Tableizer
|
234
|
+
mods[:tableizer].table
|
235
|
+
else
|
236
|
+
[]
|
237
|
+
end
|
238
|
+
end
|
239
|
+
|
240
|
+
# Returns an array of the production information of each
|
241
|
+
# production needed by the parser. The first element of any
|
242
|
+
# element in the array is an {Ace::Token::Nonterminal} that
|
243
|
+
# that specific production reduces to; the second element
|
244
|
+
# is a number describing the number of items in the right hand
|
245
|
+
# side of the production; the string represents the action
|
246
|
+
# that should be taken on reduction.
|
247
|
+
#
|
248
|
+
# This information is used for `:reduce` actions in the parser;
|
249
|
+
# the value of the `:reduce` action corresponds to the array
|
250
|
+
# index of the production in this array.
|
251
|
+
#
|
252
|
+
# @return [Array<Array<(Ace::Token::Nonterminal, Numeric, String)>]
|
253
|
+
def productions
|
254
|
+
grammar.all_productions.map do |production|
|
255
|
+
[production[:label],
|
256
|
+
production[:items].size,
|
257
|
+
production[:block]]
|
258
|
+
end
|
259
|
+
end
|
260
|
+
|
261
|
+
|
262
|
+
end
|
263
|
+
end
|
264
|
+
end
|
data/lib/antelope/generator/c.rb
CHANGED
@@ -1,11 +1,11 @@
|
|
1
|
-
module Antelope
|
2
|
-
module Generator
|
3
|
-
class C < Group
|
4
|
-
register_as "c", "C"
|
5
|
-
|
6
|
-
register_generator CHeader, "c-header"
|
7
|
-
register_generator CSource, "c-source"
|
8
|
-
|
9
|
-
end
|
10
|
-
end
|
11
|
-
end
|
1
|
+
module Antelope
|
2
|
+
module Generator
|
3
|
+
class C < Group
|
4
|
+
register_as "c", "C"
|
5
|
+
|
6
|
+
register_generator CHeader, "c-header"
|
7
|
+
register_generator CSource, "c-source"
|
8
|
+
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|