Class: Antelope::Ace::Compiler
- Inherits:
-
Object
- Object
- Antelope::Ace::Compiler
- Defined in:
- lib/antelope/ace/compiler.rb
Overview
Compiles a set of tokens generated by Scanner. These tokens may not nessicarily have been generated by Scanner, however the tokens must follow the same rules even still.
A list of all tokens that this compiler accepts:
:directive
(2 arguments):copy
(1 argument):second
(no arguments):label
(2 arguments):part
(2 arguments):or
(no arguments):prec
(1 argument):block
(1 argument):third
(no arguments):body
(1 argument)
The tokens are handled by methods that follow the rule
compile_<token name>
.
Instance Attribute Summary collapse
-
#body ⇒ String
The body of the output compiler.
-
#options ⇒ Hash
Options defined by directives in the first part of the file.
-
#rules ⇒ Array<Hash>
A list of all the rules that are defined in the file.
Class Method Summary collapse
-
.compile(tokens) ⇒ Compiler
Creates a compiler, and then runs the compiler.
Instance Method Summary collapse
-
#compare_versions(required) ⇒ void
private
Compares the required version and the Antelope version.
-
#compile ⇒ self
Runs the compiler on the input tokens.
-
#compile_block(block) ⇒ void
Compiles a block.
-
#compile_copy(body) ⇒ void
Compiles a copy token.
-
#compile_directive(name, args) ⇒ void
Compiles a directive.
- #compile_extra(name, args) ⇒ Object
-
#compile_label(label, val) ⇒ void
Compiles a label.
-
#compile_or ⇒ void
Compiles an or.
-
#compile_part(text, val) ⇒ Object
Compiles a part.
-
#compile_prec(prec) ⇒ void
Compiles the precedence operator.
-
#compile_second ⇒ void
Sets the state to the second part.
-
#compile_third ⇒ void
Sets the state to the third part.
- #handle_token(args) ⇒ Object private
-
#initialize(tokens) ⇒ Compiler
constructor
Initialize the compiler.
-
#require_state!(*state) ⇒ void
private
Checks the current state against the given states.
Constructor Details
#initialize(tokens) ⇒ Compiler
Initialize the compiler. The compiler keeps track of a state;
this state is basically which part of the file we're in. The
state can be :first
, :second
, or :third
; some tokens
may not exist in certain states.
88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 |
# File 'lib/antelope/ace/compiler.rb', line 88 def initialize(tokens) @tokens = tokens @body = "" @state = :first @rules = [] @current = nil @current_label = nil @options = { :terminals => [], :nonterminals => [], :prec => [], :type => nil, :extra => Hashie::Extensions::IndifferentAccess. inject!({}) } end |
Instance Attribute Details
#body ⇒ String
The body of the output compiler. This should be formatted in the language that the parser is to be written in. Some output generators may have special syntax that allows the parser to be put in the body; see the output generators for more.
35 36 37 |
# File 'lib/antelope/ace/compiler.rb', line 35 def body @body end |
#options ⇒ Hash
Options defined by directives in the first part of the file.
:terminals
(Array<Symbol, String?>)
— A list of all of the terminals in the language. If this is not properly defined, the grammar will throw an error saying that a symbol used in the grammar is not defined.:prec
(Array<(Symbol, Array<Symbol>)>
) — A list of the precedence rules of the grammar. The first element of each element is the type of precedence (and should be any of:left
,:right
, or:nonassoc
), and the second element should be the symbols that are on that level.:type
(String
) — The type of generator to generate; this should be a language.:extra
(Hash<Symbol, Array<Object>>
) — Extra options that are not defined here.
70 71 72 |
# File 'lib/antelope/ace/compiler.rb', line 70 def @options end |
#rules ⇒ Array<Hash>
A list of all the rules that are defined in the file. The rules are defined as such:
label
(Symbol
) — The left-hand side of the rule; this is the nonterminal that the right side reduces to.set
(Array<Symbol>
) — The right-hand side of the rule. This is a combination of terminals and nonterminals.block
(String
) — The code to be run on a reduction. this should be formatted in the language that the output parser is written in. Optional; default value is""
.prec
(String
) — The precedence level for the rule. This should be a nonterminal or terminal. Optional; default value is""
.
52 53 54 |
# File 'lib/antelope/ace/compiler.rb', line 52 def rules @rules end |
Class Method Details
.compile(tokens) ⇒ Compiler
Creates a compiler, and then runs the compiler.
77 78 79 |
# File 'lib/antelope/ace/compiler.rb', line 77 def self.compile(tokens) new(tokens).compile end |
Instance Method Details
#compare_versions(required) ⇒ void (private)
This method returns an undefined value.
Compares the required version and the Antelope version.
322 323 324 325 326 327 328 329 330 331 |
# File 'lib/antelope/ace/compiler.rb', line 322 def compare_versions(required) antelope_version = Gem::Version.new(Antelope::VERSION) required_version = Gem::Requirement.new(required) unless required_version =~ antelope_version raise IncompatibleVersionError, "Grammar requires #{required}, " \ "have #{Antelope::VERSION}" end end |
#compile ⇒ self
Runs the compiler on the input tokens. For each token,
it calls compile_<type>
with <type>
being the first
element of the token, with the remaining part of the array
passed as arguments.
118 119 120 121 122 123 124 |
# File 'lib/antelope/ace/compiler.rb', line 118 def compile @tokens.each do |token| send(:"compile_#{token[0]}", *token[1..-1]) end self end |
#compile_block(block) ⇒ void
This method returns an undefined value.
Compiles a block. This should only occur in a rule definition, and in the second part. It sets the block on the current rule.
273 274 275 276 |
# File 'lib/antelope/ace/compiler.rb', line 273 def compile_block(block) require_state! :second @current[:block] = block end |
#compile_copy(body) ⇒ void
This method returns an undefined value.
Compiles a copy token. A copy token basically copies its argument directly into the body. Used in both the first and third parts.
197 198 199 200 |
# File 'lib/antelope/ace/compiler.rb', line 197 def compile_copy(body) require_state! :first, :third @body << body end |
#compile_directive(name, args) ⇒ void
This method returns an undefined value.
Compiles a directive. This may only be triggered in the first section of the file. The directive accepts two arguments. The directive name can be any of the following:
:terminal
— adds a terminal. Requires 1-2 arguments; the first argument is the terminal name, and the second argument is a string that can represent the terminal.:require
— requires a certain version of Antelope. Requires 1 argument. If the first argument is a version greater than the current version of Antelope, it raises an error.:left
— creates a new precedence level, with the argument values being the symbols. The precedence level is left associative.:right
— creates a new precedence level, with the argument valeus being the symbols. The precedence level is right associative.:nonassoc
— creates a nre precedence level, with the argument values being the symbols. The precedence level is nonassociative.:type
— the type of parser to generate. This should correspond to the output language of the parser.
157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 |
# File 'lib/antelope/ace/compiler.rb', line 157 def compile_directive(name, args) require_state! :first name = name.intern case name when :terminal, :token handle_token(args) when :require compare_versions(args[0]) when :left, :right, :nonassoc [:prec] << [name, *args.map(&:intern)] when :language, :generator, :"grammar.type" [:type] = args[0].downcase when :type raise SyntaxError, "%type directive requires first " \ "argument to be caret" unless args[0].caret? [:nonterminals] << [args[0], args[1..-1].map(&:intern)] when :define compile_extra(args[0], args[1..-1]) else compile_extra(name, args) end end |
#compile_extra(name, args) ⇒ Object
182 183 184 185 186 187 188 189 |
# File 'lib/antelope/ace/compiler.rb', line 182 def compile_extra(name, args) matching = Generator.directives[name.to_s] raise NoDirectiveError, "no directive named #{name}" \ unless matching [:extra][name] = args end |
#compile_label(label, val) ⇒ void
This method returns an undefined value.
Compiles a label. This starts a rule definition. The token
should only exist in the second part. A rule definition
occurs by setting the @current_label
to the first argument,
and @current
to a blank rule save the label set. If a
rule definition was already in progress, it is completed.
218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 |
# File 'lib/antelope/ace/compiler.rb', line 218 def compile_label(label, val) require_state! :second if @current @rules << @current end label = label.intern @current_label = [label, val] @current = { label: label, label_id: val, set: [], block: "", prec: "" } end |
#compile_or ⇒ void
This method returns an undefined value.
Compiles an or. This should only occur in a rule definition, and in the second part. It starts a new rule definition by calling #compile_label with the current label.
252 253 254 |
# File 'lib/antelope/ace/compiler.rb', line 252 def compile_or compile_label(*@current_label) end |
#compile_part(text, val) ⇒ Object
Compiles a part. This should only occur during a rule definition. The token should only exist in the second part. It adds the first argument to the set of the current rule.
241 242 243 244 |
# File 'lib/antelope/ace/compiler.rb', line 241 def compile_part(text, val) require_state! :second @current[:set] << [text.intern, val] end |
#compile_prec(prec) ⇒ void
This method returns an undefined value.
Compiles the precedence operator. This should only occur in a rule definition, and in the second part. It sets the precedence definition on the current rule.
262 263 264 265 |
# File 'lib/antelope/ace/compiler.rb', line 262 def compile_prec(prec) require_state! :second @current[:prec] = prec end |
#compile_second ⇒ void
This method returns an undefined value.
Sets the state to the second part.
205 206 207 |
# File 'lib/antelope/ace/compiler.rb', line 205 def compile_second @state = :second end |
#compile_third ⇒ void
This method returns an undefined value.
Sets the state to the third part. If a rule definition was in progress, it finishes the rule.
282 283 284 285 286 287 288 289 |
# File 'lib/antelope/ace/compiler.rb', line 282 def compile_third if @current @rules << @current @current_label = @current = nil end @state = :third end |
#handle_token(args) ⇒ Object (private)
293 294 295 296 297 298 299 300 301 302 303 |
# File 'lib/antelope/ace/compiler.rb', line 293 def handle_token(args) type = "" if args[0].caret? type = args.shift end name = args.shift value = args.shift [:terminals] << [name.intern, type, nil, value] end |
#require_state!(*state) ⇒ void (private)
This method returns an undefined value.
Checks the current state against the given states.
310 311 312 313 314 315 |
# File 'lib/antelope/ace/compiler.rb', line 310 def require_state!(*state) raise InvalidStateError, "In state #{@state}, " \ "required state #{state.join(", ")}" \ unless state.include?(@state) end |