antelope 0.1.8 → 0.1.9
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/.yardopts +2 -0
- data/CONTRIBUTING.md +4 -4
- data/GENERATORS.md +61 -19
- data/README.md +84 -9
- data/TODO.md +58 -0
- data/examples/deterministic.ace +21 -9
- data/examples/example.ace +16 -10
- data/examples/example.output +213 -146
- data/examples/simple.ace +1 -1
- data/lib/antelope/ace/compiler.rb +52 -15
- data/lib/antelope/ace/errors.rb +7 -0
- data/lib/antelope/ace/grammar/generation.rb +3 -3
- data/lib/antelope/ace/grammar/precedences.rb +5 -7
- data/lib/antelope/ace/grammar/productions.rb +36 -11
- data/lib/antelope/ace/grammar/{terminals.rb → symbols.rb} +25 -2
- data/lib/antelope/ace/grammar.rb +12 -3
- data/lib/antelope/ace/precedence.rb +4 -0
- data/lib/antelope/ace/scanner/argument.rb +57 -0
- data/lib/antelope/ace/scanner/first.rb +32 -6
- data/lib/antelope/ace/scanner/second.rb +23 -8
- data/lib/antelope/ace/scanner.rb +32 -26
- data/lib/antelope/ace/token.rb +21 -2
- data/lib/antelope/cli.rb +22 -2
- data/lib/antelope/generation/constructor/first.rb +1 -1
- data/lib/antelope/generation/constructor.rb +2 -0
- data/lib/antelope/generation/null.rb +13 -0
- data/lib/antelope/generation/recognizer/rule.rb +4 -3
- data/lib/antelope/generation/recognizer/state.rb +18 -3
- data/lib/antelope/generation/recognizer.rb +19 -24
- data/lib/antelope/generation/tableizer.rb +30 -2
- data/lib/antelope/generation.rb +1 -0
- data/lib/antelope/generator/base.rb +150 -13
- data/lib/antelope/generator/c.rb +11 -0
- data/lib/antelope/generator/c_header.rb +105 -0
- data/lib/antelope/generator/c_source.rb +39 -0
- data/lib/antelope/generator/null.rb +5 -0
- data/lib/antelope/generator/output.rb +3 -3
- data/lib/antelope/generator/ruby.rb +23 -5
- data/lib/antelope/generator/templates/c_header.ant +36 -0
- data/lib/antelope/generator/templates/c_source.ant +202 -0
- data/lib/antelope/generator/templates/output.ant +68 -0
- data/lib/antelope/generator/templates/ruby.ant +146 -0
- data/lib/antelope/generator.rb +15 -3
- data/lib/antelope/template/compiler.rb +78 -0
- data/lib/antelope/template/errors.rb +9 -0
- data/lib/antelope/template/scanner.rb +111 -0
- data/lib/antelope/template.rb +60 -0
- data/lib/antelope/version.rb +1 -1
- data/lib/antelope.rb +1 -0
- data/spec/antelope/template_spec.rb +39 -0
- data/subl/Ace (Ruby).JSON-tmLanguage +94 -0
- data/subl/Ace (Ruby).tmLanguage +153 -0
- metadata +21 -8
- data/examples/deterministic.output +0 -131
- data/examples/simple.output +0 -121
- data/lib/antelope/generator/templates/output.erb +0 -56
- data/lib/antelope/generator/templates/ruby.erb +0 -63
data/lib/antelope/ace/token.rb
CHANGED
@@ -35,14 +35,30 @@ module Antelope
|
|
35
35
|
# @return [Recognizer::State]
|
36
36
|
attr_accessor :to
|
37
37
|
|
38
|
+
# The type of the token. This is given by a caret argument to
|
39
|
+
# the grammar. This is primarily used for generators.
|
40
|
+
#
|
41
|
+
# @return [String]
|
42
|
+
attr_accessor :type
|
43
|
+
|
44
|
+
attr_accessor :id
|
45
|
+
|
38
46
|
# Initialize.
|
39
47
|
#
|
40
48
|
# @param name [Symbol] the name of the token.
|
49
|
+
# @param type [String?] the type of the token. For definitions,
|
50
|
+
# this is the given type of the token (for typed language
|
51
|
+
# output).
|
52
|
+
# @param id [String?] the id of the token in the production.
|
53
|
+
# For some languages, this allows references to the token via
|
54
|
+
# the id.
|
41
55
|
# @param value [String?] the value of the token. This is only
|
42
56
|
# used in output representation to the developer.
|
43
|
-
def initialize(name, value = nil)
|
57
|
+
def initialize(name, type = nil, id = nil, value = nil)
|
44
58
|
@name = name
|
45
59
|
@value = value
|
60
|
+
@type = type
|
61
|
+
@id = id
|
46
62
|
@from = nil
|
47
63
|
@to = nil
|
48
64
|
end
|
@@ -110,6 +126,9 @@ module Antelope
|
|
110
126
|
buf
|
111
127
|
end
|
112
128
|
|
129
|
+
# Returns a nice inspect.
|
130
|
+
#
|
131
|
+
# @return [String]
|
113
132
|
def inspect
|
114
133
|
"#<#{self.class} from=#{from.id if from} to=#{to.id if to} " \
|
115
134
|
"name=#{name.inspect} value=#{@value.inspect}>"
|
@@ -149,7 +168,7 @@ module Antelope
|
|
149
168
|
#
|
150
169
|
# @return [Token]
|
151
170
|
def without_transitions
|
152
|
-
self.class.new(name, @value)
|
171
|
+
self.class.new(name, @type, @id, @value)
|
153
172
|
end
|
154
173
|
|
155
174
|
# Generates a hash for this class.
|
data/lib/antelope/cli.rb
CHANGED
@@ -3,6 +3,8 @@
|
|
3
3
|
require "thor"
|
4
4
|
|
5
5
|
module Antelope
|
6
|
+
|
7
|
+
# Handles the command line interface.
|
6
8
|
class CLI < Thor
|
7
9
|
|
8
10
|
class_option :verbose, default: false, type: :boolean
|
@@ -10,19 +12,37 @@ module Antelope
|
|
10
12
|
option :type, default: nil, type: :string,
|
11
13
|
desc: "The type of generator to use"
|
12
14
|
desc "compile FILE [FILE]*", "compile the given files"
|
15
|
+
|
16
|
+
# Compile.
|
13
17
|
def compile(*files)
|
14
18
|
files.each do |file|
|
15
19
|
compile_file(file)
|
16
20
|
end
|
17
21
|
end
|
18
22
|
|
23
|
+
desc "check FILE [FILE]*", "check the syntax of the given files"
|
24
|
+
|
25
|
+
# Check.
|
26
|
+
def check(*files)
|
27
|
+
files.each do |file|
|
28
|
+
compile_file(file, [Generator::Null])
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
19
32
|
private
|
20
33
|
|
21
|
-
|
34
|
+
# Compiles the given file, and then generates. If an error
|
35
|
+
# occurs, it prints it out to stderr, along with a backtrace if
|
36
|
+
# the verbose flag was set.
|
37
|
+
#
|
38
|
+
# @param file [String] the file to compile.
|
39
|
+
# @param gen [Array, Symbol] the generator to use.
|
40
|
+
# @return [void]
|
41
|
+
def compile_file(file, gen = :guess)
|
22
42
|
puts "Compiling #{file}... "
|
23
43
|
|
24
44
|
grammar = Ace::Grammar.from_file(file)
|
25
|
-
grammar.generate(options)
|
45
|
+
grammar.generate(options, gen)
|
26
46
|
|
27
47
|
rescue => e
|
28
48
|
$stderr.puts "Error while compiling: #{e.class}: #{e.message}"
|
@@ -16,7 +16,7 @@ module Antelope
|
|
16
16
|
# Constructs the first set for a given token. This is how
|
17
17
|
# the method should behave:
|
18
18
|
#
|
19
|
-
# FIRST(ε) == [] # if
|
19
|
+
# FIRST(ε) == [] # if ε is the epsilon token
|
20
20
|
# FIRST(x) == [x] # if x is a terminal
|
21
21
|
# FIRST(αβ) == if nullable?(α)
|
22
22
|
# FIRST(α) U FIRST(β)
|
@@ -63,6 +63,7 @@ module Antelope
|
|
63
63
|
production.items = []
|
64
64
|
|
65
65
|
current_state = state
|
66
|
+
old_state = state
|
66
67
|
|
67
68
|
production.label.from = state
|
68
69
|
production.label.to = state.transitions[rule.left.name]
|
@@ -78,6 +79,7 @@ module Antelope
|
|
78
79
|
|
79
80
|
production.items << new_item
|
80
81
|
|
82
|
+
old_state = current_state
|
81
83
|
current_state = transition
|
82
84
|
end
|
83
85
|
|
@@ -168,8 +168,9 @@ module Antelope
|
|
168
168
|
# @return [Numeric]
|
169
169
|
def ===(other)
|
170
170
|
if other.is_a? Rule
|
171
|
-
left === other.left and right.
|
172
|
-
|
171
|
+
left === other.left and right.size == other.right.size and
|
172
|
+
right.each_with_index.
|
173
|
+
all? { |e, i| e === other.right[i] }
|
173
174
|
else
|
174
175
|
super
|
175
176
|
end
|
@@ -203,7 +204,7 @@ module Antelope
|
|
203
204
|
# @private
|
204
205
|
# @return [Array<(Ace::Token::Nonterminal, Array<Ace::Token>, Numeric)>]
|
205
206
|
def to_a
|
206
|
-
[left, right, position]
|
207
|
+
[left, right, position]
|
207
208
|
end
|
208
209
|
end
|
209
210
|
end
|
@@ -86,10 +86,15 @@ module Antelope
|
|
86
86
|
# @param rule [State, Rule] the object to append.
|
87
87
|
# @return [self]
|
88
88
|
def <<(rule)
|
89
|
-
|
89
|
+
case rule
|
90
|
+
when State
|
90
91
|
rule.rules.map(&:clone).each { |r| self << r }
|
91
|
-
|
92
|
+
when Rule
|
92
93
|
rules << rule unless rules.include? rule
|
94
|
+
when Array, Set
|
95
|
+
rule.each do |part|
|
96
|
+
self << part
|
97
|
+
end
|
93
98
|
else
|
94
99
|
raise ArgumentError, "Expected #{State} or #{Rule}, " \
|
95
100
|
"got #{rule.class}"
|
@@ -100,11 +105,21 @@ module Antelope
|
|
100
105
|
|
101
106
|
alias_method :push, :<<
|
102
107
|
|
108
|
+
# Check to see if this state is fuzzily equivalent to another
|
109
|
+
# state. It does this by checking if the transitions are
|
110
|
+
# equivalent, and then that the rules are fuzzily equivalent.
|
111
|
+
# Ideally, the method is commutative; that is,
|
112
|
+
# `(a === b) == (b === a)`.
|
113
|
+
#
|
114
|
+
# @param other [State] the state to check.
|
115
|
+
# @return [Boolean]
|
116
|
+
# @see Rule#===
|
103
117
|
def ===(other)
|
104
118
|
return super unless other.is_a? State
|
105
119
|
|
106
120
|
other_rules = other.rules.to_a
|
107
|
-
other.transitions == transitions
|
121
|
+
other.transitions == transitions &&
|
122
|
+
rules.size == other_rules.size &&
|
108
123
|
rules.each_with_index.
|
109
124
|
all? { |rule, i| rule === other_rules[i] }
|
110
125
|
end
|
@@ -90,21 +90,7 @@ module Antelope
|
|
90
90
|
def compute_states
|
91
91
|
fixed_point(states) do
|
92
92
|
states.dup.each do |state|
|
93
|
-
state
|
94
|
-
next unless rule.succ?
|
95
|
-
transitional = find_state_for(rule.succ) do |succ|
|
96
|
-
ns = State.new << succ
|
97
|
-
compute_closure(ns)
|
98
|
-
@map[succ] = ns
|
99
|
-
end
|
100
|
-
|
101
|
-
if state.transitions[rule.active.name]
|
102
|
-
state.transitions[rule.active.name].merge! transitional
|
103
|
-
else
|
104
|
-
states << transitional
|
105
|
-
state.transitions[rule.active.name] = transitional
|
106
|
-
end
|
107
|
-
end
|
93
|
+
compute_gotos(state)
|
108
94
|
end
|
109
95
|
end
|
110
96
|
end
|
@@ -124,18 +110,27 @@ module Antelope
|
|
124
110
|
end
|
125
111
|
end
|
126
112
|
|
127
|
-
|
113
|
+
def compute_gotos(state)
|
114
|
+
actives = state.rules.map(&:active).select(&:name).to_set
|
115
|
+
|
116
|
+
actives.each do |active|
|
117
|
+
next if state.transitions[active.name]
|
118
|
+
rules = state.rules.
|
119
|
+
select { |r| r.active == active && r.succ? }.
|
120
|
+
map(&:succ).to_set
|
121
|
+
s = states.find { |st| rules <= st.rules } || begin
|
122
|
+
s = State.new << rules
|
123
|
+
compute_closure(s)
|
124
|
+
states << s
|
125
|
+
s
|
126
|
+
end
|
128
127
|
|
129
|
-
|
130
|
-
|
131
|
-
# @param rule [Rule]
|
132
|
-
# @yield [rule]
|
133
|
-
# @return [State]
|
134
|
-
def find_state_for(rule, &block)
|
135
|
-
#states.find { |state| state.include?(rule) } or yield(rule)
|
136
|
-
@map.fetch(rule) { block.call(rule) }
|
128
|
+
state.transitions[active.name] = s
|
129
|
+
end
|
137
130
|
end
|
138
131
|
|
132
|
+
private
|
133
|
+
|
139
134
|
# Changes the IDs of the states into a more friendly format.
|
140
135
|
#
|
141
136
|
# @return [void]
|
@@ -38,6 +38,7 @@ module Antelope
|
|
38
38
|
def call
|
39
39
|
tablize
|
40
40
|
conflictize
|
41
|
+
defaultize
|
41
42
|
end
|
42
43
|
|
43
44
|
# Construct a table based on the grammar. The table itself is
|
@@ -67,7 +68,8 @@ module Antelope
|
|
67
68
|
end
|
68
69
|
|
69
70
|
if rule.production.id.zero?
|
70
|
-
table[state.id][
|
71
|
+
table[state.id][:$end] =
|
72
|
+
[[:accept, rule.production.id]]
|
71
73
|
end
|
72
74
|
end
|
73
75
|
end
|
@@ -94,7 +96,7 @@ module Antelope
|
|
94
96
|
|
95
97
|
terminal = grammar.precedence_for(on)
|
96
98
|
|
97
|
-
rule_part, other_part = data.sort_by { |(t,
|
99
|
+
rule_part, other_part = data.sort_by { |(t, _)| t }
|
98
100
|
|
99
101
|
unless other_part[0] == :state
|
100
102
|
$stderr.puts \
|
@@ -121,6 +123,32 @@ module Antelope
|
|
121
123
|
end
|
122
124
|
end
|
123
125
|
end
|
126
|
+
|
127
|
+
# Reduce many transitions into a single `$default` transition.
|
128
|
+
# This only works if there is no `$empty` transition; if there
|
129
|
+
# is an `$empty` transition, then the `$default` transition is
|
130
|
+
# set to be the `$empty` transition.
|
131
|
+
#
|
132
|
+
# @return [void]
|
133
|
+
def defaultize
|
134
|
+
max = @table.map { |s| s.keys.size }.max
|
135
|
+
@table.each_with_index do |state|
|
136
|
+
if state.key?(:$empty)
|
137
|
+
state[:$default] = state[:$empty]
|
138
|
+
else
|
139
|
+
common = state.group_by { |k, v| v }.values.
|
140
|
+
sort_by(&:size).first
|
141
|
+
|
142
|
+
if common.size > (max / 2)
|
143
|
+
action = common[0][1]
|
144
|
+
|
145
|
+
keys = common.map(&:first)
|
146
|
+
state.delete_if { |k, _| keys.include?(k) }
|
147
|
+
state[:$default] = action
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
124
152
|
end
|
125
153
|
end
|
126
154
|
end
|
data/lib/antelope/generation.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'hashie/mash'
|
2
|
+
|
1
3
|
module Antelope
|
2
4
|
module Generator
|
3
5
|
|
@@ -10,6 +12,7 @@ module Antelope
|
|
10
12
|
# @abstract Subclass and redefine {#generate} to create a
|
11
13
|
# generator.
|
12
14
|
class Base
|
15
|
+
Boolean = Object.new
|
13
16
|
# The modifiers that were applied to the grammar.
|
14
17
|
#
|
15
18
|
# @return [Hash<(Symbol, Object)>]
|
@@ -37,6 +40,43 @@ module Antelope
|
|
37
40
|
Generator.register_generator(self, *names)
|
38
41
|
end
|
39
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
|
+
|
40
80
|
# Initialize the generator.
|
41
81
|
#
|
42
82
|
# @param grammar [Grammar]
|
@@ -57,6 +97,93 @@ module Antelope
|
|
57
97
|
|
58
98
|
protected
|
59
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
|
+
|
60
187
|
# Copies a template from the source, runs it through erb (in the
|
61
188
|
# context of this class), and then outputs it at the destination.
|
62
189
|
# If given a block, it will call the block after the template is
|
@@ -71,18 +198,22 @@ module Antelope
|
|
71
198
|
# @yieldreturn [String] The new content to write to the output.
|
72
199
|
# @return [void]
|
73
200
|
def template(source, destination)
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
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)
|
86
217
|
end
|
87
218
|
end
|
88
219
|
|
@@ -99,7 +230,11 @@ module Antelope
|
|
99
230
|
#
|
100
231
|
# @return [Array<Hash<Symbol => Array<(Symbol, Numeric)>>>]
|
101
232
|
def table
|
102
|
-
mods[:tableizer].
|
233
|
+
if mods[:tableizer].is_a? Generation::Tableizer
|
234
|
+
mods[:tableizer].table
|
235
|
+
else
|
236
|
+
[]
|
237
|
+
end
|
103
238
|
end
|
104
239
|
|
105
240
|
# Returns an array of the production information of each
|
@@ -122,6 +257,8 @@ module Antelope
|
|
122
257
|
production[:block]]
|
123
258
|
end
|
124
259
|
end
|
260
|
+
|
261
|
+
|
125
262
|
end
|
126
263
|
end
|
127
264
|
end
|
@@ -0,0 +1,105 @@
|
|
1
|
+
module Antelope
|
2
|
+
module Generator
|
3
|
+
class CHeader < Base
|
4
|
+
|
5
|
+
register_as "c-header", "c_header"
|
6
|
+
|
7
|
+
has_directive "union", Array[String, String]
|
8
|
+
has_directive "api.prefix", String
|
9
|
+
has_directive "api.push-pull", String
|
10
|
+
has_directive "api.value.type", String
|
11
|
+
has_directive "api.token.prefix", String
|
12
|
+
has_directive "parse-param", Array
|
13
|
+
has_directive "lex-param", Array
|
14
|
+
has_directive "param", Array
|
15
|
+
|
16
|
+
def push?
|
17
|
+
directives.api.push_pull == "push"
|
18
|
+
end
|
19
|
+
|
20
|
+
def define_stype?
|
21
|
+
!!directives.union[0] && !directives.api.value.type
|
22
|
+
end
|
23
|
+
|
24
|
+
def lex_params
|
25
|
+
params = [directives.lex_param, directives.param].compact.
|
26
|
+
flatten
|
27
|
+
|
28
|
+
if params.any?
|
29
|
+
", " << params.join(", ")
|
30
|
+
else
|
31
|
+
""
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def parse_params
|
36
|
+
[directives.parse_param, directives.param].compact.flatten.
|
37
|
+
join(", ")
|
38
|
+
end
|
39
|
+
|
40
|
+
def params
|
41
|
+
if directives.param
|
42
|
+
directives.param.join(", ")
|
43
|
+
else
|
44
|
+
""
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def stype
|
49
|
+
prefix.upcase << if directives.api.value.type
|
50
|
+
directives.api.value.type
|
51
|
+
elsif directives.union.size > 1
|
52
|
+
directives.union[0]
|
53
|
+
else
|
54
|
+
"STYPE"
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def union_body
|
59
|
+
directives.union.last
|
60
|
+
end
|
61
|
+
|
62
|
+
def terminal_type
|
63
|
+
"int" # for now
|
64
|
+
end
|
65
|
+
|
66
|
+
def token_prefix
|
67
|
+
if directives.api.token.prefix
|
68
|
+
directives.api.token.prefix
|
69
|
+
elsif directives.api.prefix
|
70
|
+
prefix.upcase
|
71
|
+
else
|
72
|
+
""
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def prefix
|
77
|
+
if directives.api.prefix
|
78
|
+
directives.api.prefix
|
79
|
+
else
|
80
|
+
"yy"
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def upper_prefix
|
85
|
+
prefix.upcase
|
86
|
+
end
|
87
|
+
|
88
|
+
def symbols
|
89
|
+
@_symbols ||= begin
|
90
|
+
sym = grammar.terminals.map(&:name) + grammar.nonterminals
|
91
|
+
nums = sym.each_with_index.map { |v, i| [v, i + 257] }
|
92
|
+
Hash[nums]
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def guard_name
|
97
|
+
"#{prefix.upcase}#{file.gsub(/[\W]/, "_").upcase}"
|
98
|
+
end
|
99
|
+
|
100
|
+
def generate
|
101
|
+
template "c_header", "#{file}.h"
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module Antelope
|
2
|
+
module Generator
|
3
|
+
class CSource < CHeader
|
4
|
+
|
5
|
+
def action_for(state)
|
6
|
+
out = ""
|
7
|
+
|
8
|
+
grammar.terminals.each do |terminal|
|
9
|
+
action = state[terminal.name]
|
10
|
+
|
11
|
+
if action.size == 2 && action[0] == :state
|
12
|
+
out << "#{action[1] + 1}, "
|
13
|
+
elsif action.size == 2 &&
|
14
|
+
[:reduce, :accept].include?(action[0])
|
15
|
+
if $DEBUG
|
16
|
+
out << "#{prefix.upcase}STATES + #{action[1] + 1}, "
|
17
|
+
else
|
18
|
+
out << "#{table.size + action[1] + 1}, "
|
19
|
+
end
|
20
|
+
else
|
21
|
+
out << "0, "
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
|
26
|
+
out.chomp(", ")
|
27
|
+
end
|
28
|
+
|
29
|
+
def cify_block(block)
|
30
|
+
block.gsub(/\$([0-9]+)/, "#{prefix}vals[\\1]")
|
31
|
+
.gsub(/\$\$/, "#{prefix}out")
|
32
|
+
end
|
33
|
+
|
34
|
+
def generate
|
35
|
+
template "c_source", "#{file}.c"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|