1 # Copyright (C) 2005-2009, Parrot Foundation.
6 TGE::Compiler - A compiler for the grammar syntax of TGE.
12 .namespace [ 'TGE'; 'Compiler' ]
15 $P0 = get_class [ 'TGE'; 'Grammar' ]
16 $P1 = subclass $P0, [ 'TGE'; 'Compiler' ]
21 Take the source string for a tree grammar, and return a sensible data
26 .sub parse_grammar :method
29 # Parse the source string and build a match tree
32 start_rule = get_hll_global ['TGE';'Parser'], "start"
33 match = start_rule(source, 'grammar'=>'TGE::Parser')
35 unless match goto err_parse # if parse fails, stop
36 # say 'parse succeeded'
37 # say 'Match tree dump:'
38 # load_bytecode "dumper.pbc"
39 # load_bytecode "PGE/Dumper.pbc"
40 # '_dumper'(match, "match")
42 # Transform the parse tree and return the result
44 tree_match = self.'apply'(match)
45 $P5 = tree_match.'get'('result')
46 # say 'Data structure dump:'
47 # '_dumper'($P5, "syntax tree")
51 print "Unable to parse the tree grammar.\n"
56 .sub init :vtable :method
57 self.'add_rule'("ROOT", "result", ".", "ROOT_result")
58 self.'add_rule'("statements", "result", ".", "statements_result")
59 self.'add_rule'("statement", "result", ".", "statement_result")
60 self.'add_rule'("transrule", "result", ".", "transrule_result")
61 self.'add_rule'("grammardec", "result", ".", "grammardec_result")
62 self.'add_rule'("type", "value", ".", "type_value")
63 self.'add_rule'("inherit", "value", ".", "inherit_value")
64 self.'add_rule'("name", "value", ".", "name_value")
65 self.'add_rule'("parent", "value", ".", "parent_value")
66 self.'add_rule'("action", "value", ".", "action_value")
67 self.'add_rule'("language", "value", ".", "language_value")
70 .sub ROOT_result :method
73 $I0 = exists node["TGE::Parser::statements"]
74 unless $I0 goto err_no_tree
75 $P0 = node["TGE::Parser::statements"]
76 $P2 = tree.'get'('result', $P0, 'statements')
80 print "Top-level rule did not match.\n"
84 .sub statements_result :method
88 statements = new 'ResizablePMCArray'
90 # Iterate over the list of statements, and generate a processed tree for
91 # each statement. Return an array of all the processed statements.
93 it = iter node # loop over the array
95 unless it goto loop_end
97 $P2 = tree.'get'('result', $P1, 'statement')
104 print "This grammar contained no statements.\n"
108 .sub statement_result :method
115 it = iter $P0 # setup iterator for node
117 unless it, iter_end # while (entries) ...
118 shift $S1, it # get the key of the iterator
121 result = tree.'get'('result', $P2, $S1)
129 .sub transrule_result :method
137 it = iter $P0 # setup iterator for node
139 unless it, iter_end # while (entries) ...
141 shift $S1, it # get the key of the iterator
144 $P3 = tree.'get'('value', $P2, $S1)
150 $I0 = defined rule["parent"]
151 if $I0 goto parent_defined
154 rule["build"] = "rule"
158 print "Unable to find all the components of a rule definition\n"
163 .sub grammardec_result :method
171 it = iter $P0 # setup iterator for node
173 unless it, iter_end # while (entries) ...
175 shift $S1, it # get the key of the iterator
178 $P3 = tree.'get'('value', $P2, $S1)
183 decl["build"] = "grammar"
187 # The attribute 'value' on nodes of type 'inherit'.
188 .sub inherit_value :method
194 value = tree.'get'('value', $P2, 'type')
198 # The attribute 'value' on nodes of type 'type'.
199 .sub type_value :method
209 # The attribute 'value' on nodes of type 'name'.
210 .sub name_value :method
221 # The attribute 'value' on nodes of type 'parent'.
222 .sub parent_value :method
234 # The attribute 'value' on nodes of type 'action'.
235 .sub action_value :method
238 .local pmc value, infile
240 value = new 'CodeString'
241 infile = get_global '$!infile'
243 (lineno) = $P2.'line_number'()
244 value.'emit'('#line %0 %1', lineno, infile)
249 # The attribute 'value' on nodes of type 'language'.
250 # (This will be refactored out to a general syntax for modifiers.)
251 .sub language_value :method
265 Compile a grammar from a source string.
269 .sub 'precompile' :method
271 .param string infile :optional
272 .param int has_infile :opt_flag
274 .local string outstring
275 .local string header_string
277 if has_infile goto quote_infile
281 infile = concat '"', infile
286 set_global '$!infile', $P0
288 # Unnamed grammars are class 'AnonGrammar'
289 .local string grammarname
290 grammarname = 'AnonGrammar'
291 rule_data = self.'parse_grammar'(source)
293 # Construct grammar rules from the data structure of rule info
296 it = iter rule_data # loop over the rule info
298 unless it goto loop_end
300 $S0 = statement['build']
301 unless $S0 == 'rule' goto grammar_build
302 $S1 = self.'rule_string'(statement)
304 $S2 = self.'rule_header'(statement)
308 $S1 = self.'grammar_string'(statement)
310 grammarname = statement['type']
314 outstring .= "\n.sub init :vtable :method\n"
315 outstring .= header_string
316 outstring .= "\n.end\n"
318 .return (outstring, grammarname)
321 .sub 'compile' :method
325 compiler = compreg "PIR"
328 .local string grammarname
330 .local pmc new_grammar
332 (code, grammarname) = self.'precompile'(source)
334 unless grammarname == 'AnonGrammar' goto named_grammar
336 $P2['type'] = 'AnonGrammar'
337 $P2['inherit'] = 'TGE::Grammar'
338 $S1 = self.'grammar_string'($P2)
341 libloader = compiler(code)
344 new_grammar = new grammarname
345 .return (new_grammar)
348 .sub 'rule_header' :method
356 parent = rule["parent"]
357 output = " self.'add_rule'('"
371 .sub 'rule_string' :method
380 code .= "' :method\n"
381 code .= " .param pmc tree\n"
382 code .= " .param pmc node\n"
389 # NOTE - this code assumes that a type of '' is impossible
390 # (in older versions of Parrot, it was)
392 .sub 'grammar_string' :method
396 .local string inherit
397 type = grammar["type"]
398 inherit = grammar["inherit"]
399 .local string inherit_key, type_key
400 inherit_key = self.'classname_key'(inherit)
401 type_key = self.'classname_key'(type)
403 code = "\n.namespace"
407 code .= ".sub '__onload' :load :init\n"
408 code .= " load_bytecode 'TGE.pbc'\n"
409 code .= " push_eh class_loaded\n"
410 code .= " $P1 = subclass "
415 code .= " class_loaded:\n"
421 .sub 'classname_key' :method
425 parts = split '::', name
427 # If splitting on '::' doesn't break down name, try splitting on ';'.
429 if $I0 > 1 goto build_key
430 parts = split ';', name
434 $S0 = join "'; '", parts
444 # vim: expandtab shiftwidth=4 ft=pir: