File: | jdk/src/hotspot/share/adlc/adlparse.cpp |
Warning: | line 2783, column 7 Value stored to 'line' during its initialization is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* |
2 | * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. |
3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
4 | * |
5 | * This code is free software; you can redistribute it and/or modify it |
6 | * under the terms of the GNU General Public License version 2 only, as |
7 | * published by the Free Software Foundation. |
8 | * |
9 | * This code is distributed in the hope that it will be useful, but WITHOUT |
10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
12 | * version 2 for more details (a copy is included in the LICENSE file that |
13 | * accompanied this code). |
14 | * |
15 | * You should have received a copy of the GNU General Public License version |
16 | * 2 along with this work; if not, write to the Free Software Foundation, |
17 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
18 | * |
19 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
20 | * or visit www.oracle.com if you need additional information or have any |
21 | * questions. |
22 | * |
23 | */ |
24 | |
25 | // ADLPARSE.CPP - Architecture Description Language Parser |
26 | // Authors: Chris Vick and Mike Paleczny |
27 | #include "adlc.hpp" |
28 | |
29 | //----------------------------ADLParser---------------------------------------- |
30 | // Create a new ADL parser |
31 | ADLParser::ADLParser(FileBuff& buffer, ArchDesc& archDesc) |
32 | : _buf(buffer), _AD(archDesc), |
33 | _globalNames(archDesc.globalNames()) { |
34 | _AD._syntax_errs = _AD._semantic_errs = 0; // No errors so far this file |
35 | _AD._warnings = 0; // No warnings either |
36 | _curline = _ptr = NULL__null; // No pointers into buffer yet |
37 | |
38 | _preproc_depth = 0; |
39 | _preproc_not_taken = 0; |
40 | |
41 | // Delimit command-line definitions from in-file definitions: |
42 | _AD._preproc_list.add_signal(); |
43 | } |
44 | |
45 | //------------------------------~ADLParser------------------------------------- |
46 | // Delete an ADL parser. |
47 | ADLParser::~ADLParser() { |
48 | if (!_AD._quiet_mode) |
49 | fprintf(stderrstderr,"---------------------------- Errors and Warnings ----------------------------\n"); |
50 | #ifndef ASSERT1 |
51 | if (!_AD._quiet_mode) { |
52 | fprintf(stderrstderr, "**************************************************************\n"); |
53 | fprintf(stderrstderr, "***** WARNING: ASSERT is undefined, assertions disabled. *****\n"); |
54 | fprintf(stderrstderr, "**************************************************************\n"); |
55 | } |
56 | #endif |
57 | if( _AD._syntax_errs + _AD._semantic_errs + _AD._warnings == 0 ) { |
58 | if (!_AD._quiet_mode) |
59 | fprintf(stderrstderr,"No errors or warnings to report from phase-1 parse.\n" ); |
60 | } |
61 | else { |
62 | if( _AD._syntax_errs ) { // Any syntax errors? |
63 | fprintf(stderrstderr,"%s: Found %d syntax error", _buf._fp->_name, _AD._syntax_errs); |
64 | if( _AD._syntax_errs > 1 ) fprintf(stderrstderr,"s.\n\n"); |
65 | else fprintf(stderrstderr,".\n\n"); |
66 | } |
67 | if( _AD._semantic_errs ) { // Any semantic errors? |
68 | fprintf(stderrstderr,"%s: Found %d semantic error", _buf._fp->_name, _AD._semantic_errs); |
69 | if( _AD._semantic_errs > 1 ) fprintf(stderrstderr,"s.\n\n"); |
70 | else fprintf(stderrstderr,".\n\n"); |
71 | } |
72 | if( _AD._warnings ) { // Any warnings? |
73 | fprintf(stderrstderr,"%s: Found %d warning", _buf._fp->_name, _AD._warnings); |
74 | if( _AD._warnings > 1 ) fprintf(stderrstderr,"s.\n\n"); |
75 | else fprintf(stderrstderr,".\n\n"); |
76 | } |
77 | } |
78 | if (!_AD._quiet_mode) |
79 | fprintf(stderrstderr,"-----------------------------------------------------------------------------\n"); |
80 | _AD._TotalLines += linenum()-1; // -1 for overshoot in "nextline" routine |
81 | |
82 | // Write out information we have stored |
83 | // // UNIXism == fsync(stderr); |
84 | } |
85 | |
86 | //------------------------------parse------------------------------------------ |
87 | // Each top-level keyword should appear as the first non-whitespace on a line. |
88 | // |
89 | void ADLParser::parse() { |
90 | char *ident; |
91 | |
92 | // Iterate over the lines in the file buffer parsing Level 1 objects |
93 | for( next_line(); _curline != NULL__null; next_line()) { |
94 | _ptr = _curline; // Reset ptr to start of new line |
95 | skipws(); // Skip any leading whitespace |
96 | ident = get_ident(); // Get first token |
97 | if (ident == NULL__null) { // Empty line |
98 | continue; // Get the next line |
99 | } |
100 | if (!strcmp(ident, "instruct")) instr_parse(); |
101 | else if (!strcmp(ident, "operand")) oper_parse(); |
102 | else if (!strcmp(ident, "opclass")) opclass_parse(); |
103 | else if (!strcmp(ident, "ins_attrib")) ins_attr_parse(); |
104 | else if (!strcmp(ident, "op_attrib")) op_attr_parse(); |
105 | else if (!strcmp(ident, "source")) source_parse(); |
106 | else if (!strcmp(ident, "source_hpp")) source_hpp_parse(); |
107 | else if (!strcmp(ident, "register")) reg_parse(); |
108 | else if (!strcmp(ident, "frame")) frame_parse(); |
109 | else if (!strcmp(ident, "encode")) encode_parse(); |
110 | else if (!strcmp(ident, "pipeline")) pipe_parse(); |
111 | else if (!strcmp(ident, "definitions")) definitions_parse(); |
112 | else if (!strcmp(ident, "peephole")) peep_parse(); |
113 | else if (!strcmp(ident, "#line")) preproc_line(); |
114 | else if (!strcmp(ident, "#define")) preproc_define(); |
115 | else if (!strcmp(ident, "#undef")) preproc_undef(); |
116 | else { |
117 | parse_err(SYNERR1, "expected one of - instruct, operand, ins_attrib, op_attrib, source, register, pipeline, encode\n Found %s",ident); |
118 | } |
119 | } |
120 | // Add reg_class spill_regs after parsing. |
121 | RegisterForm *regBlock = _AD.get_registers(); |
122 | if (regBlock == NULL__null) { |
123 | parse_err(SEMERR2, "Did not declare 'register' definitions"); |
124 | } |
125 | regBlock->addSpillRegClass(); |
126 | regBlock->addDynamicRegClass(); |
127 | |
128 | // Done with parsing, check consistency. |
129 | |
130 | if (_preproc_depth != 0) { |
131 | parse_err(SYNERR1, "End of file inside #ifdef"); |
132 | } |
133 | |
134 | // AttributeForms ins_cost and op_cost must be defined for default behaviour |
135 | if (_globalNames[AttributeForm::_ins_cost] == NULL__null) { |
136 | parse_err(SEMERR2, "Did not declare 'ins_cost' attribute"); |
137 | } |
138 | if (_globalNames[AttributeForm::_op_cost] == NULL__null) { |
139 | parse_err(SEMERR2, "Did not declare 'op_cost' attribute"); |
140 | } |
141 | } |
142 | |
143 | // ******************** Private Level 1 Parse Functions ******************** |
144 | //------------------------------instr_parse------------------------------------ |
145 | // Parse the contents of an instruction definition, build the InstructForm to |
146 | // represent that instruction, and add it to the InstructForm list. |
147 | void ADLParser::instr_parse(void) { |
148 | char *ident; |
149 | InstructForm *instr; |
150 | MatchRule *rule; |
151 | int match_rules_cnt = 0; |
152 | |
153 | // First get the name of the instruction |
154 | if( (ident = get_unique_ident(_globalNames,"instruction")) == NULL__null ) |
155 | return; |
156 | instr = new InstructForm(ident); // Create new instruction form |
157 | instr->_linenum = linenum(); |
158 | _globalNames.Insert(ident, instr); // Add name to the name table |
159 | // Debugging Stuff |
160 | if (_AD._adl_debug > 1) |
161 | fprintf(stderrstderr,"Parsing Instruction Form %s\n", ident); |
162 | |
163 | // Then get the operands |
164 | skipws(); |
165 | if (_curchar != '(') { |
166 | parse_err(SYNERR1, "missing '(' in instruct definition\n"); |
167 | } |
168 | // Parse the operand list |
169 | else get_oplist(instr->_parameters, instr->_localNames); |
170 | skipws(); // Skip leading whitespace |
171 | // Check for block delimiter |
172 | if ( (_curchar != '%') |
173 | || ( next_char(), (_curchar != '{')) ) { |
174 | parse_err(SYNERR1, "missing '%%{' in instruction definition\n"); |
175 | return; |
176 | } |
177 | next_char(); // Maintain the invariant |
178 | do { |
179 | ident = get_ident(); // Grab next identifier |
180 | if (ident == NULL__null) { |
181 | parse_err(SYNERR1, "keyword identifier expected at %c\n", _curchar); |
182 | continue; |
183 | } |
184 | if (!strcmp(ident, "predicate")) instr->_predicate = pred_parse(); |
185 | else if (!strcmp(ident, "match")) { |
186 | // Allow one instruction have several match rules. |
187 | rule = instr->_matrule; |
188 | if (rule == NULL__null) { |
189 | // This is first match rule encountered |
190 | rule = match_parse(instr->_localNames); |
191 | if (rule) { |
192 | instr->_matrule = rule; |
193 | // Special case the treatment of Control instructions. |
194 | if( instr->is_ideal_control() ) { |
195 | // Control instructions return a special result, 'Universe' |
196 | rule->_result = "Universe"; |
197 | } |
198 | // Check for commutative operations with tree operands. |
199 | matchrule_clone_and_swap(rule, instr->_ident, match_rules_cnt); |
200 | } |
201 | } else { |
202 | // Find the end of the match rule list |
203 | while (rule->_next != NULL__null) |
204 | rule = rule->_next; |
205 | // Add the new match rule to the list |
206 | rule->_next = match_parse(instr->_localNames); |
207 | if (rule->_next) { |
208 | rule = rule->_next; |
209 | if( instr->is_ideal_control() ) { |
210 | parse_err(SYNERR1, "unique match rule expected for %s\n", rule->_name); |
211 | return; |
212 | } |
213 | assert(match_rules_cnt < 100," too many match rule clones"){ if (!(match_rules_cnt < 100)) { fprintf(stderr, "assert fails %s %d: %s\n" , "/home/daniel/Projects/java/jdk/src/hotspot/share/adlc/adlparse.cpp" , 213, " too many match rule clones"); abort(); }}; |
214 | char* buf = (char*) AllocateHeap(strlen(instr->_ident) + 4); |
215 | sprintf(buf, "%s_%d", instr->_ident, match_rules_cnt++); |
216 | rule->_result = buf; |
217 | // Check for commutative operations with tree operands. |
218 | matchrule_clone_and_swap(rule, instr->_ident, match_rules_cnt); |
219 | } |
220 | } |
221 | } |
222 | else if (!strcmp(ident, "encode")) { |
223 | parse_err(SYNERR1, "Instructions specify ins_encode, not encode\n"); |
224 | } |
225 | else if (!strcmp(ident, "ins_encode")) ins_encode_parse(*instr); |
226 | // Parse late expand keyword. |
227 | else if (!strcmp(ident, "postalloc_expand")) postalloc_expand_parse(*instr); |
228 | else if (!strcmp(ident, "opcode")) instr->_opcode = opcode_parse(instr); |
229 | else if (!strcmp(ident, "size")) instr->_size = size_parse(instr); |
230 | else if (!strcmp(ident, "effect")) effect_parse(instr); |
231 | else if (!strcmp(ident, "expand")) instr->_exprule = expand_parse(instr); |
232 | else if (!strcmp(ident, "rewrite")) instr->_rewrule = rewrite_parse(); |
233 | else if (!strcmp(ident, "constraint")) { |
234 | parse_err(SYNERR1, "Instructions do not specify a constraint\n"); |
235 | } |
236 | else if (!strcmp(ident, "construct")) { |
237 | parse_err(SYNERR1, "Instructions do not specify a construct\n"); |
238 | } |
239 | else if (!strcmp(ident, "format")) instr->_format = format_parse(); |
240 | else if (!strcmp(ident, "interface")) { |
241 | parse_err(SYNERR1, "Instructions do not specify an interface\n"); |
242 | } |
243 | else if (!strcmp(ident, "ins_pipe")) ins_pipe_parse(*instr); |
244 | else { // Done with staticly defined parts of instruction definition |
245 | // Check identifier to see if it is the name of an attribute |
246 | const Form *form = _globalNames[ident]; |
247 | AttributeForm *attr = form ? form->is_attribute() : NULL__null; |
248 | if (attr && (attr->_atype == INS_ATTR0)) { |
249 | // Insert the new attribute into the linked list. |
250 | Attribute *temp = attr_parse(ident); |
251 | temp->_next = instr->_attribs; |
252 | instr->_attribs = temp; |
253 | } else { |
254 | parse_err(SYNERR1, "expected one of:\n predicate, match, encode, or the name of" |
255 | " an instruction attribute at %s\n", ident); |
256 | } |
257 | } |
258 | skipws(); |
259 | } while(_curchar != '%'); |
260 | next_char(); |
261 | if (_curchar != '}') { |
262 | parse_err(SYNERR1, "missing '%%}' in instruction definition\n"); |
263 | return; |
264 | } |
265 | // Check for "Set" form of chain rule |
266 | adjust_set_rule(instr); |
267 | if (_AD._pipeline) { |
268 | // No pipe required for late expand. |
269 | if (instr->expands() || instr->postalloc_expands()) { |
270 | if (instr->_ins_pipe) { |
271 | parse_err(WARN0, "ins_pipe and expand rule both specified for instruction \"%s\";" |
272 | " ins_pipe will be unused\n", instr->_ident); |
273 | } |
274 | } else { |
275 | if (!instr->_ins_pipe) { |
276 | parse_err(WARN0, "No ins_pipe specified for instruction \"%s\"\n", instr->_ident); |
277 | } |
278 | } |
279 | } |
280 | // Add instruction to tail of instruction list |
281 | _AD.addForm(instr); |
282 | |
283 | // Create instruction form for each additional match rule |
284 | rule = instr->_matrule; |
285 | if (rule != NULL__null) { |
286 | rule = rule->_next; |
287 | while (rule != NULL__null) { |
288 | ident = (char*)rule->_result; |
289 | InstructForm *clone = new InstructForm(ident, instr, rule); // Create new instruction form |
290 | _globalNames.Insert(ident, clone); // Add name to the name table |
291 | // Debugging Stuff |
292 | if (_AD._adl_debug > 1) |
293 | fprintf(stderrstderr,"Parsing Instruction Form %s\n", ident); |
294 | // Check for "Set" form of chain rule |
295 | adjust_set_rule(clone); |
296 | // Add instruction to tail of instruction list |
297 | _AD.addForm(clone); |
298 | rule = rule->_next; |
299 | clone->_matrule->_next = NULL__null; // One match rule per clone |
300 | } |
301 | } |
302 | } |
303 | |
304 | //------------------------------matchrule_clone_and_swap----------------------- |
305 | // Check for commutative operations with subtree operands, |
306 | // create clones and swap operands. |
307 | void ADLParser::matchrule_clone_and_swap(MatchRule* rule, const char* instr_ident, int& match_rules_cnt) { |
308 | // Check for commutative operations with tree operands. |
309 | int count = 0; |
310 | rule->count_commutative_op(count); |
311 | if (count > 0) { |
312 | // Clone match rule and swap commutative operation's operands. |
313 | rule->matchrule_swap_commutative_op(instr_ident, count, match_rules_cnt); |
314 | } |
315 | } |
316 | |
317 | //------------------------------adjust_set_rule-------------------------------- |
318 | // Check for "Set" form of chain rule |
319 | void ADLParser::adjust_set_rule(InstructForm *instr) { |
320 | if (instr->_matrule == NULL__null || instr->_matrule->_rChild == NULL__null) return; |
321 | const char *rch = instr->_matrule->_rChild->_opType; |
322 | const Form *frm = _globalNames[rch]; |
323 | if( (! strcmp(instr->_matrule->_opType,"Set")) && |
324 | frm && frm->is_operand() && (! frm->ideal_only()) ) { |
325 | // Previous implementation, which missed leaP*, but worked for loadCon* |
326 | unsigned position = 0; |
327 | const char *result = NULL__null; |
328 | const char *name = NULL__null; |
329 | const char *optype = NULL__null; |
330 | MatchNode *right = instr->_matrule->_rChild; |
331 | if (right->base_operand(position, _globalNames, result, name, optype)) { |
332 | position = 1; |
333 | const char *result2 = NULL__null; |
334 | const char *name2 = NULL__null; |
335 | const char *optype2 = NULL__null; |
336 | // Can not have additional base operands in right side of match! |
337 | if ( ! right->base_operand( position, _globalNames, result2, name2, optype2) ) { |
338 | if (instr->_predicate != NULL__null) |
339 | parse_err(SYNERR1, "ADLC does not support instruction chain rules with predicates"); |
340 | // Chain from input _ideal_operand_type_, |
341 | // Needed for shared roots of match-trees |
342 | ChainList *lst = (ChainList *)_AD._chainRules[optype]; |
343 | if (lst == NULL__null) { |
344 | lst = new ChainList(); |
345 | _AD._chainRules.Insert(optype, lst); |
346 | } |
347 | if (!lst->search(instr->_matrule->_lChild->_opType)) { |
348 | const char *cost = instr->cost(); |
349 | if (cost == NULL__null) { |
350 | cost = ((AttributeForm*)_globalNames[AttributeForm::_ins_cost])->_attrdef; |
351 | } |
352 | // The ADLC does not support chaining from the ideal operand type |
353 | // of a predicated user-defined operand |
354 | if( frm->is_operand() == NULL__null || frm->is_operand()->_predicate == NULL__null ) { |
355 | lst->insert(instr->_matrule->_lChild->_opType,cost,instr->_ident); |
356 | } |
357 | } |
358 | // Chain from input _user_defined_operand_type_, |
359 | lst = (ChainList *)_AD._chainRules[result]; |
360 | if (lst == NULL__null) { |
361 | lst = new ChainList(); |
362 | _AD._chainRules.Insert(result, lst); |
363 | } |
364 | if (!lst->search(instr->_matrule->_lChild->_opType)) { |
365 | const char *cost = instr->cost(); |
366 | if (cost == NULL__null) { |
367 | cost = ((AttributeForm*)_globalNames[AttributeForm::_ins_cost])->_attrdef; |
368 | } |
369 | // It is safe to chain from the top-level user-defined operand even |
370 | // if it has a predicate, since the predicate is checked before |
371 | // the user-defined type is available. |
372 | lst->insert(instr->_matrule->_lChild->_opType,cost,instr->_ident); |
373 | } |
374 | } else { |
375 | // May have instruction chain rule if root of right-tree is an ideal |
376 | OperandForm *rightOp = _globalNames[right->_opType]->is_operand(); |
377 | if( rightOp ) { |
378 | const Form *rightRoot = _globalNames[rightOp->_matrule->_opType]; |
379 | if( rightRoot && rightRoot->ideal_only() ) { |
380 | const char *chain_op = NULL__null; |
381 | if( rightRoot->is_instruction() ) |
382 | chain_op = rightOp->_ident; |
383 | if( chain_op ) { |
384 | // Look-up the operation in chain rule table |
385 | ChainList *lst = (ChainList *)_AD._chainRules[chain_op]; |
386 | if (lst == NULL__null) { |
387 | lst = new ChainList(); |
388 | _AD._chainRules.Insert(chain_op, lst); |
389 | } |
390 | // if (!lst->search(instr->_matrule->_lChild->_opType)) { |
391 | const char *cost = instr->cost(); |
392 | if (cost == NULL__null) { |
393 | cost = ((AttributeForm*)_globalNames[AttributeForm::_ins_cost])->_attrdef; |
394 | } |
395 | // This chains from a top-level operand whose predicate, if any, |
396 | // has been checked. |
397 | lst->insert(instr->_matrule->_lChild->_opType,cost,instr->_ident); |
398 | // } |
399 | } |
400 | } |
401 | } |
402 | } // end chain rule from right-tree's ideal root |
403 | } |
404 | } |
405 | } |
406 | |
407 | |
408 | //------------------------------oper_parse------------------------------------- |
409 | void ADLParser::oper_parse(void) { |
410 | char *ident; |
411 | OperandForm *oper; |
412 | AttributeForm *attr; |
413 | MatchRule *rule; |
414 | |
415 | // First get the name of the operand |
416 | skipws(); |
417 | if( (ident = get_unique_ident(_globalNames,"operand")) == NULL__null ) |
418 | return; |
419 | oper = new OperandForm(ident); // Create new operand form |
420 | oper->_linenum = linenum(); |
421 | _globalNames.Insert(ident, oper); // Add name to the name table |
422 | |
423 | // Debugging Stuff |
424 | if (_AD._adl_debug > 1) fprintf(stderrstderr,"Parsing Operand Form %s\n", ident); |
425 | |
426 | // Get the component operands |
427 | skipws(); |
428 | if (_curchar != '(') { |
429 | parse_err(SYNERR1, "missing '(' in operand definition\n"); |
430 | return; |
431 | } |
432 | else get_oplist(oper->_parameters, oper->_localNames); // Parse the component operand list |
433 | skipws(); |
434 | // Check for block delimiter |
435 | if ((_curchar != '%') || (*(_ptr+1) != '{')) { // If not open block |
436 | parse_err(SYNERR1, "missing '%%{' in operand definition\n"); |
437 | return; |
438 | } |
439 | next_char(); next_char(); // Skip over "%{" symbol |
440 | do { |
441 | ident = get_ident(); // Grab next identifier |
442 | if (ident == NULL__null) { |
443 | parse_err(SYNERR1, "keyword identifier expected at %c\n", _curchar); |
444 | continue; |
445 | } |
446 | if (!strcmp(ident, "predicate")) oper->_predicate = pred_parse(); |
447 | else if (!strcmp(ident, "match")) { |
448 | // Find the end of the match rule list |
449 | rule = oper->_matrule; |
450 | if (rule) { |
451 | while (rule->_next) rule = rule->_next; |
452 | // Add the new match rule to the list |
453 | rule->_next = match_parse(oper->_localNames); |
454 | if (rule->_next) { |
455 | rule->_next->_result = oper->_ident; |
456 | } |
457 | } |
458 | else { |
459 | // This is first match rule encountered |
460 | oper->_matrule = match_parse(oper->_localNames); |
461 | if (oper->_matrule) { |
462 | oper->_matrule->_result = oper->_ident; |
463 | } |
464 | } |
465 | } |
466 | else if (!strcmp(ident, "encode")) oper->_interface = interface_parse(); |
467 | else if (!strcmp(ident, "ins_encode")) { |
468 | parse_err(SYNERR1, "Operands specify 'encode', not 'ins_encode'\n"); |
469 | } |
470 | else if (!strcmp(ident, "opcode")) { |
471 | parse_err(SYNERR1, "Operands do not specify an opcode\n"); |
472 | } |
473 | else if (!strcmp(ident, "effect")) { |
474 | parse_err(SYNERR1, "Operands do not specify an effect\n"); |
475 | } |
476 | else if (!strcmp(ident, "expand")) { |
477 | parse_err(SYNERR1, "Operands do not specify an expand\n"); |
478 | } |
479 | else if (!strcmp(ident, "rewrite")) { |
480 | parse_err(SYNERR1, "Operands do not specify a rewrite\n"); |
481 | } |
482 | else if (!strcmp(ident, "constraint"))oper->_constraint= constraint_parse(); |
483 | else if (!strcmp(ident, "construct")) oper->_construct = construct_parse(); |
484 | else if (!strcmp(ident, "format")) oper->_format = format_parse(); |
485 | else if (!strcmp(ident, "interface")) oper->_interface = interface_parse(); |
486 | // Check identifier to see if it is the name of an attribute |
487 | else if (((attr = _globalNames[ident]->is_attribute()) != NULL__null) && |
488 | (attr->_atype == OP_ATTR1)) oper->_attribs = attr_parse(ident); |
489 | else { |
490 | parse_err(SYNERR1, "expected one of - constraint, predicate, match, encode, format, construct, or the name of a defined operand attribute at %s\n", ident); |
491 | } |
492 | skipws(); |
493 | } while(_curchar != '%'); |
494 | next_char(); |
495 | if (_curchar != '}') { |
496 | parse_err(SYNERR1, "missing '%%}' in operand definition\n"); |
497 | return; |
498 | } |
499 | // Add operand to tail of operand list |
500 | _AD.addForm(oper); |
501 | } |
502 | |
503 | //------------------------------opclass_parse---------------------------------- |
504 | // Operand Classes are a block with a comma delimited list of operand names |
505 | void ADLParser::opclass_parse(void) { |
506 | char *ident; |
507 | OpClassForm *opc; |
508 | OperandForm *opForm; |
509 | |
510 | // First get the name of the operand class |
511 | skipws(); |
512 | if( (ident = get_unique_ident(_globalNames,"opclass")) == NULL__null ) |
513 | return; |
514 | opc = new OpClassForm(ident); // Create new operand class form |
515 | _globalNames.Insert(ident, opc); // Add name to the name table |
516 | |
517 | // Debugging Stuff |
518 | if (_AD._adl_debug > 1) |
519 | fprintf(stderrstderr,"Parsing Operand Class Form %s\n", ident); |
520 | |
521 | // Get the list of operands |
522 | skipws(); |
523 | if (_curchar != '(') { |
524 | parse_err(SYNERR1, "missing '(' in operand definition\n"); |
525 | return; |
526 | } |
527 | do { |
528 | next_char(); // Skip past open paren or comma |
529 | ident = get_ident(); // Grab next identifier |
530 | if (ident == NULL__null) { |
531 | parse_err(SYNERR1, "keyword identifier expected at %c\n", _curchar); |
532 | continue; |
533 | } |
534 | // Check identifier to see if it is the name of an operand |
535 | const Form *form = _globalNames[ident]; |
536 | opForm = form ? form->is_operand() : NULL__null; |
537 | if ( opForm ) { |
538 | opc->_oplst.addName(ident); // Add operand to opclass list |
539 | opForm->_classes.addName(opc->_ident);// Add opclass to operand list |
540 | } |
541 | else { |
542 | parse_err(SYNERR1, "expected name of a defined operand at %s\n", ident); |
543 | } |
544 | skipws(); // skip trailing whitespace |
545 | } while (_curchar == ','); // Check for the comma |
546 | // Check for closing ')' |
547 | if (_curchar != ')') { |
548 | parse_err(SYNERR1, "missing ')' or ',' in opclass definition\n"); |
549 | return; |
550 | } |
551 | next_char(); // Consume the ')' |
552 | skipws(); |
553 | // Check for closing ';' |
554 | if (_curchar != ';') { |
555 | parse_err(SYNERR1, "missing ';' in opclass definition\n"); |
556 | return; |
557 | } |
558 | next_char(); // Consume the ';' |
559 | // Add operand to tail of operand list |
560 | _AD.addForm(opc); |
561 | } |
562 | |
563 | //------------------------------ins_attr_parse--------------------------------- |
564 | void ADLParser::ins_attr_parse(void) { |
565 | char *ident; |
566 | char *aexpr; |
567 | AttributeForm *attrib; |
568 | |
569 | // get name for the instruction attribute |
570 | skipws(); // Skip leading whitespace |
571 | if( (ident = get_unique_ident(_globalNames,"inst_attrib")) == NULL__null ) |
572 | return; |
573 | // Debugging Stuff |
574 | if (_AD._adl_debug > 1) fprintf(stderrstderr,"Parsing Ins_Attribute Form %s\n", ident); |
575 | |
576 | // Get default value of the instruction attribute |
577 | skipws(); // Skip whitespace |
578 | if ((aexpr = get_paren_expr("attribute default expression string")) == NULL__null) { |
579 | parse_err(SYNERR1, "missing '(' in ins_attrib definition\n"); |
580 | return; |
581 | } |
582 | // Debug Stuff |
583 | if (_AD._adl_debug > 1) fprintf(stderrstderr,"Attribute Expression: %s\n", aexpr); |
584 | |
585 | // Check for terminator |
586 | if (_curchar != ';') { |
587 | parse_err(SYNERR1, "missing ';' in ins_attrib definition\n"); |
588 | return; |
589 | } |
590 | next_char(); // Advance past the ';' |
591 | |
592 | // Construct the attribute, record global name, and store in ArchDesc |
593 | attrib = new AttributeForm(ident, INS_ATTR0, aexpr); |
594 | _globalNames.Insert(ident, attrib); // Add name to the name table |
595 | _AD.addForm(attrib); |
596 | } |
597 | |
598 | //------------------------------op_attr_parse---------------------------------- |
599 | void ADLParser::op_attr_parse(void) { |
600 | char *ident; |
601 | char *aexpr; |
602 | AttributeForm *attrib; |
603 | |
604 | // get name for the operand attribute |
605 | skipws(); // Skip leading whitespace |
606 | if( (ident = get_unique_ident(_globalNames,"op_attrib")) == NULL__null ) |
607 | return; |
608 | // Debugging Stuff |
609 | if (_AD._adl_debug > 1) fprintf(stderrstderr,"Parsing Op_Attribute Form %s\n", ident); |
610 | |
611 | // Get default value of the instruction attribute |
612 | skipws(); // Skip whitespace |
613 | if ((aexpr = get_paren_expr("attribute default expression string")) == NULL__null) { |
614 | parse_err(SYNERR1, "missing '(' in op_attrib definition\n"); |
615 | return; |
616 | } |
617 | // Debug Stuff |
618 | if (_AD._adl_debug > 1) fprintf(stderrstderr,"Attribute Expression: %s\n", aexpr); |
619 | |
620 | // Check for terminator |
621 | if (_curchar != ';') { |
622 | parse_err(SYNERR1, "missing ';' in op_attrib definition\n"); |
623 | return; |
624 | } |
625 | next_char(); // Advance past the ';' |
626 | |
627 | // Construct the attribute, record global name, and store in ArchDesc |
628 | attrib = new AttributeForm(ident, OP_ATTR1, aexpr); |
629 | _globalNames.Insert(ident, attrib); |
630 | _AD.addForm(attrib); |
631 | } |
632 | |
633 | //------------------------------definitions_parse----------------------------------- |
634 | void ADLParser::definitions_parse(void) { |
635 | skipws(); // Skip leading whitespace |
636 | if (_curchar == '%' && *(_ptr+1) == '{') { |
637 | next_char(); next_char(); // Skip "%{" |
638 | skipws(); |
639 | while (_curchar != '%' && *(_ptr+1) != '}') { |
640 | // Process each definition until finding closing string "%}" |
641 | char *token = get_ident(); |
642 | if (token == NULL__null) { |
643 | parse_err(SYNERR1, "missing identifier inside definitions block.\n"); |
644 | return; |
645 | } |
646 | if (strcmp(token,"int_def")==0) { int_def_parse(); } |
647 | // if (strcmp(token,"str_def")==0) { str_def_parse(); } |
648 | skipws(); |
649 | } |
650 | } |
651 | else { |
652 | parse_err(SYNERR1, "Missing %%{ ... %%} block after definitions keyword.\n"); |
653 | return; |
654 | } |
655 | } |
656 | |
657 | //------------------------------int_def_parse---------------------------------- |
658 | // Parse Example: |
659 | // int_def MEMORY_REF_COST ( 200, DEFAULT_COST * 2); |
660 | // <keyword> <name> ( <int_value>, <description> ); |
661 | // |
662 | void ADLParser::int_def_parse(void) { |
663 | char *name = NULL__null; // Name of definition |
664 | char *value = NULL__null; // its value, |
665 | int int_value = -1; // positive values only |
666 | char *description = NULL__null; // textual description |
667 | |
668 | // Get definition name |
669 | skipws(); // Skip whitespace |
670 | name = get_ident(); |
671 | if (name == NULL__null) { |
672 | parse_err(SYNERR1, "missing definition name after int_def\n"); |
673 | return; |
674 | } |
675 | |
676 | // Check for value of int_def dname( integer_value [, string_expression ] ) |
677 | skipws(); |
678 | if (_curchar == '(') { |
679 | |
680 | // Parse the integer value. |
681 | next_char(); |
682 | value = get_ident(); |
683 | if (value == NULL__null) { |
684 | parse_err(SYNERR1, "missing value in int_def\n"); |
685 | return; |
686 | } |
687 | if( !is_int_token(value, int_value) ) { |
688 | parse_err(SYNERR1, "value in int_def is not recognized as integer\n"); |
689 | return; |
690 | } |
691 | skipws(); |
692 | |
693 | // Check for description |
694 | if (_curchar == ',') { |
695 | next_char(); // skip ',' |
696 | |
697 | description = get_expr("int_def description", ")"); |
698 | if (description == NULL__null) { |
699 | parse_err(SYNERR1, "invalid or missing description in int_def\n"); |
700 | return; |
701 | } |
702 | trim(description); |
703 | } |
704 | |
705 | if (_curchar != ')') { |
706 | parse_err(SYNERR1, "missing ')' in register definition statement\n"); |
707 | return; |
708 | } |
709 | next_char(); |
710 | } |
711 | |
712 | // Check for closing ';' |
713 | skipws(); |
714 | if (_curchar != ';') { |
715 | parse_err(SYNERR1, "missing ';' after int_def\n"); |
716 | return; |
717 | } |
718 | next_char(); // move past ';' |
719 | |
720 | // Debug Stuff |
721 | if (_AD._adl_debug > 1) { |
722 | fprintf(stderrstderr,"int_def: %s ( %s, %s )\n", name, |
723 | (value), (description ? description : "")); |
724 | } |
725 | |
726 | // Record new definition. |
727 | Expr *expr = new Expr(name, description, int_value, int_value); |
728 | const Expr *old_expr = _AD.globalDefs().define(name, expr); |
729 | if (old_expr != NULL__null) { |
730 | parse_err(SYNERR1, "Duplicate definition\n"); |
731 | return; |
732 | } |
733 | |
734 | return; |
735 | } |
736 | |
737 | |
738 | //------------------------------source_parse----------------------------------- |
739 | void ADLParser::source_parse(void) { |
740 | SourceForm *source; // Encode class for instruction/operand |
741 | char *rule = NULL__null; // String representation of encode rule |
742 | |
743 | skipws(); // Skip leading whitespace |
744 | if ( (rule = find_cpp_block("source block")) == NULL__null ) { |
745 | parse_err(SYNERR1, "incorrect or missing block for 'source'.\n"); |
746 | return; |
747 | } |
748 | // Debug Stuff |
749 | if (_AD._adl_debug > 1) fprintf(stderrstderr,"Source Form: %s\n", rule); |
750 | |
751 | source = new SourceForm(rule); // Build new Source object |
752 | _AD.addForm(source); |
753 | // skipws(); |
754 | } |
755 | |
756 | //------------------------------source_hpp_parse------------------------------- |
757 | // Parse a source_hpp %{ ... %} block. |
758 | // The code gets stuck into the ad_<arch>.hpp file. |
759 | // If the source_hpp block appears before the register block in the AD |
760 | // file, it goes up at the very top of the ad_<arch>.hpp file, so that |
761 | // it can be used by register encodings, etc. Otherwise, it goes towards |
762 | // the bottom, where it's useful as a global definition to *.cpp files. |
763 | void ADLParser::source_hpp_parse(void) { |
764 | char *rule = NULL__null; // String representation of encode rule |
765 | |
766 | skipws(); // Skip leading whitespace |
767 | if ( (rule = find_cpp_block("source_hpp block")) == NULL__null ) { |
768 | parse_err(SYNERR1, "incorrect or missing block for 'source_hpp'.\n"); |
769 | return; |
770 | } |
771 | // Debug Stuff |
772 | if (_AD._adl_debug > 1) fprintf(stderrstderr,"Header Form: %s\n", rule); |
773 | |
774 | if (_AD.get_registers() == NULL__null) { |
775 | // Very early in the file, before reg_defs, we collect pre-headers. |
776 | PreHeaderForm* pre_header = new PreHeaderForm(rule); |
777 | _AD.addForm(pre_header); |
778 | } else { |
779 | // Normally, we collect header info, placed at the bottom of the hpp file. |
780 | HeaderForm* header = new HeaderForm(rule); |
781 | _AD.addForm(header); |
782 | } |
783 | } |
784 | |
785 | //------------------------------reg_parse-------------------------------------- |
786 | void ADLParser::reg_parse(void) { |
787 | RegisterForm *regBlock = _AD.get_registers(); // Information about registers encoding |
788 | if (regBlock == NULL__null) { |
789 | // Create the RegisterForm for the architecture description. |
790 | regBlock = new RegisterForm(); // Build new Source object |
791 | _AD.addForm(regBlock); |
792 | } |
793 | |
794 | skipws(); // Skip leading whitespace |
795 | if (_curchar == '%' && *(_ptr+1) == '{') { |
796 | next_char(); next_char(); // Skip "%{" |
797 | skipws(); |
798 | while (_curchar != '%' && *(_ptr+1) != '}') { |
799 | char *token = get_ident(); |
800 | if (token == NULL__null) { |
801 | parse_err(SYNERR1, "missing identifier inside register block.\n"); |
802 | return; |
803 | } |
804 | if (strcmp(token,"reg_def")==0) { reg_def_parse(); } |
805 | else if (strcmp(token,"reg_class")==0) { reg_class_parse(); } |
806 | else if (strcmp(token, "reg_class_dynamic") == 0) { reg_class_dynamic_parse(); } |
807 | else if (strcmp(token,"alloc_class")==0) { alloc_class_parse(); } |
808 | else if (strcmp(token,"#define")==0) { preproc_define(); } |
809 | else { parse_err(SYNERR1, "bad token %s inside register block.\n", token); break; } |
810 | skipws(); |
811 | } |
812 | } |
813 | else { |
814 | parse_err(SYNERR1, "Missing %c{ ... %c} block after register keyword.\n",'%','%'); |
815 | return; |
816 | } |
817 | } |
818 | |
819 | //------------------------------encode_parse----------------------------------- |
820 | void ADLParser::encode_parse(void) { |
821 | EncodeForm *encBlock; // Information about instruction/operand encoding |
822 | |
823 | _AD.getForm(&encBlock); |
824 | if ( encBlock == NULL__null) { |
825 | // Create the EncodeForm for the architecture description. |
826 | encBlock = new EncodeForm(); // Build new Source object |
827 | _AD.addForm(encBlock); |
828 | } |
829 | |
830 | skipws(); // Skip leading whitespace |
831 | if (_curchar == '%' && *(_ptr+1) == '{') { |
832 | next_char(); next_char(); // Skip "%{" |
833 | skipws(); |
834 | while (_curchar != '%' && *(_ptr+1) != '}') { |
835 | char *token = get_ident(); |
836 | if (token == NULL__null) { |
837 | parse_err(SYNERR1, "missing identifier inside encoding block.\n"); |
838 | return; |
839 | } |
840 | if (strcmp(token,"enc_class")==0) { enc_class_parse(); } |
841 | skipws(); |
842 | } |
843 | } |
844 | else { |
845 | parse_err(SYNERR1, "Missing %c{ ... %c} block after encode keyword.\n",'%','%'); |
846 | return; |
847 | } |
848 | } |
849 | |
850 | //------------------------------enc_class_parse-------------------------------- |
851 | void ADLParser::enc_class_parse(void) { |
852 | char *ec_name; // Name of encoding class being defined |
853 | |
854 | // Get encoding class name |
855 | skipws(); // Skip whitespace |
856 | ec_name = get_ident(); |
857 | if (ec_name == NULL__null) { |
858 | parse_err(SYNERR1, "missing encoding class name after encode.\n"); |
859 | return; |
860 | } |
861 | |
862 | EncClass *encoding = _AD._encode->add_EncClass(ec_name); |
863 | encoding->_linenum = linenum(); |
864 | |
865 | skipws(); // Skip leading whitespace |
866 | // Check for optional parameter list |
867 | if (_curchar == '(') { |
868 | do { |
869 | char *pType = NULL__null; // parameter type |
870 | char *pName = NULL__null; // parameter name |
871 | |
872 | next_char(); // skip open paren & comma characters |
873 | skipws(); |
874 | if (_curchar == ')') break; |
875 | |
876 | // Get parameter type |
877 | pType = get_ident(); |
878 | if (pType == NULL__null) { |
879 | parse_err(SYNERR1, "parameter type expected at %c\n", _curchar); |
880 | return; |
881 | } |
882 | |
883 | skipws(); |
884 | // Get parameter name |
885 | pName = get_ident(); |
886 | if (pName == NULL__null) { |
887 | parse_err(SYNERR1, "parameter name expected at %c\n", _curchar); |
888 | return; |
889 | } |
890 | |
891 | // Record parameter type and name |
892 | encoding->add_parameter( pType, pName ); |
893 | |
894 | skipws(); |
895 | } while(_curchar == ','); |
896 | |
897 | if (_curchar != ')') parse_err(SYNERR1, "missing ')'\n"); |
898 | else { |
899 | next_char(); // Skip ')' |
900 | } |
901 | } // Done with parameter list |
902 | |
903 | skipws(); |
904 | // Check for block starting delimiters |
905 | if ((_curchar != '%') || (*(_ptr+1) != '{')) { // If not open block |
906 | parse_err(SYNERR1, "missing '%c{' in enc_class definition\n", '%'); |
907 | return; |
908 | } |
909 | next_char(); // Skip '%' |
910 | next_char(); // Skip '{' |
911 | |
912 | enc_class_parse_block(encoding, ec_name); |
913 | } |
914 | |
915 | |
916 | void ADLParser::enc_class_parse_block(EncClass* encoding, char* ec_name) { |
917 | skipws_no_preproc(); // Skip leading whitespace |
918 | // Prepend location descriptor, for debugging; cf. ADLParser::find_cpp_block |
919 | if (_AD._adlocation_debug) { |
920 | encoding->add_code(get_line_string()); |
921 | } |
922 | |
923 | // Collect the parts of the encode description |
924 | // (1) strings that are passed through to output |
925 | // (2) replacement/substitution variable, preceeded by a '$' |
926 | while ( (_curchar != '%') && (*(_ptr+1) != '}') ) { |
927 | |
928 | // (1) |
929 | // Check if there is a string to pass through to output |
930 | char *start = _ptr; // Record start of the next string |
931 | while ((_curchar != '$') && ((_curchar != '%') || (*(_ptr+1) != '}')) ) { |
932 | // If at the start of a comment, skip past it |
933 | if( (_curchar == '/') && ((*(_ptr+1) == '/') || (*(_ptr+1) == '*')) ) { |
934 | skipws_no_preproc(); |
935 | } else { |
936 | // ELSE advance to the next character, or start of the next line |
937 | next_char_or_line(); |
938 | } |
939 | } |
940 | // If a string was found, terminate it and record in EncClass |
941 | if ( start != _ptr ) { |
942 | *_ptr = '\0'; // Terminate the string |
943 | encoding->add_code(start); |
944 | } |
945 | |
946 | // (2) |
947 | // If we are at a replacement variable, |
948 | // copy it and record in EncClass |
949 | if (_curchar == '$') { |
950 | // Found replacement Variable |
951 | char* rep_var = get_rep_var_ident_dup(); |
952 | // Add flag to _strings list indicating we should check _rep_vars |
953 | encoding->add_rep_var(rep_var); |
954 | } |
955 | } // end while part of format description |
956 | next_char(); // Skip '%' |
957 | next_char(); // Skip '}' |
958 | |
959 | skipws(); |
960 | |
961 | if (_AD._adlocation_debug) { |
962 | encoding->add_code(end_line_marker()); |
963 | } |
964 | |
965 | // Debug Stuff |
966 | if (_AD._adl_debug > 1) fprintf(stderrstderr,"EncodingClass Form: %s\n", ec_name); |
967 | } |
968 | |
969 | //------------------------------frame_parse----------------------------------- |
970 | void ADLParser::frame_parse(void) { |
971 | FrameForm *frame; // Information about stack-frame layout |
972 | char *desc = NULL__null; // String representation of frame |
973 | |
974 | skipws(); // Skip leading whitespace |
975 | |
976 | frame = new FrameForm(); // Build new Frame object |
977 | // Check for open block sequence |
978 | skipws(); // Skip leading whitespace |
979 | if (_curchar == '%' && *(_ptr+1) == '{') { |
980 | next_char(); next_char(); // Skip "%{" |
981 | skipws(); |
982 | while (_curchar != '%' && *(_ptr+1) != '}') { |
983 | char *token = get_ident(); |
984 | if (token == NULL__null) { |
985 | parse_err(SYNERR1, "missing identifier inside frame block.\n"); |
986 | return; |
987 | } |
988 | if (strcmp(token,"sync_stack_slots")==0) { |
989 | sync_stack_slots_parse(frame); |
990 | } |
991 | if (strcmp(token,"frame_pointer")==0) { |
992 | frame_pointer_parse(frame, false); |
993 | } |
994 | if (strcmp(token,"interpreter_frame_pointer")==0) { |
995 | interpreter_frame_pointer_parse(frame, false); |
996 | } |
997 | if (strcmp(token,"inline_cache_reg")==0) { |
998 | inline_cache_parse(frame, false); |
999 | } |
1000 | if (strcmp(token,"compiler_method_oop_reg")==0) { |
1001 | parse_err(WARN0, "Using obsolete Token, compiler_method_oop_reg"); |
1002 | skipws(); |
1003 | } |
1004 | if (strcmp(token,"interpreter_method_oop_reg")==0) { |
1005 | parse_err(WARN0, "Using obsolete Token, interpreter_method_oop_reg"); |
1006 | skipws(); |
1007 | } |
1008 | if (strcmp(token,"interpreter_method_reg")==0) { |
1009 | parse_err(WARN0, "Using obsolete Token, interpreter_method_reg"); |
1010 | skipws(); |
1011 | } |
1012 | if (strcmp(token,"cisc_spilling_operand_name")==0) { |
1013 | cisc_spilling_operand_name_parse(frame, false); |
1014 | } |
1015 | if (strcmp(token,"stack_alignment")==0) { |
1016 | stack_alignment_parse(frame); |
1017 | } |
1018 | if (strcmp(token,"return_addr")==0) { |
1019 | return_addr_parse(frame, false); |
1020 | } |
1021 | if (strcmp(token,"in_preserve_stack_slots")==0) { |
1022 | parse_err(WARN0, "Using obsolete token, in_preserve_stack_slots"); |
1023 | skipws(); |
1024 | } |
1025 | if (strcmp(token,"out_preserve_stack_slots")==0) { |
1026 | parse_err(WARN0, "Using obsolete token, out_preserve_stack_slots"); |
1027 | skipws(); |
1028 | } |
1029 | if (strcmp(token,"varargs_C_out_slots_killed")==0) { |
1030 | frame->_varargs_C_out_slots_killed = parse_one_arg("varargs C out slots killed"); |
1031 | } |
1032 | if (strcmp(token,"calling_convention")==0) { |
1033 | parse_err(WARN0, "Using obsolete token, calling_convention"); |
1034 | skipws(); |
1035 | } |
1036 | if (strcmp(token,"return_value")==0) { |
1037 | frame->_return_value = return_value_parse(); |
1038 | } |
1039 | if (strcmp(token,"c_frame_pointer")==0) { |
1040 | frame_pointer_parse(frame, true); |
1041 | } |
1042 | if (strcmp(token,"c_return_addr")==0) { |
1043 | return_addr_parse(frame, true); |
1044 | } |
1045 | if (strcmp(token,"c_calling_convention")==0) { |
1046 | parse_err(WARN0, "Using obsolete token, c_calling_convention"); |
1047 | skipws(); |
1048 | } |
1049 | if (strcmp(token,"c_return_value")==0) { |
1050 | frame->_c_return_value = return_value_parse(); |
1051 | } |
1052 | |
1053 | skipws(); |
1054 | } |
1055 | } |
1056 | else { |
1057 | parse_err(SYNERR1, "Missing %c{ ... %c} block after encode keyword.\n",'%','%'); |
1058 | return; |
1059 | } |
1060 | // All Java versions are required, native versions are optional |
1061 | if(frame->_frame_pointer == NULL__null) { |
1062 | parse_err(SYNERR1, "missing frame pointer definition in frame section.\n"); |
1063 | return; |
1064 | } |
1065 | // !!!!! !!!!! |
1066 | // if(frame->_interpreter_frame_ptr_reg == NULL) { |
1067 | // parse_err(SYNERR, "missing interpreter frame pointer definition in frame section.\n"); |
1068 | // return; |
1069 | // } |
1070 | if(frame->_alignment == NULL__null) { |
1071 | parse_err(SYNERR1, "missing alignment definition in frame section.\n"); |
1072 | return; |
1073 | } |
1074 | if(frame->_return_addr == NULL__null) { |
1075 | parse_err(SYNERR1, "missing return address location in frame section.\n"); |
1076 | return; |
1077 | } |
1078 | if(frame->_varargs_C_out_slots_killed == NULL__null) { |
1079 | parse_err(SYNERR1, "missing varargs C out slots killed definition in frame section.\n"); |
1080 | return; |
1081 | } |
1082 | if(frame->_return_value == NULL__null) { |
1083 | parse_err(SYNERR1, "missing return value definition in frame section.\n"); |
1084 | return; |
1085 | } |
1086 | // Fill natives in identically with the Java versions if not present. |
1087 | if(frame->_c_frame_pointer == NULL__null) { |
1088 | frame->_c_frame_pointer = frame->_frame_pointer; |
1089 | } |
1090 | if(frame->_c_return_addr == NULL__null) { |
1091 | frame->_c_return_addr = frame->_return_addr; |
1092 | frame->_c_return_addr_loc = frame->_return_addr_loc; |
1093 | } |
1094 | if(frame->_c_return_value == NULL__null) { |
1095 | frame->_c_return_value = frame->_return_value; |
1096 | } |
1097 | |
1098 | // Debug Stuff |
1099 | if (_AD._adl_debug > 1) fprintf(stderrstderr,"Frame Form: %s\n", desc); |
1100 | |
1101 | // Create the EncodeForm for the architecture description. |
1102 | _AD.addForm(frame); |
1103 | // skipws(); |
1104 | } |
1105 | |
1106 | //------------------------------sync_stack_slots_parse------------------------- |
1107 | void ADLParser::sync_stack_slots_parse(FrameForm *frame) { |
1108 | // Assign value into frame form |
1109 | frame->_sync_stack_slots = parse_one_arg("sync stack slots entry"); |
1110 | } |
1111 | |
1112 | //------------------------------frame_pointer_parse---------------------------- |
1113 | void ADLParser::frame_pointer_parse(FrameForm *frame, bool native) { |
1114 | char *frame_pointer = parse_one_arg("frame pointer entry"); |
1115 | // Assign value into frame form |
1116 | if (native) { frame->_c_frame_pointer = frame_pointer; } |
1117 | else { frame->_frame_pointer = frame_pointer; } |
1118 | } |
1119 | |
1120 | //------------------------------interpreter_frame_pointer_parse---------------------------- |
1121 | void ADLParser::interpreter_frame_pointer_parse(FrameForm *frame, bool native) { |
1122 | frame->_interpreter_frame_pointer_reg = parse_one_arg("interpreter frame pointer entry"); |
1123 | } |
1124 | |
1125 | //------------------------------inline_cache_parse----------------------------- |
1126 | void ADLParser::inline_cache_parse(FrameForm *frame, bool native) { |
1127 | frame->_inline_cache_reg = parse_one_arg("inline cache reg entry"); |
1128 | } |
1129 | |
1130 | //------------------------------cisc_spilling_operand_parse--------------------- |
1131 | void ADLParser::cisc_spilling_operand_name_parse(FrameForm *frame, bool native) { |
1132 | frame->_cisc_spilling_operand_name = parse_one_arg("cisc spilling operand name"); |
1133 | } |
1134 | |
1135 | //------------------------------stack_alignment_parse-------------------------- |
1136 | void ADLParser::stack_alignment_parse(FrameForm *frame) { |
1137 | char *alignment = parse_one_arg("stack alignment entry"); |
1138 | // Assign value into frame |
1139 | frame->_alignment = alignment; |
1140 | } |
1141 | |
1142 | //------------------------------parse_one_arg------------------------------- |
1143 | char *ADLParser::parse_one_arg(const char *description) { |
1144 | char *token = NULL__null; |
1145 | if(_curchar == '(') { |
1146 | next_char(); |
1147 | skipws(); |
1148 | token = get_expr(description, ")"); |
1149 | if (token == NULL__null) { |
1150 | parse_err(SYNERR1, "missing value inside %s.\n", description); |
1151 | return NULL__null; |
1152 | } |
1153 | next_char(); // skip the close paren |
1154 | if(_curchar != ';') { // check for semi-colon |
1155 | parse_err(SYNERR1, "missing %c in.\n", ';', description); |
1156 | return NULL__null; |
1157 | } |
1158 | next_char(); // skip the semi-colon |
1159 | } |
1160 | else { |
1161 | parse_err(SYNERR1, "Missing %c in.\n", '(', description); |
1162 | return NULL__null; |
1163 | } |
1164 | |
1165 | trim(token); |
1166 | return token; |
1167 | } |
1168 | |
1169 | //------------------------------return_addr_parse------------------------------ |
1170 | void ADLParser::return_addr_parse(FrameForm *frame, bool native) { |
1171 | bool in_register = true; |
1172 | if(_curchar == '(') { |
1173 | next_char(); |
1174 | skipws(); |
1175 | char *token = get_ident(); |
1176 | if (token == NULL__null) { |
1177 | parse_err(SYNERR1, "missing value inside return address entry.\n"); |
1178 | return; |
1179 | } |
1180 | // check for valid values for stack/register |
1181 | if (strcmp(token, "REG") == 0) { |
1182 | in_register = true; |
1183 | } |
1184 | else if (strcmp(token, "STACK") == 0) { |
1185 | in_register = false; |
1186 | } |
1187 | else { |
1188 | parse_err(SYNERR1, "invalid value inside return_address entry.\n"); |
1189 | return; |
1190 | } |
1191 | if (native) { frame->_c_return_addr_loc = in_register; } |
1192 | else { frame->_return_addr_loc = in_register; } |
1193 | |
1194 | // Parse expression that specifies register or stack position |
1195 | skipws(); |
1196 | char *token2 = get_expr("return address entry", ")"); |
1197 | if (token2 == NULL__null) { |
1198 | parse_err(SYNERR1, "missing value inside return address entry.\n"); |
1199 | return; |
1200 | } |
1201 | next_char(); // skip the close paren |
1202 | if (native) { frame->_c_return_addr = token2; } |
1203 | else { frame->_return_addr = token2; } |
1204 | |
1205 | if(_curchar != ';') { // check for semi-colon |
1206 | parse_err(SYNERR1, "missing %c in return address entry.\n", ';'); |
1207 | return; |
1208 | } |
1209 | next_char(); // skip the semi-colon |
1210 | } |
1211 | else { |
1212 | parse_err(SYNERR1, "Missing %c in return_address entry.\n", '('); |
1213 | } |
1214 | } |
1215 | |
1216 | //------------------------------return_value_parse----------------------------- |
1217 | char *ADLParser::return_value_parse() { |
1218 | char *desc = NULL__null; // String representation of return_value |
1219 | |
1220 | skipws(); // Skip leading whitespace |
1221 | if ( (desc = find_cpp_block("return value block")) == NULL__null ) { |
1222 | parse_err(SYNERR1, "incorrect or missing block for 'return_value'.\n"); |
1223 | } |
1224 | return desc; |
1225 | } |
1226 | |
1227 | //------------------------------ins_pipe_parse--------------------------------- |
1228 | void ADLParser::ins_pipe_parse(InstructForm &instr) { |
1229 | char * ident; |
1230 | |
1231 | skipws(); |
1232 | if ( _curchar != '(' ) { // Check for delimiter |
1233 | parse_err(SYNERR1, "missing \"(\" in ins_pipe definition\n"); |
1234 | return; |
1235 | } |
1236 | |
1237 | next_char(); |
1238 | ident = get_ident(); // Grab next identifier |
1239 | |
1240 | if (ident == NULL__null) { |
1241 | parse_err(SYNERR1, "keyword identifier expected at %c\n", _curchar); |
1242 | return; |
1243 | } |
1244 | |
1245 | skipws(); |
1246 | if ( _curchar != ')' ) { // Check for delimiter |
1247 | parse_err(SYNERR1, "missing \")\" in ins_pipe definition\n"); |
1248 | return; |
1249 | } |
1250 | |
1251 | next_char(); // skip the close paren |
1252 | if(_curchar != ';') { // check for semi-colon |
1253 | parse_err(SYNERR1, "missing %c in return value entry.\n", ';'); |
1254 | return; |
1255 | } |
1256 | next_char(); // skip the semi-colon |
1257 | |
1258 | // Check ident for validity |
1259 | if (_AD._pipeline && !_AD._pipeline->_classlist.search(ident)) { |
1260 | parse_err(SYNERR1, "\"%s\" is not a valid pipeline class\n", ident); |
1261 | return; |
1262 | } |
1263 | |
1264 | // Add this instruction to the list in the pipeline class |
1265 | _AD._pipeline->_classdict[ident]->is_pipeclass()->_instructs.addName(instr._ident); |
1266 | |
1267 | // Set the name of the pipeline class in the instruction |
1268 | instr._ins_pipe = ident; |
1269 | return; |
1270 | } |
1271 | |
1272 | //------------------------------pipe_parse------------------------------------- |
1273 | void ADLParser::pipe_parse(void) { |
1274 | PipelineForm *pipeline; // Encode class for instruction/operand |
1275 | char * ident; |
1276 | |
1277 | pipeline = new PipelineForm(); // Build new Source object |
1278 | _AD.addForm(pipeline); |
1279 | |
1280 | skipws(); // Skip leading whitespace |
1281 | // Check for block delimiter |
1282 | if ( (_curchar != '%') |
1283 | || ( next_char(), (_curchar != '{')) ) { |
1284 | parse_err(SYNERR1, "missing '%%{' in pipeline definition\n"); |
1285 | return; |
1286 | } |
1287 | next_char(); // Maintain the invariant |
1288 | do { |
1289 | ident = get_ident(); // Grab next identifier |
1290 | if (ident == NULL__null) { |
1291 | parse_err(SYNERR1, "keyword identifier expected at %c\n", _curchar); |
1292 | continue; |
1293 | } |
1294 | if (!strcmp(ident, "resources" )) resource_parse(*pipeline); |
1295 | else if (!strcmp(ident, "pipe_desc" )) pipe_desc_parse(*pipeline); |
1296 | else if (!strcmp(ident, "pipe_class")) pipe_class_parse(*pipeline); |
1297 | else if (!strcmp(ident, "define")) { |
1298 | skipws(); |
1299 | if ( (_curchar != '%') |
1300 | || ( next_char(), (_curchar != '{')) ) { |
1301 | parse_err(SYNERR1, "expected '%%{'\n"); |
1302 | return; |
1303 | } |
1304 | next_char(); skipws(); |
1305 | |
1306 | char *node_class = get_ident(); |
1307 | if (node_class == NULL__null) { |
1308 | parse_err(SYNERR1, "expected identifier, found \"%c\"\n", _curchar); |
1309 | return; |
1310 | } |
1311 | |
1312 | skipws(); |
1313 | if (_curchar != ',' && _curchar != '=') { |
1314 | parse_err(SYNERR1, "expected `=`, found '%c'\n", _curchar); |
1315 | break; |
1316 | } |
1317 | next_char(); skipws(); |
1318 | |
1319 | char *pipe_class = get_ident(); |
1320 | if (pipe_class == NULL__null) { |
1321 | parse_err(SYNERR1, "expected identifier, found \"%c\"\n", _curchar); |
1322 | return; |
1323 | } |
1324 | if (_curchar != ';' ) { |
1325 | parse_err(SYNERR1, "expected `;`, found '%c'\n", _curchar); |
1326 | break; |
1327 | } |
1328 | next_char(); // Skip over semi-colon |
1329 | |
1330 | skipws(); |
1331 | if ( (_curchar != '%') |
1332 | || ( next_char(), (_curchar != '}')) ) { |
1333 | parse_err(SYNERR1, "expected '%%}', found \"%c\"\n", _curchar); |
1334 | } |
1335 | next_char(); |
1336 | |
1337 | // Check ident for validity |
1338 | if (_AD._pipeline && !_AD._pipeline->_classlist.search(pipe_class)) { |
1339 | parse_err(SYNERR1, "\"%s\" is not a valid pipeline class\n", pipe_class); |
1340 | return; |
1341 | } |
1342 | |
1343 | // Add this machine node to the list in the pipeline class |
1344 | _AD._pipeline->_classdict[pipe_class]->is_pipeclass()->_instructs.addName(node_class); |
1345 | |
1346 | MachNodeForm *machnode = new MachNodeForm(node_class); // Create new machnode form |
1347 | machnode->_machnode_pipe = pipe_class; |
1348 | |
1349 | _AD.addForm(machnode); |
1350 | } |
1351 | else if (!strcmp(ident, "attributes")) { |
1352 | bool vsi_seen = false; |
1353 | |
1354 | skipws(); |
1355 | if ( (_curchar != '%') |
1356 | || ( next_char(), (_curchar != '{')) ) { |
1357 | parse_err(SYNERR1, "expected '%%{'\n"); |
1358 | return; |
1359 | } |
1360 | next_char(); skipws(); |
1361 | |
1362 | while (_curchar != '%') { |
1363 | ident = get_ident(); |
1364 | if (ident == NULL__null) |
1365 | break; |
1366 | |
1367 | if (!strcmp(ident, "variable_size_instructions")) { |
1368 | skipws(); |
1369 | if (_curchar == ';') { |
1370 | next_char(); skipws(); |
1371 | } |
1372 | |
1373 | pipeline->_variableSizeInstrs = true; |
1374 | vsi_seen = true; |
1375 | continue; |
1376 | } |
1377 | |
1378 | if (!strcmp(ident, "fixed_size_instructions")) { |
1379 | skipws(); |
1380 | if (_curchar == ';') { |
1381 | next_char(); skipws(); |
1382 | } |
1383 | |
1384 | pipeline->_variableSizeInstrs = false; |
1385 | vsi_seen = true; |
1386 | continue; |
1387 | } |
1388 | |
1389 | if (!strcmp(ident, "branch_has_delay_slot")) { |
1390 | skipws(); |
1391 | if (_curchar == ';') { |
1392 | next_char(); skipws(); |
1393 | } |
1394 | |
1395 | pipeline->_branchHasDelaySlot = true; |
1396 | continue; |
1397 | } |
1398 | |
1399 | if (!strcmp(ident, "max_instructions_per_bundle")) { |
1400 | skipws(); |
1401 | if (_curchar != '=') { |
1402 | parse_err(SYNERR1, "expected `=`\n"); |
1403 | break; |
1404 | } |
1405 | |
1406 | next_char(); skipws(); |
1407 | pipeline->_maxInstrsPerBundle = get_int(); |
1408 | skipws(); |
1409 | |
1410 | if (_curchar == ';') { |
1411 | next_char(); skipws(); |
1412 | } |
1413 | |
1414 | continue; |
1415 | } |
1416 | |
1417 | if (!strcmp(ident, "max_bundles_per_cycle")) { |
1418 | skipws(); |
1419 | if (_curchar != '=') { |
1420 | parse_err(SYNERR1, "expected `=`\n"); |
1421 | break; |
1422 | } |
1423 | |
1424 | next_char(); skipws(); |
1425 | pipeline->_maxBundlesPerCycle = get_int(); |
1426 | skipws(); |
1427 | |
1428 | if (_curchar == ';') { |
1429 | next_char(); skipws(); |
1430 | } |
1431 | |
1432 | continue; |
1433 | } |
1434 | |
1435 | if (!strcmp(ident, "instruction_unit_size")) { |
1436 | skipws(); |
1437 | if (_curchar != '=') { |
1438 | parse_err(SYNERR1, "expected `=`, found '%c'\n", _curchar); |
1439 | break; |
1440 | } |
1441 | |
1442 | next_char(); skipws(); |
1443 | pipeline->_instrUnitSize = get_int(); |
1444 | skipws(); |
1445 | |
1446 | if (_curchar == ';') { |
1447 | next_char(); skipws(); |
1448 | } |
1449 | |
1450 | continue; |
1451 | } |
1452 | |
1453 | if (!strcmp(ident, "bundle_unit_size")) { |
1454 | skipws(); |
1455 | if (_curchar != '=') { |
1456 | parse_err(SYNERR1, "expected `=`, found '%c'\n", _curchar); |
1457 | break; |
1458 | } |
1459 | |
1460 | next_char(); skipws(); |
1461 | pipeline->_bundleUnitSize = get_int(); |
1462 | skipws(); |
1463 | |
1464 | if (_curchar == ';') { |
1465 | next_char(); skipws(); |
1466 | } |
1467 | |
1468 | continue; |
1469 | } |
1470 | |
1471 | if (!strcmp(ident, "instruction_fetch_unit_size")) { |
1472 | skipws(); |
1473 | if (_curchar != '=') { |
1474 | parse_err(SYNERR1, "expected `=`, found '%c'\n", _curchar); |
1475 | break; |
1476 | } |
1477 | |
1478 | next_char(); skipws(); |
1479 | pipeline->_instrFetchUnitSize = get_int(); |
1480 | skipws(); |
1481 | |
1482 | if (_curchar == ';') { |
1483 | next_char(); skipws(); |
1484 | } |
1485 | |
1486 | continue; |
1487 | } |
1488 | |
1489 | if (!strcmp(ident, "instruction_fetch_units")) { |
1490 | skipws(); |
1491 | if (_curchar != '=') { |
1492 | parse_err(SYNERR1, "expected `=`, found '%c'\n", _curchar); |
1493 | break; |
1494 | } |
1495 | |
1496 | next_char(); skipws(); |
1497 | pipeline->_instrFetchUnits = get_int(); |
1498 | skipws(); |
1499 | |
1500 | if (_curchar == ';') { |
1501 | next_char(); skipws(); |
1502 | } |
1503 | |
1504 | continue; |
1505 | } |
1506 | |
1507 | if (!strcmp(ident, "nops")) { |
1508 | skipws(); |
1509 | if (_curchar != '(') { |
1510 | parse_err(SYNERR1, "expected `(`, found '%c'\n", _curchar); |
1511 | break; |
1512 | } |
1513 | |
1514 | next_char(); skipws(); |
1515 | |
1516 | while (_curchar != ')') { |
1517 | ident = get_ident(); |
1518 | if (ident == NULL__null) { |
1519 | parse_err(SYNERR1, "expected identifier for nop instruction, found '%c'\n", _curchar); |
1520 | break; |
1521 | } |
1522 | |
1523 | pipeline->_noplist.addName(ident); |
1524 | pipeline->_nopcnt++; |
1525 | skipws(); |
1526 | |
1527 | if (_curchar == ',') { |
1528 | next_char(); skipws(); |
1529 | } |
1530 | } |
1531 | |
1532 | next_char(); skipws(); |
1533 | |
1534 | if (_curchar == ';') { |
1535 | next_char(); skipws(); |
1536 | } |
1537 | |
1538 | continue; |
1539 | } |
1540 | |
1541 | parse_err(SYNERR1, "unknown specifier \"%s\"\n", ident); |
1542 | } |
1543 | |
1544 | if ( (_curchar != '%') |
1545 | || ( next_char(), (_curchar != '}')) ) { |
1546 | parse_err(SYNERR1, "expected '%%}', found \"%c\"\n", _curchar); |
1547 | } |
1548 | next_char(); skipws(); |
1549 | |
1550 | if (pipeline->_maxInstrsPerBundle == 0) |
1551 | parse_err(SYNERR1, "\"max_instructions_per_bundle\" unspecified\n"); |
1552 | if (pipeline->_instrUnitSize == 0 && pipeline->_bundleUnitSize == 0) |
1553 | parse_err(SYNERR1, "\"instruction_unit_size\" and \"bundle_unit_size\" unspecified\n"); |
1554 | if (pipeline->_instrFetchUnitSize == 0) |
1555 | parse_err(SYNERR1, "\"instruction_fetch_unit_size\" unspecified\n"); |
1556 | if (pipeline->_instrFetchUnits == 0) |
1557 | parse_err(SYNERR1, "\"instruction_fetch_units\" unspecified\n"); |
1558 | if (!vsi_seen) |
1559 | parse_err(SYNERR1, "\"variable_size_instruction\" or \"fixed_size_instruction\" unspecified\n"); |
1560 | } |
1561 | else { // Done with staticly defined parts of instruction definition |
1562 | parse_err(SYNERR1, "expected one of \"resources\", \"pipe_desc\", \"pipe_class\", found \"%s\"\n", ident); |
1563 | return; |
1564 | } |
1565 | skipws(); |
1566 | if (_curchar == ';') |
1567 | skipws(); |
1568 | } while(_curchar != '%'); |
1569 | |
1570 | next_char(); |
1571 | if (_curchar != '}') { |
1572 | parse_err(SYNERR1, "missing \"%%}\" in pipeline definition\n"); |
1573 | return; |
1574 | } |
1575 | |
1576 | next_char(); |
1577 | } |
1578 | |
1579 | //------------------------------resource_parse---------------------------- |
1580 | void ADLParser::resource_parse(PipelineForm &pipeline) { |
1581 | ResourceForm *resource; |
1582 | char * ident; |
1583 | char * expr; |
1584 | unsigned mask; |
1585 | pipeline._rescount = 0; |
1586 | |
1587 | skipws(); // Skip leading whitespace |
1588 | |
1589 | if (_curchar != '(') { |
1590 | parse_err(SYNERR1, "missing \"(\" in resource definition\n"); |
1591 | return; |
1592 | } |
1593 | |
1594 | do { |
1595 | next_char(); // Skip "(" or "," |
1596 | ident = get_ident(); // Grab next identifier |
1597 | |
1598 | if (_AD._adl_debug > 1) { |
1599 | if (ident != NULL__null) { |
1600 | fprintf(stderrstderr, "resource_parse: identifier: %s\n", ident); |
1601 | } |
1602 | } |
1603 | |
1604 | if (ident == NULL__null) { |
1605 | parse_err(SYNERR1, "keyword identifier expected at \"%c\"\n", _curchar); |
1606 | return; |
1607 | } |
1608 | skipws(); |
1609 | |
1610 | if (_curchar != '=') { |
1611 | mask = (1 << pipeline._rescount++); |
1612 | } |
1613 | else { |
1614 | next_char(); skipws(); |
1615 | expr = get_ident(); // Grab next identifier |
1616 | if (expr == NULL__null) { |
1617 | parse_err(SYNERR1, "keyword identifier expected at \"%c\"\n", _curchar); |
1618 | return; |
1619 | } |
1620 | resource = (ResourceForm *) pipeline._resdict[expr]; |
1621 | if (resource == NULL__null) { |
1622 | parse_err(SYNERR1, "resource \"%s\" is not defined\n", expr); |
1623 | return; |
1624 | } |
1625 | mask = resource->mask(); |
1626 | |
1627 | skipws(); |
1628 | while (_curchar == '|') { |
1629 | next_char(); skipws(); |
1630 | |
1631 | expr = get_ident(); // Grab next identifier |
1632 | if (expr == NULL__null) { |
1633 | parse_err(SYNERR1, "keyword identifier expected at \"%c\"\n", _curchar); |
1634 | return; |
1635 | } |
1636 | |
1637 | resource = (ResourceForm *) pipeline._resdict[expr]; // Look up the value |
1638 | if (resource == NULL__null) { |
1639 | parse_err(SYNERR1, "resource \"%s\" is not defined\n", expr); |
1640 | return; |
1641 | } |
1642 | |
1643 | mask |= resource->mask(); |
1644 | skipws(); |
1645 | } |
1646 | } |
1647 | |
1648 | resource = new ResourceForm(mask); |
1649 | |
1650 | pipeline._resdict.Insert(ident, resource); |
1651 | pipeline._reslist.addName(ident); |
1652 | } while (_curchar == ','); |
1653 | |
1654 | if (_curchar != ')') { |
1655 | parse_err(SYNERR1, "\")\" expected at \"%c\"\n", _curchar); |
1656 | return; |
1657 | } |
1658 | |
1659 | next_char(); // Skip ")" |
1660 | if (_curchar == ';') |
1661 | next_char(); // Skip ";" |
1662 | } |
1663 | |
1664 | //------------------------------resource_parse---------------------------- |
1665 | void ADLParser::pipe_desc_parse(PipelineForm &pipeline) { |
1666 | char * ident; |
1667 | |
1668 | skipws(); // Skip leading whitespace |
1669 | |
1670 | if (_curchar != '(') { |
1671 | parse_err(SYNERR1, "missing \"(\" in pipe_desc definition\n"); |
1672 | return; |
1673 | } |
1674 | |
1675 | do { |
1676 | next_char(); // Skip "(" or "," |
1677 | ident = get_ident(); // Grab next identifier |
1678 | if (ident == NULL__null) { |
1679 | parse_err(SYNERR1, "keyword identifier expected at \"%c\"\n", _curchar); |
1680 | return; |
1681 | } |
1682 | |
1683 | // Add the name to the list |
1684 | pipeline._stages.addName(ident); |
1685 | pipeline._stagecnt++; |
1686 | |
1687 | skipws(); |
1688 | } while (_curchar == ','); |
1689 | |
1690 | if (_curchar != ')') { |
1691 | parse_err(SYNERR1, "\")\" expected at \"%c\"\n", _curchar); |
1692 | return; |
1693 | } |
1694 | |
1695 | next_char(); // Skip ")" |
1696 | if (_curchar == ';') |
1697 | next_char(); // Skip ";" |
1698 | } |
1699 | |
1700 | //------------------------------pipe_class_parse-------------------------- |
1701 | void ADLParser::pipe_class_parse(PipelineForm &pipeline) { |
1702 | PipeClassForm *pipe_class; |
1703 | char * ident; |
1704 | char * stage; |
1705 | char * read_or_write; |
1706 | int is_write; |
1707 | int is_read; |
1708 | OperandForm *oper; |
1709 | |
1710 | skipws(); // Skip leading whitespace |
1711 | |
1712 | ident = get_ident(); // Grab next identifier |
1713 | |
1714 | if (ident == NULL__null) { |
1715 | parse_err(SYNERR1, "keyword identifier expected at \"%c\"\n", _curchar); |
1716 | return; |
1717 | } |
1718 | |
1719 | // Create a record for the pipe_class |
1720 | pipe_class = new PipeClassForm(ident, ++pipeline._classcnt); |
1721 | pipeline._classdict.Insert(ident, pipe_class); |
1722 | pipeline._classlist.addName(ident); |
1723 | |
1724 | // Then get the operands |
1725 | skipws(); |
1726 | if (_curchar != '(') { |
1727 | parse_err(SYNERR1, "missing \"(\" in pipe_class definition\n"); |
1728 | } |
1729 | // Parse the operand list |
1730 | else get_oplist(pipe_class->_parameters, pipe_class->_localNames); |
1731 | skipws(); // Skip leading whitespace |
1732 | // Check for block delimiter |
1733 | if ( (_curchar != '%') |
1734 | || ( next_char(), (_curchar != '{')) ) { |
1735 | parse_err(SYNERR1, "missing \"%%{\" in pipe_class definition\n"); |
1736 | return; |
1737 | } |
1738 | next_char(); |
1739 | |
1740 | do { |
1741 | ident = get_ident(); // Grab next identifier |
1742 | if (ident == NULL__null) { |
1743 | parse_err(SYNERR1, "keyword identifier expected at \"%c\"\n", _curchar); |
1744 | continue; |
1745 | } |
1746 | skipws(); |
1747 | |
1748 | if (!strcmp(ident, "fixed_latency")) { |
1749 | skipws(); |
1750 | if (_curchar != '(') { |
1751 | parse_err(SYNERR1, "missing \"(\" in latency definition\n"); |
1752 | return; |
1753 | } |
1754 | next_char(); skipws(); |
1755 | if( !isdigit(_curchar) ) { |
1756 | parse_err(SYNERR1, "number expected for \"%c\" in latency definition\n", _curchar); |
1757 | return; |
1758 | } |
1759 | int fixed_latency = get_int(); |
1760 | skipws(); |
1761 | if (_curchar != ')') { |
1762 | parse_err(SYNERR1, "missing \")\" in latency definition\n"); |
1763 | return; |
1764 | } |
1765 | next_char(); skipws(); |
1766 | if (_curchar != ';') { |
1767 | parse_err(SYNERR1, "missing \";\" in latency definition\n"); |
1768 | return; |
1769 | } |
1770 | |
1771 | pipe_class->setFixedLatency(fixed_latency); |
1772 | next_char(); skipws(); |
1773 | continue; |
1774 | } |
1775 | |
1776 | if (!strcmp(ident, "zero_instructions") || |
1777 | !strcmp(ident, "no_instructions")) { |
1778 | skipws(); |
1779 | if (_curchar != ';') { |
1780 | parse_err(SYNERR1, "missing \";\" in latency definition\n"); |
1781 | return; |
1782 | } |
1783 | |
1784 | pipe_class->setInstructionCount(0); |
1785 | next_char(); skipws(); |
1786 | continue; |
1787 | } |
1788 | |
1789 | if (!strcmp(ident, "one_instruction_with_delay_slot") || |
1790 | !strcmp(ident, "single_instruction_with_delay_slot")) { |
1791 | skipws(); |
1792 | if (_curchar != ';') { |
1793 | parse_err(SYNERR1, "missing \";\" in latency definition\n"); |
1794 | return; |
1795 | } |
1796 | |
1797 | pipe_class->setInstructionCount(1); |
1798 | pipe_class->setBranchDelay(true); |
1799 | next_char(); skipws(); |
1800 | continue; |
1801 | } |
1802 | |
1803 | if (!strcmp(ident, "one_instruction") || |
1804 | !strcmp(ident, "single_instruction")) { |
1805 | skipws(); |
1806 | if (_curchar != ';') { |
1807 | parse_err(SYNERR1, "missing \";\" in latency definition\n"); |
1808 | return; |
1809 | } |
1810 | |
1811 | pipe_class->setInstructionCount(1); |
1812 | next_char(); skipws(); |
1813 | continue; |
1814 | } |
1815 | |
1816 | if (!strcmp(ident, "instructions_in_first_bundle") || |
1817 | !strcmp(ident, "instruction_count")) { |
1818 | skipws(); |
1819 | |
1820 | int number_of_instructions = 1; |
1821 | |
1822 | if (_curchar != '(') { |
1823 | parse_err(SYNERR1, "\"(\" expected at \"%c\"\n", _curchar); |
1824 | continue; |
1825 | } |
1826 | |
1827 | next_char(); skipws(); |
1828 | number_of_instructions = get_int(); |
1829 | |
1830 | skipws(); |
1831 | if (_curchar != ')') { |
1832 | parse_err(SYNERR1, "\")\" expected at \"%c\"\n", _curchar); |
1833 | continue; |
1834 | } |
1835 | |
1836 | next_char(); skipws(); |
1837 | if (_curchar != ';') { |
1838 | parse_err(SYNERR1, "missing \";\" in latency definition\n"); |
1839 | return; |
1840 | } |
1841 | |
1842 | pipe_class->setInstructionCount(number_of_instructions); |
1843 | next_char(); skipws(); |
1844 | continue; |
1845 | } |
1846 | |
1847 | if (!strcmp(ident, "multiple_bundles")) { |
1848 | skipws(); |
1849 | if (_curchar != ';') { |
1850 | parse_err(SYNERR1, "missing \";\" after multiple bundles\n"); |
1851 | return; |
1852 | } |
1853 | |
1854 | pipe_class->setMultipleBundles(true); |
1855 | next_char(); skipws(); |
1856 | continue; |
1857 | } |
1858 | |
1859 | if (!strcmp(ident, "has_delay_slot")) { |
1860 | skipws(); |
1861 | if (_curchar != ';') { |
1862 | parse_err(SYNERR1, "missing \";\" after \"has_delay_slot\"\n"); |
1863 | return; |
1864 | } |
1865 | |
1866 | pipe_class->setBranchDelay(true); |
1867 | next_char(); skipws(); |
1868 | continue; |
1869 | } |
1870 | |
1871 | if (!strcmp(ident, "force_serialization")) { |
1872 | skipws(); |
1873 | if (_curchar != ';') { |
1874 | parse_err(SYNERR1, "missing \";\" after \"force_serialization\"\n"); |
1875 | return; |
1876 | } |
1877 | |
1878 | pipe_class->setForceSerialization(true); |
1879 | next_char(); skipws(); |
1880 | continue; |
1881 | } |
1882 | |
1883 | if (!strcmp(ident, "may_have_no_code")) { |
1884 | skipws(); |
1885 | if (_curchar != ';') { |
1886 | parse_err(SYNERR1, "missing \";\" after \"may_have_no_code\"\n"); |
1887 | return; |
1888 | } |
1889 | |
1890 | pipe_class->setMayHaveNoCode(true); |
1891 | next_char(); skipws(); |
1892 | continue; |
1893 | } |
1894 | |
1895 | const Form *parm = pipe_class->_localNames[ident]; |
1896 | if (parm != NULL__null) { |
1897 | oper = parm->is_operand(); |
1898 | if (oper == NULL__null && !parm->is_opclass()) { |
1899 | parse_err(SYNERR1, "operand name expected at %s\n", ident); |
1900 | continue; |
1901 | } |
1902 | |
1903 | if (_curchar != ':') { |
1904 | parse_err(SYNERR1, "\":\" expected at \"%c\"\n", _curchar); |
1905 | continue; |
1906 | } |
1907 | next_char(); skipws(); |
1908 | stage = get_ident(); |
1909 | if (stage == NULL__null) { |
1910 | parse_err(SYNERR1, "pipeline stage identifier expected at \"%c\"\n", _curchar); |
1911 | continue; |
1912 | } |
1913 | |
1914 | skipws(); |
1915 | if (_curchar != '(') { |
1916 | parse_err(SYNERR1, "\"(\" expected at \"%c\"\n", _curchar); |
1917 | continue; |
1918 | } |
1919 | |
1920 | next_char(); |
1921 | read_or_write = get_ident(); |
1922 | if (read_or_write == NULL__null) { |
1923 | parse_err(SYNERR1, "\"read\" or \"write\" expected at \"%c\"\n", _curchar); |
1924 | continue; |
1925 | } |
1926 | |
1927 | is_read = strcmp(read_or_write, "read") == 0; |
1928 | is_write = strcmp(read_or_write, "write") == 0; |
1929 | if (!is_read && !is_write) { |
1930 | parse_err(SYNERR1, "\"read\" or \"write\" expected at \"%c\"\n", _curchar); |
1931 | continue; |
1932 | } |
1933 | |
1934 | skipws(); |
1935 | if (_curchar != ')') { |
1936 | parse_err(SYNERR1, "\")\" expected at \"%c\"\n", _curchar); |
1937 | continue; |
1938 | } |
1939 | |
1940 | next_char(); skipws(); |
1941 | int more_instrs = 0; |
1942 | if (_curchar == '+') { |
1943 | next_char(); skipws(); |
1944 | if (_curchar < '0' || _curchar > '9') { |
1945 | parse_err(SYNERR1, "<number> expected at \"%c\"\n", _curchar); |
1946 | continue; |
1947 | } |
1948 | while (_curchar >= '0' && _curchar <= '9') { |
1949 | more_instrs *= 10; |
1950 | more_instrs += _curchar - '0'; |
1951 | next_char(); |
1952 | } |
1953 | skipws(); |
1954 | } |
1955 | |
1956 | PipeClassOperandForm *pipe_operand = new PipeClassOperandForm(stage, is_write, more_instrs); |
1957 | pipe_class->_localUsage.Insert(ident, pipe_operand); |
1958 | |
1959 | if (_curchar == '%') |
1960 | continue; |
1961 | |
1962 | if (_curchar != ';') { |
1963 | parse_err(SYNERR1, "\";\" expected at \"%c\"\n", _curchar); |
1964 | continue; |
1965 | } |
1966 | next_char(); skipws(); |
1967 | continue; |
1968 | } |
1969 | |
1970 | // Scan for Resource Specifier |
1971 | const Form *res = pipeline._resdict[ident]; |
1972 | if (res != NULL__null) { |
1973 | int cyclecnt = 1; |
1974 | if (_curchar != ':') { |
1975 | parse_err(SYNERR1, "\":\" expected at \"%c\"\n", _curchar); |
1976 | continue; |
1977 | } |
1978 | next_char(); skipws(); |
1979 | stage = get_ident(); |
1980 | if (stage == NULL__null) { |
1981 | parse_err(SYNERR1, "pipeline stage identifier expected at \"%c\"\n", _curchar); |
1982 | continue; |
1983 | } |
1984 | |
1985 | skipws(); |
1986 | if (_curchar == '(') { |
1987 | next_char(); |
1988 | cyclecnt = get_int(); |
1989 | |
1990 | skipws(); |
1991 | if (_curchar != ')') { |
1992 | parse_err(SYNERR1, "\")\" expected at \"%c\"\n", _curchar); |
1993 | continue; |
1994 | } |
1995 | |
1996 | next_char(); skipws(); |
1997 | } |
1998 | |
1999 | PipeClassResourceForm *resource = new PipeClassResourceForm(ident, stage, cyclecnt); |
2000 | int stagenum = pipeline._stages.index(stage); |
2001 | if (pipeline._maxcycleused < (stagenum+cyclecnt)) |
2002 | pipeline._maxcycleused = (stagenum+cyclecnt); |
2003 | pipe_class->_resUsage.addForm(resource); |
2004 | |
2005 | if (_curchar == '%') |
2006 | continue; |
2007 | |
2008 | if (_curchar != ';') { |
2009 | parse_err(SYNERR1, "\";\" expected at \"%c\"\n", _curchar); |
2010 | continue; |
2011 | } |
2012 | next_char(); skipws(); |
2013 | continue; |
2014 | } |
2015 | |
2016 | parse_err(SYNERR1, "resource expected at \"%s\"\n", ident); |
2017 | return; |
2018 | } while(_curchar != '%'); |
2019 | |
2020 | next_char(); |
2021 | if (_curchar != '}') { |
2022 | parse_err(SYNERR1, "missing \"%%}\" in pipe_class definition\n"); |
2023 | return; |
2024 | } |
2025 | |
2026 | next_char(); |
2027 | } |
2028 | |
2029 | //------------------------------peep_parse------------------------------------- |
2030 | void ADLParser::peep_parse(void) { |
2031 | Peephole *peep; // Pointer to current peephole rule form |
2032 | char *desc = NULL__null; // String representation of rule |
2033 | |
2034 | skipws(); // Skip leading whitespace |
2035 | |
2036 | peep = new Peephole(); // Build new Peephole object |
2037 | // Check for open block sequence |
2038 | skipws(); // Skip leading whitespace |
2039 | if (_curchar == '%' && *(_ptr+1) == '{') { |
2040 | next_char(); next_char(); // Skip "%{" |
2041 | skipws(); |
2042 | while (_curchar != '%' && *(_ptr+1) != '}') { |
2043 | char *token = get_ident(); |
2044 | if (token == NULL__null) { |
2045 | parse_err(SYNERR1, "missing identifier inside peephole rule.\n"); |
2046 | return; |
2047 | } |
2048 | // check for legal subsections of peephole rule |
2049 | if (strcmp(token,"peepmatch")==0) { |
2050 | peep_match_parse(*peep); } |
2051 | else if (strcmp(token,"peepconstraint")==0) { |
2052 | peep_constraint_parse(*peep); } |
2053 | else if (strcmp(token,"peepreplace")==0) { |
2054 | peep_replace_parse(*peep); } |
2055 | else { |
2056 | parse_err(SYNERR1, "expected peepmatch, peepconstraint, or peepreplace for identifier %s.\n", token); |
2057 | } |
2058 | skipws(); |
2059 | } |
2060 | } |
2061 | else { |
2062 | parse_err(SYNERR1, "Missing %%{ ... %%} block after peephole keyword.\n"); |
2063 | return; |
2064 | } |
2065 | next_char(); // Skip past '%' |
2066 | next_char(); // Skip past '}' |
2067 | } |
2068 | |
2069 | // ******************** Private Level 2 Parse Functions ******************** |
2070 | //------------------------------constraint_parse------------------------------ |
2071 | Constraint *ADLParser::constraint_parse(void) { |
2072 | char *func; |
2073 | char *arg; |
2074 | |
2075 | // Check for constraint expression |
2076 | skipws(); |
2077 | if (_curchar != '(') { |
2078 | parse_err(SYNERR1, "missing constraint expression, (...)\n"); |
2079 | return NULL__null; |
2080 | } |
2081 | next_char(); // Skip past '(' |
2082 | |
2083 | // Get constraint function |
2084 | skipws(); |
2085 | func = get_ident(); |
2086 | if (func == NULL__null) { |
2087 | parse_err(SYNERR1, "missing function in constraint expression.\n"); |
2088 | return NULL__null; |
2089 | } |
2090 | if (strcmp(func,"ALLOC_IN_RC")==0 |
2091 | || strcmp(func,"IS_R_CLASS")==0) { |
2092 | // Check for '(' before argument |
2093 | skipws(); |
2094 | if (_curchar != '(') { |
2095 | parse_err(SYNERR1, "missing '(' for constraint function's argument.\n"); |
2096 | return NULL__null; |
2097 | } |
2098 | next_char(); |
2099 | |
2100 | // Get it's argument |
2101 | skipws(); |
2102 | arg = get_ident(); |
2103 | if (arg == NULL__null) { |
2104 | parse_err(SYNERR1, "missing argument for constraint function %s\n",func); |
2105 | return NULL__null; |
2106 | } |
2107 | // Check for ')' after argument |
2108 | skipws(); |
2109 | if (_curchar != ')') { |
2110 | parse_err(SYNERR1, "missing ')' after constraint function argument %s\n",arg); |
2111 | return NULL__null; |
2112 | } |
2113 | next_char(); |
2114 | } else { |
2115 | parse_err(SYNERR1, "Invalid constraint function %s\n",func); |
2116 | return NULL__null; |
2117 | } |
2118 | |
2119 | // Check for closing paren and ';' |
2120 | skipws(); |
2121 | if (_curchar != ')') { |
2122 | parse_err(SYNERR1, "Missing ')' for constraint function %s\n",func); |
2123 | return NULL__null; |
2124 | } |
2125 | next_char(); |
2126 | skipws(); |
2127 | if (_curchar != ';') { |
2128 | parse_err(SYNERR1, "Missing ';' after constraint.\n"); |
2129 | return NULL__null; |
2130 | } |
2131 | next_char(); |
2132 | |
2133 | // Create new "Constraint" |
2134 | Constraint *constraint = new Constraint(func,arg); |
2135 | return constraint; |
2136 | } |
2137 | |
2138 | //------------------------------constr_parse----------------------------------- |
2139 | ConstructRule *ADLParser::construct_parse(void) { |
2140 | return NULL__null; |
2141 | } |
2142 | |
2143 | |
2144 | //------------------------------reg_def_parse---------------------------------- |
2145 | void ADLParser::reg_def_parse(void) { |
2146 | char *rname; // Name of register being defined |
2147 | |
2148 | // Get register name |
2149 | skipws(); // Skip whitespace |
2150 | rname = get_ident(); |
2151 | if (rname == NULL__null) { |
2152 | parse_err(SYNERR1, "missing register name after reg_def\n"); |
2153 | return; |
2154 | } |
2155 | |
2156 | // Check for definition of register calling convention (save on call, ...), |
2157 | // register save type, and register encoding value. |
2158 | skipws(); |
2159 | char *callconv = NULL__null; |
2160 | char *c_conv = NULL__null; |
2161 | char *idealtype = NULL__null; |
2162 | char *encoding = NULL__null; |
2163 | char *concrete = NULL__null; |
2164 | if (_curchar == '(') { |
2165 | next_char(); |
2166 | callconv = get_ident(); |
2167 | // Parse the internal calling convention, must be NS, SOC, SOE, or AS. |
2168 | if (callconv == NULL__null) { |
2169 | parse_err(SYNERR1, "missing register calling convention value\n"); |
2170 | return; |
2171 | } |
2172 | if(strcmp(callconv, "SOC") && strcmp(callconv,"SOE") && |
2173 | strcmp(callconv, "NS") && strcmp(callconv, "AS")) { |
2174 | parse_err(SYNERR1, "invalid value for register calling convention\n"); |
2175 | } |
2176 | skipws(); |
2177 | if (_curchar != ',') { |
2178 | parse_err(SYNERR1, "missing comma in register definition statement\n"); |
2179 | return; |
2180 | } |
2181 | next_char(); |
2182 | |
2183 | // Parse the native calling convention, must be NS, SOC, SOE, AS |
2184 | c_conv = get_ident(); |
2185 | if (c_conv == NULL__null) { |
2186 | parse_err(SYNERR1, "missing register native calling convention value\n"); |
2187 | return; |
2188 | } |
2189 | if(strcmp(c_conv, "SOC") && strcmp(c_conv,"SOE") && |
2190 | strcmp(c_conv, "NS") && strcmp(c_conv, "AS")) { |
2191 | parse_err(SYNERR1, "invalid value for register calling convention\n"); |
2192 | } |
2193 | skipws(); |
2194 | if (_curchar != ',') { |
2195 | parse_err(SYNERR1, "missing comma in register definition statement\n"); |
2196 | return; |
2197 | } |
2198 | next_char(); |
2199 | skipws(); |
2200 | |
2201 | // Parse the ideal save type |
2202 | idealtype = get_ident(); |
2203 | if (idealtype == NULL__null) { |
2204 | parse_err(SYNERR1, "missing register save type value\n"); |
2205 | return; |
2206 | } |
2207 | skipws(); |
2208 | if (_curchar != ',') { |
2209 | parse_err(SYNERR1, "missing comma in register definition statement\n"); |
2210 | return; |
2211 | } |
2212 | next_char(); |
2213 | skipws(); |
2214 | |
2215 | // Parse the encoding value |
2216 | encoding = get_expr("encoding", ","); |
2217 | if (encoding == NULL__null) { |
2218 | parse_err(SYNERR1, "missing register encoding value\n"); |
2219 | return; |
2220 | } |
2221 | trim(encoding); |
2222 | if (_curchar != ',') { |
2223 | parse_err(SYNERR1, "missing comma in register definition statement\n"); |
2224 | return; |
2225 | } |
2226 | next_char(); |
2227 | skipws(); |
2228 | // Parse the concrete name type |
2229 | // concrete = get_ident(); |
2230 | concrete = get_expr("concrete", ")"); |
2231 | if (concrete == NULL__null) { |
2232 | parse_err(SYNERR1, "missing vm register name value\n"); |
2233 | return; |
2234 | } |
2235 | |
2236 | if (_curchar != ')') { |
2237 | parse_err(SYNERR1, "missing ')' in register definition statement\n"); |
2238 | return; |
2239 | } |
2240 | next_char(); |
2241 | } |
2242 | |
2243 | // Check for closing ';' |
2244 | skipws(); |
2245 | if (_curchar != ';') { |
2246 | parse_err(SYNERR1, "missing ';' after reg_def\n"); |
2247 | return; |
2248 | } |
2249 | next_char(); // move past ';' |
2250 | |
2251 | // Debug Stuff |
2252 | if (_AD._adl_debug > 1) { |
2253 | fprintf(stderrstderr,"Register Definition: %s ( %s, %s %s )\n", rname, |
2254 | (callconv ? callconv : ""), (c_conv ? c_conv : ""), concrete); |
2255 | } |
2256 | |
2257 | // Record new register definition. |
2258 | _AD._register->addRegDef(rname, callconv, c_conv, idealtype, encoding, concrete); |
2259 | return; |
2260 | } |
2261 | |
2262 | //------------------------------reg_class_parse-------------------------------- |
2263 | void ADLParser::reg_class_parse(void) { |
2264 | char *cname; // Name of register class being defined |
2265 | |
2266 | // Get register class name |
2267 | skipws(); // Skip leading whitespace |
2268 | cname = get_ident(); |
2269 | if (cname == NULL__null) { |
2270 | parse_err(SYNERR1, "missing register class name after 'reg_class'\n"); |
2271 | return; |
2272 | } |
2273 | // Debug Stuff |
2274 | if (_AD._adl_debug >1) fprintf(stderrstderr,"Register Class: %s\n", cname); |
2275 | |
2276 | skipws(); |
2277 | if (_curchar == '(') { |
2278 | // A register list is defined for the register class. |
2279 | // Collect registers into a generic RegClass register class. |
2280 | RegClass* reg_class = _AD._register->addRegClass<RegClass>(cname); |
2281 | |
2282 | next_char(); // Skip '(' |
2283 | skipws(); |
2284 | while (_curchar != ')') { |
2285 | char *rname = get_ident(); |
2286 | if (rname==NULL__null) { |
2287 | parse_err(SYNERR1, "missing identifier inside reg_class list.\n"); |
2288 | return; |
2289 | } |
2290 | RegDef *regDef = _AD._register->getRegDef(rname); |
2291 | if (!regDef) { |
2292 | parse_err(SEMERR2, "unknown identifier %s inside reg_class list.\n", rname); |
2293 | } else { |
2294 | reg_class->addReg(regDef); // add regDef to regClass |
2295 | } |
2296 | |
2297 | // Check for ',' and position to next token. |
2298 | skipws(); |
2299 | if (_curchar == ',') { |
2300 | next_char(); // Skip trailing ',' |
2301 | skipws(); |
2302 | } |
2303 | } |
2304 | next_char(); // Skip closing ')' |
2305 | } else if (_curchar == '%') { |
2306 | // A code snippet is defined for the register class. |
2307 | // Collect the code snippet into a CodeSnippetRegClass register class. |
2308 | CodeSnippetRegClass* reg_class = _AD._register->addRegClass<CodeSnippetRegClass>(cname); |
2309 | char *code = find_cpp_block("reg class"); |
2310 | if (code == NULL__null) { |
2311 | parse_err(SYNERR1, "missing code declaration for reg class.\n"); |
2312 | return; |
2313 | } |
2314 | reg_class->set_code_snippet(code); |
2315 | return; |
2316 | } |
2317 | |
2318 | // Check for terminating ';' |
2319 | skipws(); |
2320 | if (_curchar != ';') { |
2321 | parse_err(SYNERR1, "missing ';' at end of reg_class definition.\n"); |
2322 | return; |
2323 | } |
2324 | next_char(); // Skip trailing ';' |
2325 | |
2326 | // Check RegClass size, must be <= 32 registers in class. |
2327 | |
2328 | return; |
2329 | } |
2330 | |
2331 | //------------------------------reg_class_dynamic_parse------------------------ |
2332 | void ADLParser::reg_class_dynamic_parse(void) { |
2333 | char *cname; // Name of dynamic register class being defined |
2334 | |
2335 | // Get register class name |
2336 | skipws(); |
2337 | cname = get_ident(); |
2338 | if (cname == NULL__null) { |
2339 | parse_err(SYNERR1, "missing dynamic register class name after 'reg_class_dynamic'\n"); |
2340 | return; |
2341 | } |
2342 | |
2343 | if (_AD._adl_debug > 1) { |
2344 | fprintf(stdoutstdout, "Dynamic Register Class: %s\n", cname); |
2345 | } |
2346 | |
2347 | skipws(); |
2348 | if (_curchar != '(') { |
2349 | parse_err(SYNERR1, "missing '(' at the beginning of reg_class_dynamic definition\n"); |
2350 | return; |
2351 | } |
2352 | next_char(); |
2353 | skipws(); |
2354 | |
2355 | // Collect two register classes and the C++ code representing the condition code used to |
2356 | // select between the two classes into a ConditionalRegClass register class. |
2357 | ConditionalRegClass* reg_class = _AD._register->addRegClass<ConditionalRegClass>(cname); |
2358 | int i; |
2359 | for (i = 0; i < 2; i++) { |
2360 | char* name = get_ident(); |
2361 | if (name == NULL__null) { |
2362 | parse_err(SYNERR1, "missing class identifier inside reg_class_dynamic list.\n"); |
2363 | return; |
2364 | } |
2365 | RegClass* rc = _AD._register->getRegClass(name); |
2366 | if (rc == NULL__null) { |
2367 | parse_err(SEMERR2, "unknown identifier %s inside reg_class_dynamic list.\n", name); |
2368 | } else { |
2369 | reg_class->set_rclass_at_index(i, rc); |
2370 | } |
2371 | |
2372 | skipws(); |
2373 | if (_curchar == ',') { |
2374 | next_char(); |
2375 | skipws(); |
2376 | } else { |
2377 | parse_err(SYNERR1, "missing separator ',' inside reg_class_dynamic list.\n"); |
2378 | } |
2379 | } |
2380 | |
2381 | // Collect the condition code. |
2382 | skipws(); |
2383 | if (_curchar == '%') { |
2384 | char* code = find_cpp_block("reg class dynamic"); |
2385 | if (code == NULL__null) { |
2386 | parse_err(SYNERR1, "missing code declaration for reg_class_dynamic.\n"); |
2387 | return; |
2388 | } |
2389 | reg_class->set_condition_code(code); |
2390 | } else { |
2391 | parse_err(SYNERR1, "missing %% at the beginning of code block in reg_class_dynamic definition\n"); |
2392 | return; |
2393 | } |
2394 | |
2395 | skipws(); |
2396 | if (_curchar != ')') { |
2397 | parse_err(SYNERR1, "missing ')' at the end of reg_class_dynamic definition\n"); |
2398 | return; |
2399 | } |
2400 | next_char(); |
2401 | |
2402 | skipws(); |
2403 | if (_curchar != ';') { |
2404 | parse_err(SYNERR1, "missing ';' at the end of reg_class_dynamic definition.\n"); |
2405 | return; |
2406 | } |
2407 | next_char(); // Skip trailing ';' |
2408 | |
2409 | return; |
2410 | } |
2411 | |
2412 | //------------------------------alloc_class_parse------------------------------ |
2413 | void ADLParser::alloc_class_parse(void) { |
2414 | char *name; // Name of allocation class being defined |
2415 | |
2416 | // Get allocation class name |
2417 | skipws(); // Skip leading whitespace |
2418 | name = get_ident(); |
2419 | if (name == NULL__null) { |
2420 | parse_err(SYNERR1, "missing allocation class name after 'reg_class'\n"); |
2421 | return; |
2422 | } |
2423 | // Debug Stuff |
2424 | if (_AD._adl_debug >1) fprintf(stderrstderr,"Allocation Class: %s\n", name); |
2425 | |
2426 | AllocClass *alloc_class = _AD._register->addAllocClass(name); |
2427 | |
2428 | // Collect registers in class |
2429 | skipws(); |
2430 | if (_curchar == '(') { |
2431 | next_char(); // Skip '(' |
2432 | skipws(); |
2433 | while (_curchar != ')') { |
2434 | char *rname = get_ident(); |
2435 | if (rname==NULL__null) { |
2436 | parse_err(SYNERR1, "missing identifier inside reg_class list.\n"); |
2437 | return; |
2438 | } |
2439 | // Check if name is a RegDef |
2440 | RegDef *regDef = _AD._register->getRegDef(rname); |
2441 | if (regDef) { |
2442 | alloc_class->addReg(regDef); // add regDef to allocClass |
2443 | } else { |
2444 | |
2445 | // name must be a RegDef or a RegClass |
2446 | parse_err(SYNERR1, "name %s should be a previously defined reg_def.\n", rname); |
2447 | return; |
2448 | } |
2449 | |
2450 | // Check for ',' and position to next token. |
2451 | skipws(); |
2452 | if (_curchar == ',') { |
2453 | next_char(); // Skip trailing ',' |
2454 | skipws(); |
2455 | } |
2456 | } |
2457 | next_char(); // Skip closing ')' |
2458 | } |
2459 | |
2460 | // Check for terminating ';' |
2461 | skipws(); |
2462 | if (_curchar != ';') { |
2463 | parse_err(SYNERR1, "missing ';' at end of reg_class definition.\n"); |
2464 | return; |
2465 | } |
2466 | next_char(); // Skip trailing ';' |
2467 | |
2468 | return; |
2469 | } |
2470 | |
2471 | //------------------------------peep_match_child_parse------------------------- |
2472 | InstructForm *ADLParser::peep_match_child_parse(PeepMatch &match, int parent, int &position, int input){ |
2473 | char *token = NULL__null; |
2474 | int lparen = 0; // keep track of parenthesis nesting depth |
2475 | int rparen = 0; // position of instruction at this depth |
2476 | InstructForm *inst_seen = NULL__null; |
2477 | |
2478 | // Walk the match tree, |
2479 | // Record <parent, position, instruction name, input position> |
2480 | while ( lparen >= rparen ) { |
2481 | skipws(); |
2482 | // Left paren signals start of an input, collect with recursive call |
2483 | if (_curchar == '(') { |
2484 | ++lparen; |
2485 | next_char(); |
2486 | ( void ) peep_match_child_parse(match, parent, position, rparen); |
2487 | } |
2488 | // Right paren signals end of an input, may be more |
2489 | else if (_curchar == ')') { |
2490 | ++rparen; |
2491 | if( rparen == lparen ) { // IF rparen matches an lparen I've seen |
2492 | next_char(); // move past ')' |
2493 | } else { // ELSE leave ')' for parent |
2494 | assert( rparen == lparen + 1, "Should only see one extra ')'"){ if (!(rparen == lparen + 1)) { fprintf(stderr, "assert fails %s %d: %s\n" , "/home/daniel/Projects/java/jdk/src/hotspot/share/adlc/adlparse.cpp" , 2494, "Should only see one extra ')'"); abort(); }}; |
2495 | // if an instruction was not specified for this paren-pair |
2496 | if( ! inst_seen ) { // record signal entry |
2497 | match.add_instruction( parent, position, NameList::_signal, input ); |
2498 | ++position; |
2499 | } |
2500 | // ++input; // TEMPORARY |
2501 | return inst_seen; |
2502 | } |
2503 | } |
2504 | // if no parens, then check for instruction name |
2505 | // This instruction is the parent of a sub-tree |
2506 | else if ((token = get_ident_dup()) != NULL__null) { |
2507 | const Form *form = _AD._globalNames[token]; |
2508 | if (form) { |
2509 | InstructForm *inst = form->is_instruction(); |
2510 | // Record the first instruction at this level |
2511 | if( inst_seen == NULL__null ) { |
2512 | inst_seen = inst; |
2513 | } |
2514 | if (inst) { |
2515 | match.add_instruction( parent, position, token, input ); |
2516 | parent = position; |
2517 | ++position; |
2518 | } else { |
2519 | parse_err(SYNERR1, "instruction name expected at identifier %s.\n", |
2520 | token); |
2521 | return inst_seen; |
2522 | } |
2523 | } |
2524 | else { |
2525 | parse_err(SYNERR1, "missing identifier in peepmatch rule.\n"); |
2526 | return NULL__null; |
2527 | } |
2528 | } |
2529 | else { |
2530 | parse_err(SYNERR1, "missing identifier in peepmatch rule.\n"); |
2531 | return NULL__null; |
2532 | } |
2533 | |
2534 | } // end while |
2535 | |
2536 | assert( false, "ShouldNotReachHere();"){ if (!(false)) { fprintf(stderr, "assert fails %s %d: %s\n", "/home/daniel/Projects/java/jdk/src/hotspot/share/adlc/adlparse.cpp" , 2536, "ShouldNotReachHere();"); abort(); }}; |
2537 | return NULL__null; |
2538 | } |
2539 | |
2540 | //------------------------------peep_match_parse------------------------------- |
2541 | // Syntax for a peepmatch rule |
2542 | // |
2543 | // peepmatch ( root_instr_name [(instruction subtree)] [,(instruction subtree)]* ); |
2544 | // |
2545 | void ADLParser::peep_match_parse(Peephole &peep) { |
2546 | |
2547 | skipws(); |
2548 | // Check the structure of the rule |
2549 | // Check for open paren |
2550 | if (_curchar != '(') { |
2551 | parse_err(SYNERR1, "missing '(' at start of peepmatch rule.\n"); |
2552 | return; |
2553 | } |
2554 | next_char(); // skip '(' |
2555 | |
2556 | // Construct PeepMatch and parse the peepmatch rule. |
2557 | PeepMatch *match = new PeepMatch(_ptr); |
2558 | int parent = -1; // parent of root |
2559 | int position = 0; // zero-based positions |
2560 | int input = 0; // input position in parent's operands |
2561 | InstructForm *root= peep_match_child_parse( *match, parent, position, input); |
2562 | if( root == NULL__null ) { |
2563 | parse_err(SYNERR1, "missing instruction-name at start of peepmatch.\n"); |
2564 | return; |
2565 | } |
2566 | |
2567 | if( _curchar != ')' ) { |
2568 | parse_err(SYNERR1, "missing ')' at end of peepmatch.\n"); |
2569 | return; |
2570 | } |
2571 | next_char(); // skip ')' |
2572 | |
2573 | // Check for closing semicolon |
2574 | skipws(); |
2575 | if( _curchar != ';' ) { |
2576 | parse_err(SYNERR1, "missing ';' at end of peepmatch.\n"); |
2577 | return; |
2578 | } |
2579 | next_char(); // skip ';' |
2580 | |
2581 | // Store match into peep, and store peep into instruction |
2582 | peep.add_match(match); |
2583 | root->append_peephole(&peep); |
2584 | } |
2585 | |
2586 | //------------------------------peep_constraint_parse-------------------------- |
2587 | // Syntax for a peepconstraint rule |
2588 | // A parenthesized list of relations between operands in peepmatch subtree |
2589 | // |
2590 | // peepconstraint %{ |
2591 | // (instruction_number.operand_name |
2592 | // relational_op |
2593 | // instruction_number.operand_name OR register_name |
2594 | // [, ...] ); |
2595 | // |
2596 | // // instruction numbers are zero-based using topological order in peepmatch |
2597 | // |
2598 | void ADLParser::peep_constraint_parse(Peephole &peep) { |
2599 | |
2600 | skipws(); |
2601 | // Check the structure of the rule |
2602 | // Check for open paren |
2603 | if (_curchar != '(') { |
2604 | parse_err(SYNERR1, "missing '(' at start of peepconstraint rule.\n"); |
2605 | return; |
2606 | } |
2607 | else { |
2608 | next_char(); // Skip '(' |
2609 | } |
2610 | |
2611 | // Check for a constraint |
2612 | skipws(); |
2613 | while( _curchar != ')' ) { |
2614 | // Get information on the left instruction and its operand |
2615 | // left-instructions's number |
2616 | int left_inst = get_int(); |
2617 | // Left-instruction's operand |
2618 | skipws(); |
2619 | if( _curchar != '.' ) { |
2620 | parse_err(SYNERR1, "missing '.' in peepconstraint after instruction number.\n"); |
2621 | return; |
2622 | } |
2623 | next_char(); // Skip '.' |
2624 | char *left_op = get_ident_dup(); |
2625 | |
2626 | skipws(); |
2627 | // Collect relational operator |
2628 | char *relation = get_relation_dup(); |
2629 | |
2630 | skipws(); |
2631 | // Get information on the right instruction and its operand |
2632 | int right_inst; // Right-instructions's number |
2633 | if( isdigit(_curchar) ) { |
2634 | right_inst = get_int(); |
2635 | // Right-instruction's operand |
2636 | skipws(); |
2637 | if( _curchar != '.' ) { |
2638 | parse_err(SYNERR1, "missing '.' in peepconstraint after instruction number.\n"); |
2639 | return; |
2640 | } |
2641 | next_char(); // Skip '.' |
2642 | } else { |
2643 | right_inst = -1; // Flag as being a register constraint |
2644 | } |
2645 | |
2646 | char *right_op = get_ident_dup(); |
2647 | |
2648 | // Construct the next PeepConstraint |
2649 | PeepConstraint *constraint = new PeepConstraint( left_inst, left_op, |
2650 | relation, |
2651 | right_inst, right_op ); |
2652 | // And append it to the list for this peephole rule |
2653 | peep.append_constraint( constraint ); |
2654 | |
2655 | // Check for another constraint, or end of rule |
2656 | skipws(); |
2657 | if( _curchar == ',' ) { |
2658 | next_char(); // Skip ',' |
2659 | skipws(); |
2660 | } |
2661 | else if( _curchar != ')' ) { |
2662 | parse_err(SYNERR1, "expected ',' or ')' after peephole constraint.\n"); |
2663 | return; |
2664 | } |
2665 | } // end while( processing constraints ) |
2666 | next_char(); // Skip ')' |
2667 | |
2668 | // Check for terminating ';' |
2669 | skipws(); |
2670 | if (_curchar != ';') { |
2671 | parse_err(SYNERR1, "missing ';' at end of peepconstraint.\n"); |
2672 | return; |
2673 | } |
2674 | next_char(); // Skip trailing ';' |
2675 | } |
2676 | |
2677 | |
2678 | //------------------------------peep_replace_parse----------------------------- |
2679 | // Syntax for a peepreplace rule |
2680 | // root instruction name followed by a |
2681 | // parenthesized list of whitespace separated instruction.operand specifiers |
2682 | // |
2683 | // peepreplace ( instr_name ( [instruction_number.operand_name]* ) ); |
2684 | // |
2685 | // |
2686 | void ADLParser::peep_replace_parse(Peephole &peep) { |
2687 | int lparen = 0; // keep track of parenthesis nesting depth |
2688 | int rparen = 0; // keep track of parenthesis nesting depth |
2689 | int icount = 0; // count of instructions in rule for naming |
2690 | char *str = NULL__null; |
2691 | char *token = NULL__null; |
2692 | |
2693 | skipws(); |
2694 | // Check for open paren |
2695 | if (_curchar != '(') { |
2696 | parse_err(SYNERR1, "missing '(' at start of peepreplace rule.\n"); |
2697 | return; |
2698 | } |
2699 | else { |
2700 | lparen++; |
2701 | next_char(); |
2702 | } |
2703 | |
2704 | // Check for root instruction |
2705 | char *inst = get_ident_dup(); |
2706 | const Form *form = _AD._globalNames[inst]; |
2707 | if( form == NULL__null || form->is_instruction() == NULL__null ) { |
2708 | parse_err(SYNERR1, "Instruction name expected at start of peepreplace.\n"); |
2709 | return; |
2710 | } |
2711 | |
2712 | // Store string representation of rule into replace |
2713 | PeepReplace *replace = new PeepReplace(str); |
2714 | replace->add_instruction( inst ); |
2715 | |
2716 | skipws(); |
2717 | // Start of root's operand-list |
2718 | if (_curchar != '(') { |
2719 | parse_err(SYNERR1, "missing '(' at peepreplace root's operand-list.\n"); |
2720 | return; |
2721 | } |
2722 | else { |
2723 | lparen++; |
2724 | next_char(); |
2725 | } |
2726 | |
2727 | skipws(); |
2728 | // Get the list of operands |
2729 | while( _curchar != ')' ) { |
2730 | // Get information on an instruction and its operand |
2731 | // instructions's number |
2732 | int inst_num = get_int(); |
2733 | // Left-instruction's operand |
2734 | skipws(); |
2735 | if( _curchar != '.' ) { |
2736 | parse_err(SYNERR1, "missing '.' in peepreplace after instruction number.\n"); |
2737 | return; |
2738 | } |
2739 | next_char(); // Skip '.' |
2740 | char *inst_op = get_ident_dup(); |
2741 | if( inst_op == NULL__null ) { |
2742 | parse_err(SYNERR1, "missing operand identifier in peepreplace.\n"); |
2743 | return; |
2744 | } |
2745 | |
2746 | // Record this operand's position in peepmatch |
2747 | replace->add_operand( inst_num, inst_op ); |
2748 | skipws(); |
2749 | } |
2750 | |
2751 | // Check for the end of operands list |
2752 | skipws(); |
2753 | assert( _curchar == ')', "While loop should have advanced to ')'."){ if (!(_curchar == ')')) { fprintf(stderr, "assert fails %s %d: %s\n" , "/home/daniel/Projects/java/jdk/src/hotspot/share/adlc/adlparse.cpp" , 2753, "While loop should have advanced to ')'."); abort(); } }; |
2754 | next_char(); // Skip ')' |
2755 | |
2756 | skipws(); |
2757 | // Check for end of peepreplace |
2758 | if( _curchar != ')' ) { |
2759 | parse_err(SYNERR1, "missing ')' at end of peepmatch.\n"); |
2760 | parse_err(SYNERR1, "Support one replacement instruction.\n"); |
2761 | return; |
2762 | } |
2763 | next_char(); // Skip ')' |
2764 | |
2765 | // Check for closing semicolon |
2766 | skipws(); |
2767 | if( _curchar != ';' ) { |
2768 | parse_err(SYNERR1, "missing ';' at end of peepreplace.\n"); |
2769 | return; |
2770 | } |
2771 | next_char(); // skip ';' |
2772 | |
2773 | // Store replace into peep |
2774 | peep.add_replace( replace ); |
2775 | } |
2776 | |
2777 | //------------------------------pred_parse------------------------------------- |
2778 | Predicate *ADLParser::pred_parse(void) { |
2779 | Predicate *predicate; // Predicate class for operand |
2780 | char *rule = NULL__null; // String representation of predicate |
2781 | |
2782 | skipws(); // Skip leading whitespace |
2783 | int line = linenum(); |
Value stored to 'line' during its initialization is never read | |
2784 | if ( (rule = get_paren_expr("pred expression", true)) == NULL__null ) { |
2785 | parse_err(SYNERR1, "incorrect or missing expression for 'predicate'\n"); |
2786 | return NULL__null; |
2787 | } |
2788 | // Debug Stuff |
2789 | if (_AD._adl_debug > 1) fprintf(stderrstderr,"Predicate: %s\n", rule); |
2790 | if (_curchar != ';') { |
2791 | parse_err(SYNERR1, "missing ';' in predicate definition\n"); |
2792 | return NULL__null; |
2793 | } |
2794 | next_char(); // Point after the terminator |
2795 | |
2796 | predicate = new Predicate(rule); // Build new predicate object |
2797 | skipws(); |
2798 | return predicate; |
2799 | } |
2800 | |
2801 | |
2802 | //------------------------------ins_encode_parse_block------------------------- |
2803 | // Parse the block form of ins_encode. See ins_encode_parse for more details |
2804 | void ADLParser::ins_encode_parse_block(InstructForm& inst) { |
2805 | // Create a new encoding name based on the name of the instruction |
2806 | // definition, which should be unique. |
2807 | const char* prefix = "__ins_encode_"; |
2808 | char* ec_name = (char*) AllocateHeap(strlen(inst._ident) + strlen(prefix) + 1); |
2809 | sprintf(ec_name, "%s%s", prefix, inst._ident); |
2810 | |
2811 | assert(_AD._encode->encClass(ec_name) == NULL, "shouldn't already exist"){ if (!(_AD._encode->encClass(ec_name) == __null)) { fprintf (stderr, "assert fails %s %d: %s\n", "/home/daniel/Projects/java/jdk/src/hotspot/share/adlc/adlparse.cpp" , 2811, "shouldn't already exist"); abort(); }}; |
2812 | EncClass* encoding = _AD._encode->add_EncClass(ec_name); |
2813 | encoding->_linenum = linenum(); |
2814 | |
2815 | // synthesize the arguments list for the enc_class from the |
2816 | // arguments to the instruct definition. |
2817 | const char* param = NULL__null; |
2818 | inst._parameters.reset(); |
2819 | while ((param = inst._parameters.iter()) != NULL__null) { |
2820 | OpClassForm* opForm = inst._localNames[param]->is_opclass(); |
2821 | assert(opForm != NULL, "sanity"){ if (!(opForm != __null)) { fprintf(stderr, "assert fails %s %d: %s\n" , "/home/daniel/Projects/java/jdk/src/hotspot/share/adlc/adlparse.cpp" , 2821, "sanity"); abort(); }}; |
2822 | encoding->add_parameter(opForm->_ident, param); |
2823 | } |
2824 | |
2825 | if (!inst._is_postalloc_expand) { |
2826 | // Define a MacroAssembler instance for use by the encoding. The |
2827 | // name is chosen to match the __ idiom used for assembly in other |
2828 | // parts of hotspot and assumes the existence of the standard |
2829 | // #define __ _masm. |
2830 | encoding->add_code(" C2_MacroAssembler _masm(&cbuf);\n"); |
2831 | } |
2832 | |
2833 | // Parse the following %{ }% block |
2834 | ins_encode_parse_block_impl(inst, encoding, ec_name); |
2835 | |
2836 | // Build an encoding rule which invokes the encoding rule we just |
2837 | // created, passing all arguments that we received. |
2838 | InsEncode* encrule = new InsEncode(); // Encode class for instruction |
2839 | NameAndList* params = encrule->add_encode(ec_name); |
2840 | inst._parameters.reset(); |
2841 | while ((param = inst._parameters.iter()) != NULL__null) { |
2842 | params->add_entry(param); |
2843 | } |
2844 | |
2845 | // Check for duplicate ins_encode sections after parsing the block |
2846 | // so that parsing can continue and find any other errors. |
2847 | if (inst._insencode != NULL__null) { |
2848 | parse_err(SYNERR1, "Multiple ins_encode sections defined\n"); |
2849 | return; |
2850 | } |
2851 | |
2852 | // Set encode class of this instruction. |
2853 | inst._insencode = encrule; |
2854 | } |
2855 | |
2856 | |
2857 | void ADLParser::ins_encode_parse_block_impl(InstructForm& inst, EncClass* encoding, char* ec_name) { |
2858 | skipws_no_preproc(); // Skip leading whitespace |
2859 | // Prepend location descriptor, for debugging; cf. ADLParser::find_cpp_block |
2860 | if (_AD._adlocation_debug) { |
2861 | encoding->add_code(get_line_string()); |
2862 | } |
2863 | |
2864 | // Collect the parts of the encode description |
2865 | // (1) strings that are passed through to output |
2866 | // (2) replacement/substitution variable, preceeded by a '$' |
2867 | while ((_curchar != '%') && (*(_ptr+1) != '}')) { |
2868 | |
2869 | // (1) |
2870 | // Check if there is a string to pass through to output |
2871 | char *start = _ptr; // Record start of the next string |
2872 | while ((_curchar != '$') && ((_curchar != '%') || (*(_ptr+1) != '}')) ) { |
2873 | // If at the start of a comment, skip past it |
2874 | if( (_curchar == '/') && ((*(_ptr+1) == '/') || (*(_ptr+1) == '*')) ) { |
2875 | skipws_no_preproc(); |
2876 | } else { |
2877 | // ELSE advance to the next character, or start of the next line |
2878 | next_char_or_line(); |
2879 | } |
2880 | } |
2881 | // If a string was found, terminate it and record in EncClass |
2882 | if (start != _ptr) { |
2883 | *_ptr = '\0'; // Terminate the string |
2884 | encoding->add_code(start); |
2885 | } |
2886 | |
2887 | // (2) |
2888 | // If we are at a replacement variable, |
2889 | // copy it and record in EncClass |
2890 | if (_curchar == '$') { |
2891 | // Found replacement Variable |
2892 | char* rep_var = get_rep_var_ident_dup(); |
2893 | |
2894 | // Add flag to _strings list indicating we should check _rep_vars |
2895 | encoding->add_rep_var(rep_var); |
2896 | |
2897 | skipws(); |
2898 | |
2899 | // Check if this instruct is a MachConstantNode. |
2900 | if (strcmp(rep_var, "constanttablebase") == 0) { |
2901 | // This instruct is a MachConstantNode. |
2902 | inst.set_needs_constant_base(true); |
2903 | if (strncmp("MachCall", inst.mach_base_class(_globalNames), strlen("MachCall")) != 0 ) { |
2904 | inst.set_is_mach_constant(true); |
2905 | } |
2906 | |
2907 | if (_curchar == '(') { |
2908 | parse_err(SYNERR1, "constanttablebase in instruct %s cannot have an argument " |
2909 | "(only constantaddress and constantoffset)", ec_name); |
2910 | return; |
2911 | } |
2912 | } |
2913 | else if ((strcmp(rep_var, "constantaddress") == 0) || |
2914 | (strcmp(rep_var, "constantoffset") == 0)) { |
2915 | // This instruct is a MachConstantNode. |
2916 | inst.set_is_mach_constant(true); |
2917 | |
2918 | // If the constant keyword has an argument, parse it. |
2919 | if (_curchar == '(') constant_parse(inst); |
2920 | } |
2921 | } |
2922 | } // end while part of format description |
2923 | next_char(); // Skip '%' |
2924 | next_char(); // Skip '}' |
2925 | |
2926 | skipws(); |
2927 | |
2928 | if (_AD._adlocation_debug) { |
2929 | encoding->add_code(end_line_marker()); |
2930 | } |
2931 | |
2932 | // Debug Stuff |
2933 | if (_AD._adl_debug > 1) fprintf(stderrstderr, "EncodingClass Form: %s\n", ec_name); |
2934 | } |
2935 | |
2936 | |
2937 | //------------------------------ins_encode_parse------------------------------- |
2938 | // Encode rules have the form |
2939 | // ins_encode( encode_class_name(parameter_list), ... ); |
2940 | // |
2941 | // The "encode_class_name" must be defined in the encode section |
2942 | // The parameter list contains $names that are locals. |
2943 | // |
2944 | // Alternatively it can be written like this: |
2945 | // |
2946 | // ins_encode %{ |
2947 | // ... // body |
2948 | // %} |
2949 | // |
2950 | // which synthesizes a new encoding class taking the same arguments as |
2951 | // the InstructForm, and automatically prefixes the definition with: |
2952 | // |
2953 | // C2_MacroAssembler masm(&cbuf);\n"); |
2954 | // |
2955 | // making it more compact to take advantage of the C2_MacroAssembler and |
2956 | // placing the assembly closer to it's use by instructions. |
2957 | void ADLParser::ins_encode_parse(InstructForm& inst) { |
2958 | |
2959 | // Parse encode class name |
2960 | skipws(); // Skip whitespace |
2961 | if (_curchar != '(') { |
2962 | // Check for ins_encode %{ form |
2963 | if ((_curchar == '%') && (*(_ptr+1) == '{')) { |
2964 | next_char(); // Skip '%' |
2965 | next_char(); // Skip '{' |
2966 | |
2967 | // Parse the block form of ins_encode |
2968 | ins_encode_parse_block(inst); |
2969 | return; |
2970 | } |
2971 | |
2972 | parse_err(SYNERR1, "missing '%%{' or '(' in ins_encode definition\n"); |
2973 | return; |
2974 | } |
2975 | next_char(); // move past '(' |
2976 | skipws(); |
2977 | |
2978 | InsEncode *encrule = new InsEncode(); // Encode class for instruction |
2979 | encrule->_linenum = linenum(); |
2980 | char *ec_name = NULL__null; // String representation of encode rule |
2981 | // identifier is optional. |
2982 | while (_curchar != ')') { |
2983 | ec_name = get_ident(); |
2984 | if (ec_name == NULL__null) { |
2985 | parse_err(SYNERR1, "Invalid encode class name after 'ins_encode('.\n"); |
2986 | return; |
2987 | } |
2988 | // Check that encoding is defined in the encode section |
2989 | EncClass *encode_class = _AD._encode->encClass(ec_name); |
2990 | if (encode_class == NULL__null) { |
2991 | // Like to defer checking these till later... |
2992 | // parse_err(WARN, "Using an undefined encode class '%s' in 'ins_encode'.\n", ec_name); |
2993 | } |
2994 | |
2995 | // Get list for encode method's parameters |
2996 | NameAndList *params = encrule->add_encode(ec_name); |
2997 | |
2998 | // Parse the parameters to this encode method. |
2999 | skipws(); |
3000 | if ( _curchar == '(' ) { |
3001 | next_char(); // move past '(' for parameters |
3002 | |
3003 | // Parse the encode method's parameters |
3004 | while (_curchar != ')') { |
3005 | char *param = get_ident_or_literal_constant("encoding operand"); |
3006 | if ( param != NULL__null ) { |
3007 | |
3008 | // Check if this instruct is a MachConstantNode. |
3009 | if (strcmp(param, "constanttablebase") == 0) { |
3010 | // This instruct is a MachConstantNode. |
3011 | inst.set_needs_constant_base(true); |
3012 | if (strncmp("MachCall", inst.mach_base_class(_globalNames), strlen("MachCall")) != 0 ) { |
3013 | inst.set_is_mach_constant(true); |
3014 | } |
3015 | |
3016 | if (_curchar == '(') { |
3017 | parse_err(SYNERR1, "constanttablebase in instruct %s cannot have an argument " |
3018 | "(only constantaddress and constantoffset)", ec_name); |
3019 | return; |
3020 | } |
3021 | } else { |
3022 | // Found a parameter: |
3023 | // Check it is a local name, add it to the list, then check for more |
3024 | // New: allow hex constants as parameters to an encode method. |
3025 | // New: allow parenthesized expressions as parameters. |
3026 | // New: allow "primary", "secondary", "tertiary" as parameters. |
3027 | // New: allow user-defined register name as parameter |
3028 | if ( (inst._localNames[param] == NULL__null) && |
3029 | !ADLParser::is_literal_constant(param) && |
3030 | (Opcode::as_opcode_type(param) == Opcode::NOT_AN_OPCODE) && |
3031 | ((_AD._register == NULL__null ) || (_AD._register->getRegDef(param) == NULL__null)) ) { |
3032 | parse_err(SYNERR1, "Using non-locally defined parameter %s for encoding %s.\n", param, ec_name); |
3033 | return; |
3034 | } |
3035 | } |
3036 | params->add_entry(param); |
3037 | |
3038 | skipws(); |
3039 | if (_curchar == ',' ) { |
3040 | // More parameters to come |
3041 | next_char(); // move past ',' between parameters |
3042 | skipws(); // Skip to next parameter |
3043 | } |
3044 | else if (_curchar == ')') { |
3045 | // Done with parameter list |
3046 | } |
3047 | else { |
3048 | // Only ',' or ')' are valid after a parameter name |
3049 | parse_err(SYNERR1, "expected ',' or ')' after parameter %s.\n", |
3050 | ec_name); |
3051 | return; |
3052 | } |
3053 | |
3054 | } else { |
3055 | skipws(); |
3056 | // Did not find a parameter |
3057 | if (_curchar == ',') { |
3058 | parse_err(SYNERR1, "Expected encode parameter before ',' in encoding %s.\n", ec_name); |
3059 | return; |
3060 | } |
3061 | if (_curchar != ')') { |
3062 | parse_err(SYNERR1, "Expected ')' after encode parameters.\n"); |
3063 | return; |
3064 | } |
3065 | } |
3066 | } // WHILE loop collecting parameters |
3067 | next_char(); // move past ')' at end of parameters |
3068 | } // done with parameter list for encoding |
3069 | |
3070 | // Check for ',' or ')' after encoding |
3071 | skipws(); // move to character after parameters |
3072 | if ( _curchar == ',' ) { |
3073 | // Found a ',' |
3074 | next_char(); // move past ',' between encode methods |
3075 | skipws(); |
3076 | } |
3077 | else if ( _curchar != ')' ) { |
3078 | // If not a ',' then only a ')' is allowed |
3079 | parse_err(SYNERR1, "Expected ')' after encoding %s.\n", ec_name); |
3080 | return; |
3081 | } |
3082 | |
3083 | // Check for ',' separating parameters |
3084 | // if ( _curchar != ',' && _curchar != ')' ) { |
3085 | // parse_err(SYNERR, "expected ',' or ')' after encode method inside ins_encode.\n"); |
3086 | // return NULL; |
3087 | // } |
3088 | |
3089 | } // done parsing ins_encode methods and their parameters |
3090 | if (_curchar != ')') { |
3091 | parse_err(SYNERR1, "Missing ')' at end of ins_encode description.\n"); |
3092 | return; |
3093 | } |
3094 | next_char(); // move past ')' |
3095 | skipws(); // Skip leading whitespace |
3096 | |
3097 | if ( _curchar != ';' ) { |
3098 | parse_err(SYNERR1, "Missing ';' at end of ins_encode.\n"); |
3099 | return; |
3100 | } |
3101 | next_char(); // move past ';' |
3102 | skipws(); // be friendly to oper_parse() |
3103 | |
3104 | // Check for duplicate ins_encode sections after parsing the block |
3105 | // so that parsing can continue and find any other errors. |
3106 | if (inst._insencode != NULL__null) { |
3107 | parse_err(SYNERR1, "Multiple ins_encode sections defined\n"); |
3108 | return; |
3109 | } |
3110 | |
3111 | // Debug Stuff |
3112 | if (_AD._adl_debug > 1) fprintf(stderrstderr,"Instruction Encode: %s\n", ec_name); |
3113 | |
3114 | // Set encode class of this instruction. |
3115 | inst._insencode = encrule; |
3116 | } |
3117 | |
3118 | //------------------------------postalloc_expand_parse--------------------------- |
3119 | // Encode rules have the form |
3120 | // postalloc_expand( encode_class_name(parameter_list) ); |
3121 | // |
3122 | // The "encode_class_name" must be defined in the encode section. |
3123 | // The parameter list contains $names that are locals. |
3124 | // |
3125 | // This is just a copy of ins_encode_parse without the loop. |
3126 | void ADLParser::postalloc_expand_parse(InstructForm& inst) { |
3127 | inst._is_postalloc_expand = true; |
3128 | |
3129 | // Parse encode class name. |
3130 | skipws(); // Skip whitespace. |
3131 | if (_curchar != '(') { |
3132 | // Check for postalloc_expand %{ form |
3133 | if ((_curchar == '%') && (*(_ptr+1) == '{')) { |
3134 | next_char(); // Skip '%' |
3135 | next_char(); // Skip '{' |
3136 | |
3137 | // Parse the block form of postalloc_expand |
3138 | ins_encode_parse_block(inst); |
3139 | return; |
3140 | } |
3141 | |
3142 | parse_err(SYNERR1, "missing '(' in postalloc_expand definition\n"); |
3143 | return; |
3144 | } |
3145 | next_char(); // Move past '('. |
3146 | skipws(); |
3147 | |
3148 | InsEncode *encrule = new InsEncode(); // Encode class for instruction. |
3149 | encrule->_linenum = linenum(); |
3150 | char *ec_name = NULL__null; // String representation of encode rule. |
3151 | // identifier is optional. |
3152 | if (_curchar != ')') { |
3153 | ec_name = get_ident(); |
3154 | if (ec_name == NULL__null) { |
3155 | parse_err(SYNERR1, "Invalid postalloc_expand class name after 'postalloc_expand('.\n"); |
3156 | return; |
3157 | } |
3158 | // Check that encoding is defined in the encode section. |
3159 | EncClass *encode_class = _AD._encode->encClass(ec_name); |
3160 | |
3161 | // Get list for encode method's parameters |
3162 | NameAndList *params = encrule->add_encode(ec_name); |
3163 | |
3164 | // Parse the parameters to this encode method. |
3165 | skipws(); |
3166 | if (_curchar == '(') { |
3167 | next_char(); // Move past '(' for parameters. |
3168 | |
3169 | // Parse the encode method's parameters. |
3170 | while (_curchar != ')') { |
3171 | char *param = get_ident_or_literal_constant("encoding operand"); |
3172 | if (param != NULL__null) { |
3173 | // Found a parameter: |
3174 | |
3175 | // First check for constant table support. |
3176 | |
3177 | // Check if this instruct is a MachConstantNode. |
3178 | if (strcmp(param, "constanttablebase") == 0) { |
3179 | // This instruct is a MachConstantNode. |
3180 | inst.set_needs_constant_base(true); |
3181 | if (strncmp("MachCall", inst.mach_base_class(_globalNames), strlen("MachCall")) != 0 ) { |
3182 | inst.set_is_mach_constant(true); |
3183 | } |
3184 | |
3185 | if (_curchar == '(') { |
3186 | parse_err(SYNERR1, "constanttablebase in instruct %s cannot have an argument " |
3187 | "(only constantaddress and constantoffset)", ec_name); |
3188 | return; |
3189 | } |
3190 | } |
3191 | else if ((strcmp(param, "constantaddress") == 0) || |
3192 | (strcmp(param, "constantoffset") == 0)) { |
3193 | // This instruct is a MachConstantNode. |
3194 | inst.set_is_mach_constant(true); |
3195 | |
3196 | // If the constant keyword has an argument, parse it. |
3197 | if (_curchar == '(') constant_parse(inst); |
3198 | } |
3199 | |
3200 | // Else check it is a local name, add it to the list, then check for more. |
3201 | // New: allow hex constants as parameters to an encode method. |
3202 | // New: allow parenthesized expressions as parameters. |
3203 | // New: allow "primary", "secondary", "tertiary" as parameters. |
3204 | // New: allow user-defined register name as parameter. |
3205 | else if ((inst._localNames[param] == NULL__null) && |
3206 | !ADLParser::is_literal_constant(param) && |
3207 | (Opcode::as_opcode_type(param) == Opcode::NOT_AN_OPCODE) && |
3208 | ((_AD._register == NULL__null) || (_AD._register->getRegDef(param) == NULL__null))) { |
3209 | parse_err(SYNERR1, "Using non-locally defined parameter %s for encoding %s.\n", param, ec_name); |
3210 | return; |
3211 | } |
3212 | params->add_entry(param); |
3213 | |
3214 | skipws(); |
3215 | if (_curchar == ',') { |
3216 | // More parameters to come. |
3217 | next_char(); // Move past ',' between parameters. |
3218 | skipws(); // Skip to next parameter. |
3219 | } else if (_curchar == ')') { |
3220 | // Done with parameter list |
3221 | } else { |
3222 | // Only ',' or ')' are valid after a parameter name. |
3223 | parse_err(SYNERR1, "expected ',' or ')' after parameter %s.\n", ec_name); |
3224 | return; |
3225 | } |
3226 | |
3227 | } else { |
3228 | skipws(); |
3229 | // Did not find a parameter. |
3230 | if (_curchar == ',') { |
3231 | parse_err(SYNERR1, "Expected encode parameter before ',' in postalloc_expand %s.\n", ec_name); |
3232 | return; |
3233 | } |
3234 | if (_curchar != ')') { |
3235 | parse_err(SYNERR1, "Expected ')' after postalloc_expand parameters.\n"); |
3236 | return; |
3237 | } |
3238 | } |
3239 | } // WHILE loop collecting parameters. |
3240 | next_char(); // Move past ')' at end of parameters. |
3241 | } // Done with parameter list for encoding. |
3242 | |
3243 | // Check for ',' or ')' after encoding. |
3244 | skipws(); // Move to character after parameters. |
3245 | if (_curchar != ')') { |
3246 | // Only a ')' is allowed. |
3247 | parse_err(SYNERR1, "Expected ')' after postalloc_expand %s.\n", ec_name); |
3248 | return; |
3249 | } |
3250 | } // Done parsing postalloc_expand method and their parameters. |
3251 | if (_curchar != ')') { |
3252 | parse_err(SYNERR1, "Missing ')' at end of postalloc_expand description.\n"); |
3253 | return; |
3254 | } |
3255 | next_char(); // Move past ')'. |
3256 | skipws(); // Skip leading whitespace. |
3257 | |
3258 | if (_curchar != ';') { |
3259 | parse_err(SYNERR1, "Missing ';' at end of postalloc_expand.\n"); |
3260 | return; |
3261 | } |
3262 | next_char(); // Move past ';'. |
3263 | skipws(); // Be friendly to oper_parse(). |
3264 | |
3265 | // Debug Stuff. |
3266 | if (_AD._adl_debug > 1) fprintf(stderrstderr, "Instruction postalloc_expand: %s\n", ec_name); |
3267 | |
3268 | // Set encode class of this instruction. |
3269 | inst._insencode = encrule; |
3270 | } |
3271 | |
3272 | |
3273 | //------------------------------constant_parse--------------------------------- |
3274 | // Parse a constant expression. |
3275 | void ADLParser::constant_parse(InstructForm& inst) { |
3276 | // Create a new encoding name based on the name of the instruction |
3277 | // definition, which should be unique. |
3278 | const char* prefix = "__constant_"; |
3279 | char* ec_name = (char*) AllocateHeap(strlen(inst._ident) + strlen(prefix) + 1); |
3280 | sprintf(ec_name, "%s%s", prefix, inst._ident); |
3281 | |
3282 | assert(_AD._encode->encClass(ec_name) == NULL, "shouldn't already exist"){ if (!(_AD._encode->encClass(ec_name) == __null)) { fprintf (stderr, "assert fails %s %d: %s\n", "/home/daniel/Projects/java/jdk/src/hotspot/share/adlc/adlparse.cpp" , 3282, "shouldn't already exist"); abort(); }}; |
3283 | EncClass* encoding = _AD._encode->add_EncClass(ec_name); |
3284 | encoding->_linenum = linenum(); |
3285 | |
3286 | // synthesize the arguments list for the enc_class from the |
3287 | // arguments to the instruct definition. |
3288 | const char* param = NULL__null; |
3289 | inst._parameters.reset(); |
3290 | while ((param = inst._parameters.iter()) != NULL__null) { |
3291 | OpClassForm* opForm = inst._localNames[param]->is_opclass(); |
3292 | assert(opForm != NULL, "sanity"){ if (!(opForm != __null)) { fprintf(stderr, "assert fails %s %d: %s\n" , "/home/daniel/Projects/java/jdk/src/hotspot/share/adlc/adlparse.cpp" , 3292, "sanity"); abort(); }}; |
3293 | encoding->add_parameter(opForm->_ident, param); |
3294 | } |
3295 | |
3296 | // Parse the following ( ) expression. |
3297 | constant_parse_expression(encoding, ec_name); |
3298 | |
3299 | // Build an encoding rule which invokes the encoding rule we just |
3300 | // created, passing all arguments that we received. |
3301 | InsEncode* encrule = new InsEncode(); // Encode class for instruction |
3302 | NameAndList* params = encrule->add_encode(ec_name); |
3303 | inst._parameters.reset(); |
3304 | while ((param = inst._parameters.iter()) != NULL__null) { |
3305 | params->add_entry(param); |
3306 | } |
3307 | |
3308 | // Set encode class of this instruction. |
3309 | inst._constant = encrule; |
3310 | } |
3311 | |
3312 | |
3313 | //------------------------------constant_parse_expression---------------------- |
3314 | void ADLParser::constant_parse_expression(EncClass* encoding, char* ec_name) { |
3315 | skipws(); |
3316 | |
3317 | // Prepend location descriptor, for debugging; cf. ADLParser::find_cpp_block |
3318 | if (_AD._adlocation_debug) { |
3319 | encoding->add_code(get_line_string()); |
3320 | } |
3321 | |
3322 | // Start code line. |
3323 | encoding->add_code(" _constant = C->output()->constant_table().add"); |
3324 | |
3325 | // Parse everything in ( ) expression. |
3326 | encoding->add_code("(this, "); |
3327 | next_char(); // Skip '(' |
3328 | int parens_depth = 1; |
3329 | |
3330 | // Collect the parts of the constant expression. |
3331 | // (1) strings that are passed through to output |
3332 | // (2) replacement/substitution variable, preceeded by a '$' |
3333 | while (parens_depth > 0) { |
3334 | if (_curchar == '(') { |
3335 | parens_depth++; |
3336 | encoding->add_code("("); |
3337 | next_char(); |
3338 | } |
3339 | else if (_curchar == ')') { |
3340 | parens_depth--; |
3341 | if (parens_depth > 0) |
3342 | encoding->add_code(")"); |
3343 | next_char(); |
3344 | } |
3345 | else { |
3346 | // (1) |
3347 | // Check if there is a string to pass through to output |
3348 | char *start = _ptr; // Record start of the next string |
3349 | while ((_curchar != '$') && (_curchar != '(') && (_curchar != ')')) { |
3350 | next_char(); |
3351 | } |
3352 | // If a string was found, terminate it and record in EncClass |
3353 | if (start != _ptr) { |
3354 | *_ptr = '\0'; // Terminate the string |
3355 | encoding->add_code(start); |
3356 | } |
3357 | |
3358 | // (2) |
3359 | // If we are at a replacement variable, copy it and record in EncClass. |
3360 | if (_curchar == '$') { |
3361 | // Found replacement Variable |
3362 | char* rep_var = get_rep_var_ident_dup(); |
3363 | encoding->add_rep_var(rep_var); |
3364 | } |
3365 | } |
3366 | } |
3367 | |
3368 | // Finish code line. |
3369 | encoding->add_code(");"); |
3370 | |
3371 | if (_AD._adlocation_debug) { |
3372 | encoding->add_code(end_line_marker()); |
3373 | } |
3374 | |
3375 | // Debug Stuff |
3376 | if (_AD._adl_debug > 1) fprintf(stderrstderr, "EncodingClass Form: %s\n", ec_name); |
3377 | } |
3378 | |
3379 | |
3380 | //------------------------------size_parse----------------------------------- |
3381 | // Parse a 'size(<expr>)' attribute which specifies the size of the |
3382 | // emitted instructions in bytes. <expr> can be a C++ expression, |
3383 | // e.g. a constant. |
3384 | char* ADLParser::size_parse(InstructForm *instr) { |
3385 | char* sizeOfInstr = NULL__null; |
3386 | |
3387 | // Get value of the instruction's size |
3388 | skipws(); |
3389 | |
3390 | // Parse size |
3391 | sizeOfInstr = get_paren_expr("size expression"); |
3392 | if (sizeOfInstr == NULL__null) { |
3393 | parse_err(SYNERR1, "size of opcode expected at %c\n", _curchar); |
3394 | return NULL__null; |
3395 | } |
3396 | |
3397 | skipws(); |
3398 | |
3399 | // Check for terminator |
3400 | if (_curchar != ';') { |
3401 | parse_err(SYNERR1, "missing ';' in ins_attrib definition\n"); |
3402 | return NULL__null; |
3403 | } |
3404 | next_char(); // Advance past the ';' |
3405 | skipws(); // necessary for instr_parse() |
3406 | |
3407 | // Debug Stuff |
3408 | if (_AD._adl_debug > 1) { |
3409 | if (sizeOfInstr != NULL__null) { |
3410 | fprintf(stderrstderr,"size of opcode: %s\n", sizeOfInstr); |
3411 | } |
3412 | } |
3413 | |
3414 | return sizeOfInstr; |
3415 | } |
3416 | |
3417 | |
3418 | //------------------------------opcode_parse----------------------------------- |
3419 | Opcode * ADLParser::opcode_parse(InstructForm *instr) { |
3420 | char *primary = NULL__null; |
3421 | char *secondary = NULL__null; |
3422 | char *tertiary = NULL__null; |
3423 | |
3424 | char *val = NULL__null; |
3425 | Opcode *opcode = NULL__null; |
3426 | |
3427 | // Get value of the instruction's opcode |
3428 | skipws(); |
3429 | if (_curchar != '(') { // Check for parenthesized operand list |
3430 | parse_err(SYNERR1, "missing '(' in expand instruction declaration\n"); |
3431 | return NULL__null; |
3432 | } |
3433 | next_char(); // skip open paren |
3434 | skipws(); |
3435 | if (_curchar != ')') { |
3436 | // Parse primary, secondary, and tertiary opcodes, if provided. |
3437 | if ( (primary = get_ident_or_literal_constant("primary opcode")) == NULL__null ) { |
3438 | parse_err(SYNERR1, "primary hex opcode expected at %c\n", _curchar); |
3439 | return NULL__null; |
3440 | } |
3441 | skipws(); |
3442 | if (_curchar == ',') { |
3443 | next_char(); |
3444 | skipws(); |
3445 | // Parse secondary opcode |
3446 | if ( (secondary = get_ident_or_literal_constant("secondary opcode")) == NULL__null ) { |
3447 | parse_err(SYNERR1, "secondary hex opcode expected at %c\n", _curchar); |
3448 | return NULL__null; |
3449 | } |
3450 | skipws(); |
3451 | if (_curchar == ',') { |
3452 | next_char(); |
3453 | skipws(); |
3454 | // Parse tertiary opcode |
3455 | if ( (tertiary = get_ident_or_literal_constant("tertiary opcode")) == NULL__null ) { |
3456 | parse_err(SYNERR1,"tertiary hex opcode expected at %c\n", _curchar); |
3457 | return NULL__null; |
3458 | } |
3459 | skipws(); |
3460 | } |
3461 | } |
3462 | skipws(); |
3463 | if (_curchar != ')') { |
3464 | parse_err(SYNERR1, "Missing ')' in opcode description\n"); |
3465 | return NULL__null; |
3466 | } |
3467 | } |
3468 | next_char(); // Skip ')' |
3469 | skipws(); |
3470 | // Check for terminator |
3471 | if (_curchar != ';') { |
3472 | parse_err(SYNERR1, "missing ';' in ins_attrib definition\n"); |
3473 | return NULL__null; |
3474 | } |
3475 | next_char(); // Advance past the ';' |
3476 | skipws(); // necessary for instr_parse() |
3477 | |
3478 | // Debug Stuff |
3479 | if (_AD._adl_debug > 1) { |
3480 | if (primary != NULL__null) fprintf(stderrstderr,"primary opcode: %s\n", primary); |
3481 | if (secondary != NULL__null) fprintf(stderrstderr,"secondary opcode: %s\n", secondary); |
3482 | if (tertiary != NULL__null) fprintf(stderrstderr,"tertiary opcode: %s\n", tertiary); |
3483 | } |
3484 | |
3485 | // Generate new object and return |
3486 | opcode = new Opcode(primary, secondary, tertiary); |
3487 | return opcode; |
3488 | } |
3489 | |
3490 | |
3491 | //------------------------------interface_parse-------------------------------- |
3492 | Interface *ADLParser::interface_parse(void) { |
3493 | char *iface_name = NULL__null; // Name of interface class being used |
3494 | char *iface_code = NULL__null; // Describe components of this class |
3495 | |
3496 | // Get interface class name |
3497 | skipws(); // Skip whitespace |
3498 | if (_curchar != '(') { |
3499 | parse_err(SYNERR1, "Missing '(' at start of interface description.\n"); |
3500 | return NULL__null; |
3501 | } |
3502 | next_char(); // move past '(' |
3503 | skipws(); |
3504 | iface_name = get_ident(); |
3505 | if (iface_name == NULL__null) { |
3506 | parse_err(SYNERR1, "missing interface name after 'interface'.\n"); |
3507 | return NULL__null; |
3508 | } |
3509 | skipws(); |
3510 | if (_curchar != ')') { |
3511 | parse_err(SYNERR1, "Missing ')' after name of interface.\n"); |
3512 | return NULL__null; |
3513 | } |
3514 | next_char(); // move past ')' |
3515 | |
3516 | // Get details of the interface, |
3517 | // for the type of interface indicated by iface_name. |
3518 | Interface *inter = NULL__null; |
3519 | skipws(); |
3520 | if ( _curchar != ';' ) { |
3521 | if ( strcmp(iface_name,"MEMORY_INTER") == 0 ) { |
3522 | inter = mem_interface_parse(); |
3523 | } |
3524 | else if ( strcmp(iface_name,"COND_INTER") == 0 ) { |
3525 | inter = cond_interface_parse(); |
3526 | } |
3527 | // The parse routines consume the "%}" |
3528 | |
3529 | // Check for probable extra ';' after defining block. |
3530 | if ( _curchar == ';' ) { |
3531 | parse_err(SYNERR1, "Extra ';' after defining interface block.\n"); |
3532 | next_char(); // Skip ';' |
3533 | return NULL__null; |
3534 | } |
3535 | } else { |
3536 | next_char(); // move past ';' |
3537 | |
3538 | // Create appropriate interface object |
3539 | if ( strcmp(iface_name,"REG_INTER") == 0 ) { |
3540 | inter = new RegInterface(); |
3541 | } |
3542 | else if ( strcmp(iface_name,"CONST_INTER") == 0 ) { |
3543 | inter = new ConstInterface(); |
3544 | } |
3545 | } |
3546 | skipws(); // be friendly to oper_parse() |
3547 | // Debug Stuff |
3548 | if (_AD._adl_debug > 1) fprintf(stderrstderr,"Interface Form: %s\n", iface_name); |
3549 | |
3550 | // Create appropriate interface object and return. |
3551 | return inter; |
3552 | } |
3553 | |
3554 | |
3555 | //------------------------------mem_interface_parse---------------------------- |
3556 | Interface *ADLParser::mem_interface_parse(void) { |
3557 | // Fields for MemInterface |
3558 | char *base = NULL__null; |
3559 | char *index = NULL__null; |
3560 | char *scale = NULL__null; |
3561 | char *disp = NULL__null; |
3562 | |
3563 | if (_curchar != '%') { |
3564 | parse_err(SYNERR1, "Missing '%%{' for 'interface' block.\n"); |
3565 | return NULL__null; |
3566 | } |
3567 | next_char(); // Skip '%' |
3568 | if (_curchar != '{') { |
3569 | parse_err(SYNERR1, "Missing '%%{' for 'interface' block.\n"); |
3570 | return NULL__null; |
3571 | } |
3572 | next_char(); // Skip '{' |
3573 | skipws(); |
3574 | do { |
3575 | char *field = get_ident(); |
3576 | if (field == NULL__null) { |
3577 | parse_err(SYNERR1, "Expected keyword, base|index|scale|disp, or '%%}' ending interface.\n"); |
3578 | return NULL__null; |
3579 | } |
3580 | if ( strcmp(field,"base") == 0 ) { |
3581 | base = interface_field_parse(); |
3582 | } |
3583 | else if ( strcmp(field,"index") == 0 ) { |
3584 | index = interface_field_parse(); |
3585 | } |
3586 | else if ( strcmp(field,"scale") == 0 ) { |
3587 | scale = interface_field_parse(); |
3588 | } |
3589 | else if ( strcmp(field,"disp") == 0 ) { |
3590 | disp = interface_field_parse(); |
3591 | } |
3592 | else { |
3593 | parse_err(SYNERR1, "Expected keyword, base|index|scale|disp, or '%%}' ending interface.\n"); |
3594 | return NULL__null; |
3595 | } |
3596 | } while( _curchar != '%' ); |
3597 | next_char(); // Skip '%' |
3598 | if ( _curchar != '}' ) { |
3599 | parse_err(SYNERR1, "Missing '%%}' for 'interface' block.\n"); |
3600 | return NULL__null; |
3601 | } |
3602 | next_char(); // Skip '}' |
3603 | |
3604 | // Construct desired object and return |
3605 | Interface *inter = new MemInterface(base, index, scale, disp); |
3606 | return inter; |
3607 | } |
3608 | |
3609 | |
3610 | //------------------------------cond_interface_parse--------------------------- |
3611 | Interface *ADLParser::cond_interface_parse(void) { |
3612 | char *equal; |
3613 | char *not_equal; |
3614 | char *less; |
3615 | char *greater_equal; |
3616 | char *less_equal; |
3617 | char *greater; |
3618 | char *overflow; |
3619 | char *no_overflow; |
3620 | const char *equal_format = "eq"; |
3621 | const char *not_equal_format = "ne"; |
3622 | const char *less_format = "lt"; |
3623 | const char *greater_equal_format = "ge"; |
3624 | const char *less_equal_format = "le"; |
3625 | const char *greater_format = "gt"; |
3626 | const char *overflow_format = "o"; |
3627 | const char *no_overflow_format = "no"; |
3628 | |
3629 | if (_curchar != '%') { |
3630 | parse_err(SYNERR1, "Missing '%%{' for 'cond_interface' block.\n"); |
3631 | return NULL__null; |
3632 | } |
3633 | next_char(); // Skip '%' |
3634 | if (_curchar != '{') { |
3635 | parse_err(SYNERR1, "Missing '%%{' for 'cond_interface' block.\n"); |
3636 | return NULL__null; |
3637 | } |
3638 | next_char(); // Skip '{' |
3639 | skipws(); |
3640 | do { |
3641 | char *field = get_ident(); |
3642 | if (field == NULL__null) { |
3643 | parse_err(SYNERR1, "Expected keyword, base|index|scale|disp, or '%%}' ending interface.\n"); |
3644 | return NULL__null; |
3645 | } |
3646 | if ( strcmp(field,"equal") == 0 ) { |
3647 | equal = interface_field_parse(&equal_format); |
3648 | } |
3649 | else if ( strcmp(field,"not_equal") == 0 ) { |
3650 | not_equal = interface_field_parse(¬_equal_format); |
3651 | } |
3652 | else if ( strcmp(field,"less") == 0 ) { |
3653 | less = interface_field_parse(&less_format); |
3654 | } |
3655 | else if ( strcmp(field,"greater_equal") == 0 ) { |
3656 | greater_equal = interface_field_parse(&greater_equal_format); |
3657 | } |
3658 | else if ( strcmp(field,"less_equal") == 0 ) { |
3659 | less_equal = interface_field_parse(&less_equal_format); |
3660 | } |
3661 | else if ( strcmp(field,"greater") == 0 ) { |
3662 | greater = interface_field_parse(&greater_format); |
3663 | } |
3664 | else if ( strcmp(field,"overflow") == 0 ) { |
3665 | overflow = interface_field_parse(&overflow_format); |
3666 | } |
3667 | else if ( strcmp(field,"no_overflow") == 0 ) { |
3668 | no_overflow = interface_field_parse(&no_overflow_format); |
3669 | } |
3670 | else { |
3671 | parse_err(SYNERR1, "Expected keyword, base|index|scale|disp, or '%%}' ending interface.\n"); |
3672 | return NULL__null; |
3673 | } |
3674 | } while( _curchar != '%' ); |
3675 | next_char(); // Skip '%' |
3676 | if ( _curchar != '}' ) { |
3677 | parse_err(SYNERR1, "Missing '%%}' for 'interface' block.\n"); |
3678 | return NULL__null; |
3679 | } |
3680 | next_char(); // Skip '}' |
3681 | |
3682 | // Construct desired object and return |
3683 | Interface *inter = new CondInterface(equal, equal_format, |
3684 | not_equal, not_equal_format, |
3685 | less, less_format, |
3686 | greater_equal, greater_equal_format, |
3687 | less_equal, less_equal_format, |
3688 | greater, greater_format, |
3689 | overflow, overflow_format, |
3690 | no_overflow, no_overflow_format); |
3691 | return inter; |
3692 | } |
3693 | |
3694 | |
3695 | //------------------------------interface_field_parse-------------------------- |
3696 | char *ADLParser::interface_field_parse(const char ** format) { |
3697 | char *iface_field = NULL__null; |
3698 | |
3699 | // Get interface field |
3700 | skipws(); // Skip whitespace |
3701 | if (_curchar != '(') { |
3702 | parse_err(SYNERR1, "Missing '(' at start of interface field.\n"); |
3703 | return NULL__null; |
3704 | } |
3705 | next_char(); // move past '(' |
3706 | skipws(); |
3707 | if ( _curchar != '0' && _curchar != '$' ) { |
3708 | parse_err(SYNERR1, "missing or invalid interface field contents.\n"); |
3709 | return NULL__null; |
3710 | } |
3711 | iface_field = get_rep_var_ident(); |
3712 | if (iface_field == NULL__null) { |
3713 | parse_err(SYNERR1, "missing or invalid interface field contents.\n"); |
3714 | return NULL__null; |
3715 | } |
3716 | skipws(); |
3717 | if (format != NULL__null && _curchar == ',') { |
3718 | next_char(); |
3719 | skipws(); |
3720 | if (_curchar != '"') { |
3721 | parse_err(SYNERR1, "Missing '\"' in field format .\n"); |
3722 | return NULL__null; |
3723 | } |
3724 | next_char(); |
3725 | char *start = _ptr; // Record start of the next string |
3726 | while ((_curchar != '"') && (_curchar != '%') && (_curchar != '\n')) { |
3727 | if (_curchar == '\\') next_char(); // superquote |
3728 | if (_curchar == '\n') parse_err(SYNERR1, "newline in string"); // unimplemented! |
3729 | next_char(); |
3730 | } |
3731 | if (_curchar != '"') { |
3732 | parse_err(SYNERR1, "Missing '\"' at end of field format .\n"); |
3733 | return NULL__null; |
3734 | } |
3735 | // If a string was found, terminate it and record in FormatRule |
3736 | if ( start != _ptr ) { |
3737 | *_ptr = '\0'; // Terminate the string |
3738 | *format = start; |
3739 | } |
3740 | next_char(); |
3741 | skipws(); |
3742 | } |
3743 | if (_curchar != ')') { |
3744 | parse_err(SYNERR1, "Missing ')' after interface field.\n"); |
3745 | return NULL__null; |
3746 | } |
3747 | next_char(); // move past ')' |
3748 | skipws(); |
3749 | if ( _curchar != ';' ) { |
3750 | parse_err(SYNERR1, "Missing ';' at end of interface field.\n"); |
3751 | return NULL__null; |
3752 | } |
3753 | next_char(); // move past ';' |
3754 | skipws(); // be friendly to interface_parse() |
3755 | |
3756 | return iface_field; |
3757 | } |
3758 | |
3759 | |
3760 | //------------------------------match_parse------------------------------------ |
3761 | MatchRule *ADLParser::match_parse(FormDict &operands) { |
3762 | MatchRule *match; // Match Rule class for instruction/operand |
3763 | char *cnstr = NULL__null; // Code for constructor |
3764 | int depth = 0; // Counter for matching parentheses |
3765 | int numleaves = 0; // Counter for number of leaves in rule |
3766 | |
3767 | // Parse the match rule tree |
3768 | MatchNode *mnode = matchNode_parse(operands, depth, numleaves, true); |
3769 | |
3770 | // Either there is a block with a constructor, or a ';' here |
3771 | skipws(); // Skip whitespace |
3772 | if ( _curchar == ';' ) { // Semicolon is valid terminator |
3773 | cnstr = NULL__null; // no constructor for this form |
3774 | next_char(); // Move past the ';', replaced with '\0' |
3775 | } |
3776 | else if ((cnstr = find_cpp_block("match constructor")) == NULL__null ) { |
3777 | parse_err(SYNERR1, "invalid construction of match rule\n" |
3778 | "Missing ';' or invalid '%%{' and '%%}' constructor\n"); |
3779 | return NULL__null; // No MatchRule to return |
3780 | } |
3781 | if (_AD._adl_debug > 1) |
3782 | if (cnstr) fprintf(stderrstderr,"Match Constructor: %s\n", cnstr); |
3783 | // Build new MatchRule object |
3784 | match = new MatchRule(_AD, mnode, depth, cnstr, numleaves); |
3785 | skipws(); // Skip any trailing whitespace |
3786 | return match; // Return MatchRule object |
3787 | } |
3788 | |
3789 | //------------------------------format_parse----------------------------------- |
3790 | FormatRule* ADLParser::format_parse(void) { |
3791 | char *desc = NULL__null; |
3792 | FormatRule *format = (new FormatRule(desc)); |
3793 | |
3794 | // Without expression form, MUST have a code block; |
3795 | skipws(); // Skip whitespace |
3796 | if ( _curchar == ';' ) { // Semicolon is valid terminator |
3797 | desc = NULL__null; // no constructor for this form |
3798 | next_char(); // Move past the ';', replaced with '\0' |
3799 | } |
3800 | else if ( _curchar == '%' && *(_ptr+1) == '{') { |
3801 | next_char(); // Move past the '%' |
3802 | next_char(); // Move past the '{' |
3803 | |
3804 | skipws(); |
3805 | if (_curchar == '$') { |
3806 | char* ident = get_rep_var_ident(); |
3807 | if (strcmp(ident, "$$template") == 0) return template_parse(); |
3808 | parse_err(SYNERR1, "Unknown \"%s\" directive in format", ident); |
3809 | return NULL__null; |
3810 | } |
3811 | // Check for the opening '"' inside the format description |
3812 | if ( _curchar == '"' ) { |
3813 | next_char(); // Move past the initial '"' |
3814 | if( _curchar == '"' ) { // Handle empty format string case |
3815 | *_ptr = '\0'; // Terminate empty string |
3816 | format->_strings.addName(_ptr); |
3817 | } |
3818 | |
3819 | // Collect the parts of the format description |
3820 | // (1) strings that are passed through to tty->print |
3821 | // (2) replacement/substitution variable, preceeded by a '$' |
3822 | // (3) multi-token ANSIY C style strings |
3823 | while ( true ) { |
3824 | if ( _curchar == '%' || _curchar == '\n' ) { |
3825 | if ( _curchar != '"' ) { |
3826 | parse_err(SYNERR1, "missing '\"' at end of format block"); |
3827 | return NULL__null; |
3828 | } |
3829 | } |
3830 | |
3831 | // (1) |
3832 | // Check if there is a string to pass through to output |
3833 | char *start = _ptr; // Record start of the next string |
3834 | while ((_curchar != '$') && (_curchar != '"') && (_curchar != '%') && (_curchar != '\n')) { |
3835 | if (_curchar == '\\') { |
3836 | next_char(); // superquote |
3837 | if ((_curchar == '$') || (_curchar == '%')) |
3838 | // hack to avoid % escapes and warnings about undefined \ escapes |
3839 | *(_ptr-1) = _curchar; |
3840 | } |
3841 | if (_curchar == '\n') parse_err(SYNERR1, "newline in string"); // unimplemented! |
3842 | next_char(); |
3843 | } |
3844 | // If a string was found, terminate it and record in FormatRule |
3845 | if ( start != _ptr ) { |
3846 | *_ptr = '\0'; // Terminate the string |
3847 | format->_strings.addName(start); |
3848 | } |
3849 | |
3850 | // (2) |
3851 | // If we are at a replacement variable, |
3852 | // copy it and record in FormatRule |
3853 | if ( _curchar == '$' ) { |
3854 | next_char(); // Move past the '$' |
3855 | char* rep_var = get_ident(); // Nil terminate the variable name |
3856 | rep_var = strdup(rep_var);// Copy the string |
3857 | *_ptr = _curchar; // and replace Nil with original character |
3858 | format->_rep_vars.addName(rep_var); |
3859 | // Add flag to _strings list indicating we should check _rep_vars |
3860 | format->_strings.addName(NameList::_signal); |
3861 | } |
3862 | |
3863 | // (3) |
3864 | // Allow very long strings to be broken up, |
3865 | // using the ANSI C syntax "foo\n" <newline> "bar" |
3866 | if ( _curchar == '"') { |
3867 | next_char(); // Move past the '"' |
3868 | skipws(); // Skip white space before next string token |
3869 | if ( _curchar != '"') { |
3870 | break; |
3871 | } else { |
3872 | // Found one. Skip both " and the whitespace in between. |
3873 | next_char(); |
3874 | } |
3875 | } |
3876 | } // end while part of format description |
3877 | |
3878 | // Check for closing '"' and '%}' in format description |
3879 | skipws(); // Move to closing '%}' |
3880 | if ( _curchar != '%' ) { |
3881 | parse_err(SYNERR1, "non-blank characters between closing '\"' and '%%' in format"); |
3882 | return NULL__null; |
3883 | } |
3884 | } // Done with format description inside |
3885 | |
3886 | skipws(); |
3887 | // Past format description, at '%' |
3888 | if ( _curchar != '%' || *(_ptr+1) != '}' ) { |
3889 | parse_err(SYNERR1, "missing '%%}' at end of format block"); |
3890 | return NULL__null; |
3891 | } |
3892 | next_char(); // Move past the '%' |
3893 | next_char(); // Move past the '}' |
3894 | } |
3895 | else { // parameter list alone must terminate with a ';' |
3896 | parse_err(SYNERR1, "missing ';' after Format expression"); |
3897 | return NULL__null; |
3898 | } |
3899 | // Debug Stuff |
3900 | if (_AD._adl_debug > 1) fprintf(stderrstderr,"Format Rule: %s\n", desc); |
3901 | |
3902 | skipws(); |
3903 | return format; |
3904 | } |
3905 | |
3906 | |
3907 | //------------------------------template_parse----------------------------------- |
3908 | FormatRule* ADLParser::template_parse(void) { |
3909 | char *desc = NULL__null; |
3910 | FormatRule *format = (new FormatRule(desc)); |
3911 | |
3912 | skipws(); |
3913 | while ( (_curchar != '%') && (*(_ptr+1) != '}') ) { |
3914 | |
3915 | // (1) |
3916 | // Check if there is a string to pass through to output |
3917 | { |
3918 | char *start = _ptr; // Record start of the next string |
3919 | while ((_curchar != '$') && ((_curchar != '%') || (*(_ptr+1) != '}')) ) { |
3920 | // If at the start of a comment, skip past it |
3921 | if( (_curchar == '/') && ((*(_ptr+1) == '/') || (*(_ptr+1) == '*')) ) { |
3922 | skipws_no_preproc(); |
3923 | } else { |
3924 | // ELSE advance to the next character, or start of the next line |
3925 | next_char_or_line(); |
3926 | } |
3927 | } |
3928 | // If a string was found, terminate it and record in EncClass |
3929 | if ( start != _ptr ) { |
3930 | *_ptr = '\0'; // Terminate the string |
3931 | // Add flag to _strings list indicating we should check _rep_vars |
3932 | format->_strings.addName(NameList::_signal2); |
3933 | format->_strings.addName(start); |
3934 | } |
3935 | } |
3936 | |
3937 | // (2) |
3938 | // If we are at a replacement variable, |
3939 | // copy it and record in EncClass |
3940 | if ( _curchar == '$' ) { |
3941 | // Found replacement Variable |
3942 | char *rep_var = get_rep_var_ident_dup(); |
3943 | if (strcmp(rep_var, "$emit") == 0) { |
3944 | // switch to normal format parsing |
3945 | next_char(); |
3946 | next_char(); |
3947 | skipws(); |
3948 | // Check for the opening '"' inside the format description |
3949 | if ( _curchar == '"' ) { |
3950 | next_char(); // Move past the initial '"' |
3951 | if( _curchar == '"' ) { // Handle empty format string case |
3952 | *_ptr = '\0'; // Terminate empty string |
3953 | format->_strings.addName(_ptr); |
3954 | } |
3955 | |
3956 | // Collect the parts of the format description |
3957 | // (1) strings that are passed through to tty->print |
3958 | // (2) replacement/substitution variable, preceeded by a '$' |
3959 | // (3) multi-token ANSIY C style strings |
3960 | while ( true ) { |
3961 | if ( _curchar == '%' || _curchar == '\n' ) { |
3962 | parse_err(SYNERR1, "missing '\"' at end of format block"); |
3963 | return NULL__null; |
3964 | } |
3965 | |
3966 | // (1) |
3967 | // Check if there is a string to pass through to output |
3968 | char *start = _ptr; // Record start of the next string |
3969 | while ((_curchar != '$') && (_curchar != '"') && (_curchar != '%') && (_curchar != '\n')) { |
3970 | if (_curchar == '\\') next_char(); // superquote |
3971 | if (_curchar == '\n') parse_err(SYNERR1, "newline in string"); // unimplemented! |
3972 | next_char(); |
3973 | } |
3974 | // If a string was found, terminate it and record in FormatRule |
3975 | if ( start != _ptr ) { |
3976 | *_ptr = '\0'; // Terminate the string |
3977 | format->_strings.addName(start); |
3978 | } |
3979 | |
3980 | // (2) |
3981 | // If we are at a replacement variable, |
3982 | // copy it and record in FormatRule |
3983 | if ( _curchar == '$' ) { |
3984 | next_char(); // Move past the '$' |
3985 | char* next_rep_var = get_ident(); // Nil terminate the variable name |
3986 | next_rep_var = strdup(next_rep_var);// Copy the string |
3987 | *_ptr = _curchar; // and replace Nil with original character |
3988 | format->_rep_vars.addName(next_rep_var); |
3989 | // Add flag to _strings list indicating we should check _rep_vars |
3990 | format->_strings.addName(NameList::_signal); |
3991 | } |
3992 | |
3993 | // (3) |
3994 | // Allow very long strings to be broken up, |
3995 | // using the ANSI C syntax "foo\n" <newline> "bar" |
3996 | if ( _curchar == '"') { |
3997 | next_char(); // Move past the '"' |
3998 | skipws(); // Skip white space before next string token |
3999 | if ( _curchar != '"') { |
4000 | break; |
4001 | } else { |
4002 | // Found one. Skip both " and the whitespace in between. |
4003 | next_char(); |
4004 | } |
4005 | } |
4006 | } // end while part of format description |
4007 | } |
4008 | } else { |
4009 | // Add flag to _strings list indicating we should check _rep_vars |
4010 | format->_rep_vars.addName(rep_var); |
4011 | // Add flag to _strings list indicating we should check _rep_vars |
4012 | format->_strings.addName(NameList::_signal3); |
4013 | } |
4014 | } // end while part of format description |
4015 | } |
4016 | |
4017 | skipws(); |
4018 | // Past format description, at '%' |
4019 | if ( _curchar != '%' || *(_ptr+1) != '}' ) { |
4020 | parse_err(SYNERR1, "missing '%%}' at end of format block"); |
4021 | return NULL__null; |
4022 | } |
4023 | next_char(); // Move past the '%' |
4024 | next_char(); // Move past the '}' |
4025 | |
4026 | // Debug Stuff |
4027 | if (_AD._adl_debug > 1) fprintf(stderrstderr,"Format Rule: %s\n", desc); |
4028 | |
4029 | skipws(); |
4030 | return format; |
4031 | } |
4032 | |
4033 | |
4034 | //------------------------------effect_parse----------------------------------- |
4035 | void ADLParser::effect_parse(InstructForm *instr) { |
4036 | char* desc = NULL__null; |
4037 | |
4038 | skipws(); // Skip whitespace |
4039 | if (_curchar != '(') { |
4040 | parse_err(SYNERR1, "missing '(' in effect definition\n"); |
4041 | return; |
4042 | } |
4043 | // Get list of effect-operand pairs and insert into dictionary |
4044 | else get_effectlist(instr->_effects, instr->_localNames, instr->_has_call); |
4045 | |
4046 | // Debug Stuff |
4047 | if (_AD._adl_debug > 1) fprintf(stderrstderr,"Effect description: %s\n", desc); |
4048 | if (_curchar != ';') { |
4049 | parse_err(SYNERR1, "missing ';' in Effect definition\n"); |
4050 | } |
4051 | next_char(); // Skip ';' |
4052 | |
4053 | } |
4054 | |
4055 | //------------------------------expand_parse----------------------------------- |
4056 | ExpandRule* ADLParser::expand_parse(InstructForm *instr) { |
4057 | char *ident, *ident2; |
4058 | NameAndList *instr_and_operands = NULL__null; |
4059 | ExpandRule *exp = new ExpandRule(); |
4060 | |
4061 | // Expand is a block containing an ordered list of operands with initializers, |
4062 | // or instructions, each of which has an ordered list of operands. |
4063 | // Check for block delimiter |
4064 | skipws(); // Skip leading whitespace |
4065 | if ((_curchar != '%') |
4066 | || (next_char(), (_curchar != '{')) ) { // If not open block |
4067 | parse_err(SYNERR1, "missing '%%{' in expand definition\n"); |
4068 | return(NULL__null); |
4069 | } |
4070 | next_char(); // Maintain the invariant |
4071 | do { |
4072 | ident = get_ident(); // Grab next identifier |
4073 | if (ident == NULL__null) { |
4074 | parse_err(SYNERR1, "identifier expected at %c\n", _curchar); |
4075 | continue; |
4076 | } |
4077 | |
4078 | // Check whether we should parse an instruction or operand. |
4079 | const Form *form = _globalNames[ident]; |
4080 | bool parse_oper = false; |
4081 | bool parse_ins = false; |
4082 | if (form == NULL__null) { |
4083 | skipws(); |
4084 | // Check whether this looks like an instruction specification. If so, |
4085 | // just parse the instruction. The declaration of the instruction is |
4086 | // not needed here. |
4087 | if (_curchar == '(') parse_ins = true; |
4088 | } else if (form->is_instruction()) { |
4089 | parse_ins = true; |
4090 | } else if (form->is_operand()) { |
4091 | parse_oper = true; |
4092 | } else { |
4093 | parse_err(SYNERR1, "instruction/operand name expected at %s\n", ident); |
4094 | continue; |
4095 | } |
4096 | |
4097 | if (parse_oper) { |
4098 | // This is a new operand |
4099 | OperandForm *oper = form->is_operand(); |
4100 | if (oper == NULL__null) { |
4101 | parse_err(SYNERR1, "instruction/operand name expected at %s\n", ident); |
4102 | continue; |
4103 | } |
4104 | // Throw the operand on the _newopers list |
4105 | skipws(); |
4106 | ident = get_unique_ident(instr->_localNames,"Operand"); |
4107 | if (ident == NULL__null) { |
4108 | parse_err(SYNERR1, "identifier expected at %c\n", _curchar); |
4109 | continue; |
4110 | } |
4111 | exp->_newopers.addName(ident); |
4112 | // Add new operand to LocalNames |
4113 | instr->_localNames.Insert(ident, oper); |
4114 | // Grab any constructor code and save as a string |
4115 | char *c = NULL__null; |
4116 | skipws(); |
4117 | if (_curchar == '%') { // Need a constructor for the operand |
4118 | c = find_cpp_block("Operand Constructor"); |
4119 | if (c == NULL__null) { |
4120 | parse_err(SYNERR1, "Invalid code block for operand constructor\n", _curchar); |
4121 | continue; |
4122 | } |
4123 | // Add constructor to _newopconst Dict |
4124 | exp->_newopconst.Insert(ident, c); |
4125 | } |
4126 | else if (_curchar != ';') { // If no constructor, need a ; |
4127 | parse_err(SYNERR1, "Missing ; in expand rule operand declaration\n"); |
4128 | continue; |
4129 | } |
4130 | else next_char(); // Skip the ; |
4131 | skipws(); |
4132 | } |
4133 | else { |
4134 | assert(parse_ins, "sanity"){ if (!(parse_ins)) { fprintf(stderr, "assert fails %s %d: %s\n" , "/home/daniel/Projects/java/jdk/src/hotspot/share/adlc/adlparse.cpp" , 4134, "sanity"); abort(); }}; |
4135 | // Add instruction to list |
4136 | instr_and_operands = new NameAndList(ident); |
4137 | // Grab operands, build nameList of them, and then put into dictionary |
4138 | skipws(); |
4139 | if (_curchar != '(') { // Check for parenthesized operand list |
4140 | parse_err(SYNERR1, "missing '(' in expand instruction declaration\n"); |
4141 | continue; |
4142 | } |
4143 | do { |
4144 | next_char(); // skip open paren & comma characters |
4145 | skipws(); |
4146 | if (_curchar == ')') break; |
4147 | ident2 = get_ident(); |
4148 | skipws(); |
4149 | if (ident2 == NULL__null) { |
4150 | parse_err(SYNERR1, "identifier expected at %c\n", _curchar); |
4151 | continue; |
4152 | } // Check that you have a valid operand |
4153 | const Form *form2 = instr->_localNames[ident2]; |
4154 | if (!form2) { |
4155 | parse_err(SYNERR1, "operand name expected at %s\n", ident2); |
4156 | continue; |
4157 | } |
4158 | OperandForm *oper = form2->is_operand(); |
4159 | if (oper == NULL__null && !form2->is_opclass()) { |
4160 | parse_err(SYNERR1, "operand name expected at %s\n", ident2); |
4161 | continue; |
4162 | } // Add operand to list |
4163 | instr_and_operands->add_entry(ident2); |
4164 | } while(_curchar == ','); |
4165 | if (_curchar != ')') { |
4166 | parse_err(SYNERR1, "missing ')'in expand instruction declaration\n"); |
4167 | continue; |
4168 | } |
4169 | next_char(); |
4170 | if (_curchar != ';') { |
4171 | parse_err(SYNERR1, "missing ';'in expand instruction declaration\n"); |
4172 | continue; |
4173 | } |
4174 | next_char(); |
4175 | |
4176 | // Record both instruction name and its operand list |
4177 | exp->add_instruction(instr_and_operands); |
4178 | |
4179 | skipws(); |
4180 | } |
4181 | |
4182 | } while(_curchar != '%'); |
4183 | next_char(); |
4184 | if (_curchar != '}') { |
4185 | parse_err(SYNERR1, "missing '%%}' in expand rule definition\n"); |
4186 | return(NULL__null); |
4187 | } |
4188 | next_char(); |
4189 | |
4190 | // Debug Stuff |
4191 | if (_AD._adl_debug > 1) fprintf(stderrstderr,"Expand Rule:\n"); |
4192 | |
4193 | skipws(); |
4194 | return (exp); |
4195 | } |
4196 | |
4197 | //------------------------------rewrite_parse---------------------------------- |
4198 | RewriteRule* ADLParser::rewrite_parse(void) { |
4199 | char* params = NULL__null; |
4200 | char* desc = NULL__null; |
4201 | |
4202 | |
4203 | // This feature targeted for second generation description language. |
4204 | |
4205 | skipws(); // Skip whitespace |
4206 | // Get parameters for rewrite |
4207 | if ((params = get_paren_expr("rewrite parameters")) == NULL__null) { |
4208 | parse_err(SYNERR1, "missing '(' in rewrite rule\n"); |
4209 | return NULL__null; |
4210 | } |
4211 | // Debug Stuff |
4212 | if (_AD._adl_debug > 1) fprintf(stderrstderr,"Rewrite parameters: %s\n", params); |
4213 | |
4214 | // For now, grab entire block; |
4215 | skipws(); |
4216 | if ( (desc = find_cpp_block("rewrite block")) == NULL__null ) { |
4217 | parse_err(SYNERR1, "incorrect or missing block for 'rewrite'.\n"); |
4218 | return NULL__null; |
4219 | } |
4220 | // Debug Stuff |
4221 | if (_AD._adl_debug > 1) fprintf(stderrstderr,"Rewrite Rule: %s\n", desc); |
4222 | |
4223 | skipws(); |
4224 | return (new RewriteRule(params,desc)); |
4225 | } |
4226 | |
4227 | //------------------------------attr_parse------------------------------------- |
4228 | Attribute *ADLParser::attr_parse(char* ident) { |
4229 | Attribute *attrib; // Attribute class |
4230 | char *cost = NULL__null; // String representation of cost attribute |
4231 | |
4232 | skipws(); // Skip leading whitespace |
4233 | if ( (cost = get_paren_expr("attribute")) == NULL__null ) { |
4234 | parse_err(SYNERR1, "incorrect or missing expression for 'attribute'\n"); |
4235 | return NULL__null; |
4236 | } |
4237 | // Debug Stuff |
4238 | if (_AD._adl_debug > 1) fprintf(stderrstderr,"Attribute: %s\n", cost); |
4239 | if (_curchar != ';') { |
4240 | parse_err(SYNERR1, "missing ';' in attribute definition\n"); |
4241 | return NULL__null; |
4242 | } |
4243 | next_char(); // Point after the terminator |
4244 | |
4245 | skipws(); |
4246 | attrib = new Attribute(ident,cost,INS_ATTR0); // Build new predicate object |
4247 | return attrib; |
4248 | } |
4249 | |
4250 | |
4251 | //------------------------------matchNode_parse-------------------------------- |
4252 | MatchNode *ADLParser::matchNode_parse(FormDict &operands, int &depth, int &numleaves, bool atroot) { |
4253 | // Count depth of parenthesis nesting for both left and right children |
4254 | int lParens = depth; |
4255 | int rParens = depth; |
4256 | |
4257 | // MatchNode objects for left, right, and root of subtree. |
4258 | MatchNode *lChild = NULL__null; |
4259 | MatchNode *rChild = NULL__null; |
4260 | char *token; // Identifier which may be opcode or operand |
4261 | |
4262 | // Match expression starts with a '(' |
4263 | if (cur_char() != '(') |
4264 | return NULL__null; |
4265 | |
4266 | next_char(); // advance past '(' |
4267 | |
4268 | // Parse the opcode |
4269 | token = get_ident(); // Get identifier, opcode |
4270 | if (token == NULL__null) { |
4271 | parse_err(SYNERR1, "missing opcode in match expression\n"); |
4272 | return NULL__null; |
4273 | } |
4274 | |
4275 | // Take note if we see one of a few special operations - those that are |
4276 | // treated differently on different architectures in the sense that on |
4277 | // one architecture there is a match rule and on another there isn't (so |
4278 | // a call will eventually be generated). |
4279 | |
4280 | for (int i = _last_machine_leaf + 1; i < _last_opcode; i++) { |
4281 | if (strcmp(token, NodeClassNames[i]) == 0) { |
4282 | _AD.has_match_rule(i, true); |
4283 | } |
4284 | } |
4285 | |
4286 | // Lookup the root value in the operands dict to perform substitution |
4287 | const char *result = NULL__null; // Result type will be filled in later |
4288 | const char *name = token; // local name associated with this node |
4289 | const char *operation = token; // remember valid operation for later |
4290 | const Form *form = operands[token]; |
4291 | OpClassForm *opcForm = form ? form->is_opclass() : NULL__null; |
4292 | if (opcForm != NULL__null) { |
4293 | // If this token is an entry in the local names table, record its type |
4294 | if (!opcForm->ideal_only()) { |
4295 | operation = opcForm->_ident; |
4296 | result = operation; // Operands result in their own type |
4297 | } |
4298 | // Otherwise it is an ideal type, and so, has no local name |
4299 | else name = NULL__null; |
4300 | } |
4301 | |
4302 | // Parse the operands |
4303 | skipws(); |
4304 | if (cur_char() != ')') { |
4305 | |
4306 | // Parse the left child |
4307 | if (strcmp(operation,"Set")) |
4308 | lChild = matchChild_parse(operands, lParens, numleaves, false); |
4309 | else |
4310 | lChild = matchChild_parse(operands, lParens, numleaves, true); |
4311 | |
4312 | skipws(); |
4313 | if (cur_char() != ')' ) { |
4314 | if(strcmp(operation, "Set")) |
4315 | rChild = matchChild_parse(operands,rParens,numleaves,false); |
4316 | else |
4317 | rChild = matchChild_parse(operands,rParens,numleaves,true); |
4318 | } |
4319 | } |
4320 | |
4321 | // Check for required ')' |
4322 | skipws(); |
4323 | if (cur_char() != ')') { |
4324 | parse_err(SYNERR1, "missing ')' in match expression\n"); |
4325 | return NULL__null; |
4326 | } |
4327 | next_char(); // skip the ')' |
4328 | |
4329 | MatchNode* mroot = new MatchNode(_AD,result,name,operation,lChild,rChild); |
4330 | |
4331 | // If not the root, reduce this subtree to an internal operand |
4332 | if (!atroot) { |
4333 | mroot->build_internalop(); |
4334 | } |
4335 | // depth is greater of left and right paths. |
4336 | depth = (lParens > rParens) ? lParens : rParens; |
4337 | |
4338 | return mroot; |
4339 | } |
4340 | |
4341 | |
4342 | //------------------------------matchChild_parse------------------------------- |
4343 | MatchNode *ADLParser::matchChild_parse(FormDict &operands, int &parens, int &numleaves, bool atroot) { |
4344 | MatchNode *child = NULL__null; |
4345 | const char *result = NULL__null; |
4346 | const char *token = NULL__null; |
4347 | const char *opType = NULL__null; |
4348 | |
4349 | if (cur_char() == '(') { // child is an operation |
4350 | ++parens; |
4351 | child = matchNode_parse(operands, parens, numleaves, atroot); |
4352 | } |
4353 | else { // child is an operand |
4354 | token = get_ident(); |
4355 | const Form *form = operands[token]; |
4356 | OpClassForm *opcForm = form ? form->is_opclass() : NULL__null; |
4357 | if (opcForm != NULL__null) { |
4358 | opType = opcForm->_ident; |
4359 | result = opcForm->_ident; // an operand's result matches its type |
4360 | } else { |
4361 | parse_err(SYNERR1, "undefined operand %s in match rule\n", token); |
4362 | return NULL__null; |
4363 | } |
4364 | |
4365 | if (opType == NULL__null) { |
4366 | parse_err(SYNERR1, "missing type for argument '%s'\n", token); |
4367 | } |
4368 | |
4369 | child = new MatchNode(_AD, result, token, opType); |
4370 | ++numleaves; |
4371 | } |
4372 | |
4373 | return child; |
4374 | } |
4375 | |
4376 | |
4377 | |
4378 | // ******************** Private Utility Functions ************************* |
4379 | |
4380 | |
4381 | char* ADLParser::find_cpp_block(const char* description) { |
4382 | char *next; // Pointer for finding block delimiters |
4383 | char* cppBlock = NULL__null; // Beginning of C++ code block |
4384 | |
4385 | if (_curchar == '%') { // Encoding is a C++ expression |
4386 | next_char(); |
4387 | if (_curchar != '{') { |
4388 | parse_err(SYNERR1, "missing '{' in %s \n", description); |
4389 | return NULL__null; |
4390 | } |
4391 | next_char(); // Skip block delimiter |
4392 | skipws_no_preproc(); // Skip leading whitespace |
4393 | cppBlock = _ptr; // Point to start of expression |
4394 | int line = linenum(); |
4395 | next = _ptr + 1; |
4396 | while(((_curchar != '%') || (*next != '}')) && (_curchar != '\0')) { |
4397 | next_char_or_line(); |
4398 | next = _ptr+1; // Maintain the next pointer |
4399 | } // Grab string |
4400 | if (_curchar == '\0') { |
4401 | parse_err(SYNERR1, "invalid termination of %s \n", description); |
4402 | return NULL__null; |
4403 | } |
4404 | *_ptr = '\0'; // Terminate string |
4405 | _ptr += 2; // Skip block delimiter |
4406 | _curchar = *_ptr; // Maintain invariant |
4407 | |
4408 | // Prepend location descriptor, for debugging. |
4409 | if (_AD._adlocation_debug) { |
4410 | char* location = get_line_string(line); |
4411 | char* end_loc = end_line_marker(); |
4412 | char* result = (char *)AllocateHeap(strlen(location) + strlen(cppBlock) + strlen(end_loc) + 1); |
4413 | strcpy(result, location); |
4414 | strcat(result, cppBlock); |
4415 | strcat(result, end_loc); |
4416 | cppBlock = result; |
4417 | free(location); |
4418 | } |
4419 | } |
4420 | |
4421 | return cppBlock; |
4422 | } |
4423 | |
4424 | // Move to the closing token of the expression we are currently at, |
4425 | // as defined by stop_chars. Match parens and quotes. |
4426 | char* ADLParser::get_expr(const char *desc, const char *stop_chars) { |
4427 | char* expr = NULL__null; |
4428 | int paren = 0; |
4429 | |
4430 | expr = _ptr; |
4431 | while (paren > 0 || !strchr(stop_chars, _curchar)) { |
4432 | if (_curchar == '(') { // Down level of nesting |
4433 | paren++; // Bump the parenthesis counter |
4434 | next_char(); // maintain the invariant |
4435 | } |
4436 | else if (_curchar == ')') { // Up one level of nesting |
4437 | if (paren == 0) { |
4438 | // Paren underflow: We didn't encounter the required stop-char. |
4439 | parse_err(SYNERR1, "too many )'s, did not find %s after %s\n", |
4440 | stop_chars, desc); |
4441 | return NULL__null; |
4442 | } |
4443 | paren--; // Drop the parenthesis counter |
4444 | next_char(); // Maintain the invariant |
4445 | } |
4446 | else if (_curchar == '"' || _curchar == '\'') { |
4447 | int qchar = _curchar; |
4448 | while (true) { |
4449 | next_char(); |
4450 | if (_curchar == qchar) { next_char(); break; } |
4451 | if (_curchar == '\\') next_char(); // superquote |
4452 | if (_curchar == '\n' || _curchar == '\0') { |
4453 | parse_err(SYNERR1, "newline in string in %s\n", desc); |
4454 | return NULL__null; |
4455 | } |
4456 | } |
4457 | } |
4458 | else if (_curchar == '%' && (_ptr[1] == '{' || _ptr[1] == '}')) { |
4459 | // Make sure we do not stray into the next ADLC-level form. |
4460 | parse_err(SYNERR1, "unexpected %%%c in %s\n", _ptr[1], desc); |
4461 | return NULL__null; |
4462 | } |
4463 | else if (_curchar == '\0') { |
4464 | parse_err(SYNERR1, "unexpected EOF in %s\n", desc); |
4465 | return NULL__null; |
4466 | } |
4467 | else { |
4468 | // Always walk over whitespace, comments, preprocessor directives, etc. |
4469 | char* pre_skip_ptr = _ptr; |
4470 | skipws(); |
4471 | // If the parser declined to make progress on whitespace, |
4472 | // skip the next character, which is therefore NOT whitespace. |
4473 | if (pre_skip_ptr == _ptr) { |
4474 | next_char(); |
4475 | } else if (pre_skip_ptr+strlen(pre_skip_ptr) != _ptr+strlen(_ptr)) { |
4476 | parse_err(SYNERR1, "unimplemented: preprocessor must not elide subexpression in %s", desc); |
4477 | } |
4478 | } |
4479 | } |
4480 | |
4481 | assert(strchr(stop_chars, _curchar), "non-null return must be at stop-char"){ if (!(strchr(stop_chars, _curchar))) { fprintf(stderr, "assert fails %s %d: %s\n" , "/home/daniel/Projects/java/jdk/src/hotspot/share/adlc/adlparse.cpp" , 4481, "non-null return must be at stop-char"); abort(); }}; |
4482 | *_ptr = '\0'; // Replace ')' or other stop-char with '\0' |
4483 | return expr; |
4484 | } |
4485 | |
4486 | // Helper function around get_expr |
4487 | // Sets _curchar to '(' so that get_paren_expr will search for a matching ')' |
4488 | char *ADLParser::get_paren_expr(const char *description, bool include_location) { |
4489 | int line = linenum(); |
4490 | if (_curchar != '(') // Escape if not valid starting position |
4491 | return NULL__null; |
4492 | next_char(); // Skip the required initial paren. |
4493 | char *token2 = get_expr(description, ")"); |
4494 | if (_curchar == ')') |
4495 | next_char(); // Skip required final paren. |
4496 | int junk = 0; |
4497 | if (include_location && _AD._adlocation_debug && !is_int_token(token2, junk)) { |
4498 | // Prepend location descriptor, for debugging. |
4499 | char* location = get_line_string(line); |
4500 | char* end_loc = end_line_marker(); |
4501 | char* result = (char *)AllocateHeap(strlen(location) + strlen(token2) + strlen(end_loc) + 1); |
4502 | strcpy(result, location); |
4503 | strcat(result, token2); |
4504 | strcat(result, end_loc); |
4505 | token2 = result; |
4506 | free(location); |
4507 | } |
4508 | return token2; |
4509 | } |
4510 | |
4511 | //------------------------------get_ident_common------------------------------- |
4512 | // Looks for an identifier in the buffer, and turns it into a null terminated |
4513 | // string(still inside the file buffer). Returns a pointer to the string or |
4514 | // NULL if some other token is found instead. |
4515 | char *ADLParser::get_ident_common(bool do_preproc) { |
4516 | char c; |
4517 | char *start; // Pointer to start of token |
4518 | char *end; // Pointer to end of token |
4519 | |
4520 | if( _curline == NULL__null ) // Return NULL at EOF. |
4521 | return NULL__null; |
4522 | |
4523 | skipws_common(do_preproc); // Skip whitespace before identifier |
4524 | start = end = _ptr; // Start points at first character |
4525 | end--; // unwind end by one to prepare for loop |
4526 | do { |
4527 | end++; // Increment end pointer |
4528 | c = *end; // Grab character to test |
4529 | } while ( ((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z')) |
4530 | || ((c >= '0') && (c <= '9')) |
4531 | || ((c == '_')) || ((c == ':')) || ((c == '#')) ); |
4532 | if (start == end) { // We popped out on the first try |
4533 | // It can occur that `start' contains the rest of the input file. |
4534 | // In this case the output should be truncated. |
4535 | if (strlen(start) > 24) { |
4536 | char buf[32]; |
4537 | strncpy(buf, start, 20); |
4538 | buf[20] = '\0'; |
4539 | strcat(buf, "[...]"); |
4540 | parse_err(SYNERR1, "Identifier expected, but found '%s'.", buf); |
4541 | } else { |
4542 | parse_err(SYNERR1, "Identifier expected, but found '%s'.", start); |
4543 | } |
4544 | start = NULL__null; |
4545 | } |
4546 | else { |
4547 | _curchar = c; // Save the first character of next token |
4548 | *end = '\0'; // NULL terminate the string in place |
4549 | } |
4550 | _ptr = end; // Reset _ptr to point to next char after token |
4551 | |
4552 | // Make sure we do not try to use #defined identifiers. If start is |
4553 | // NULL an error was already reported. |
4554 | if (do_preproc && start != NULL__null) { |
4555 | const char* def = _AD.get_preproc_def(start); |
4556 | if (def != NULL__null && strcmp(def, start)) { |
4557 | const char* def1 = def; |
4558 | const char* def2 = _AD.get_preproc_def(def1); |
4559 | // implement up to 2 levels of #define |
4560 | if (def2 != NULL__null && strcmp(def2, def1)) { |
4561 | def = def2; |
4562 | const char* def3 = _AD.get_preproc_def(def2); |
4563 | if (def3 != NULL__null && strcmp(def3, def2) && strcmp(def3, def1)) { |
4564 | parse_err(SYNERR1, "unimplemented: using %s defined as %s => %s => %s", |
4565 | start, def1, def2, def3); |
4566 | } |
4567 | } |
4568 | start = strdup(def); |
4569 | } |
4570 | } |
4571 | |
4572 | return start; // Pointer to token in filebuf |
4573 | } |
4574 | |
4575 | //------------------------------get_ident_dup---------------------------------- |
4576 | // Looks for an identifier in the buffer, and returns a duplicate |
4577 | // or NULL if some other token is found instead. |
4578 | char *ADLParser::get_ident_dup(void) { |
4579 | char *ident = get_ident(); |
4580 | |
4581 | // Duplicate an identifier before returning and restore string. |
4582 | if( ident != NULL__null ) { |
4583 | ident = strdup(ident); // Copy the string |
4584 | *_ptr = _curchar; // and replace Nil with original character |
4585 | } |
4586 | |
4587 | return ident; |
4588 | } |
4589 | |
4590 | //----------------------get_ident_or_literal_constant-------------------------- |
4591 | // Looks for an identifier in the buffer, or a parenthesized expression. |
4592 | char *ADLParser::get_ident_or_literal_constant(const char* description) { |
4593 | char* param = NULL__null; |
4594 | skipws(); |
4595 | if (_curchar == '(') { |
4596 | // Grab a constant expression. |
4597 | param = get_paren_expr(description); |
4598 | if (param[0] != '(') { |
4599 | char* buf = (char*) AllocateHeap(strlen(param) + 3); |
4600 | sprintf(buf, "(%s)", param); |
4601 | param = buf; |
4602 | } |
4603 | assert(is_literal_constant(param),{ if (!(is_literal_constant(param))) { fprintf(stderr, "assert fails %s %d: %s\n" , "/home/daniel/Projects/java/jdk/src/hotspot/share/adlc/adlparse.cpp" , 4604, "expr must be recognizable as a constant"); abort(); } } |
4604 | "expr must be recognizable as a constant"){ if (!(is_literal_constant(param))) { fprintf(stderr, "assert fails %s %d: %s\n" , "/home/daniel/Projects/java/jdk/src/hotspot/share/adlc/adlparse.cpp" , 4604, "expr must be recognizable as a constant"); abort(); } }; |
4605 | } else { |
4606 | param = get_ident(); |
4607 | } |
4608 | return param; |
4609 | } |
4610 | |
4611 | //------------------------------get_rep_var_ident----------------------------- |
4612 | // Do NOT duplicate, |
4613 | // Leave nil terminator in buffer |
4614 | // Preserve initial '$'(s) in string |
4615 | char *ADLParser::get_rep_var_ident(void) { |
4616 | // Remember starting point |
4617 | char *rep_var = _ptr; |
4618 | |
4619 | // Check for replacement variable indicator '$' and pass if present |
4620 | if ( _curchar == '$' ) { |
4621 | next_char(); |
4622 | } |
4623 | // Check for a subfield indicator, a second '$', and pass if present |
4624 | if ( _curchar == '$' ) { |
4625 | next_char(); |
4626 | } |
4627 | |
4628 | // Check for a control indicator, a third '$': |
4629 | if ( _curchar == '$' ) { |
4630 | next_char(); |
4631 | } |
4632 | |
4633 | // Check for more than three '$'s in sequence, SYNERR |
4634 | if( _curchar == '$' ) { |
4635 | parse_err(SYNERR1, "Replacement variables and field specifiers can not start with '$$$$'"); |
4636 | next_char(); |
4637 | return NULL__null; |
4638 | } |
4639 | |
4640 | // Nil terminate the variable name following the '$' |
4641 | char *rep_var_name = get_ident(); |
4642 | assert( rep_var_name != NULL,{ if (!(rep_var_name != __null)) { fprintf(stderr, "assert fails %s %d: %s\n" , "/home/daniel/Projects/java/jdk/src/hotspot/share/adlc/adlparse.cpp" , 4643, "Missing identifier after replacement variable indicator '$'" ); abort(); }} |
4643 | "Missing identifier after replacement variable indicator '$'"){ if (!(rep_var_name != __null)) { fprintf(stderr, "assert fails %s %d: %s\n" , "/home/daniel/Projects/java/jdk/src/hotspot/share/adlc/adlparse.cpp" , 4643, "Missing identifier after replacement variable indicator '$'" ); abort(); }}; |
4644 | |
4645 | return rep_var; |
4646 | } |
4647 | |
4648 | |
4649 | |
4650 | //------------------------------get_rep_var_ident_dup------------------------- |
4651 | // Return the next replacement variable identifier, skipping first '$' |
4652 | // given a pointer into a line of the buffer. |
4653 | // Null terminates string, still inside the file buffer, |
4654 | // Returns a pointer to a copy of the string, or NULL on failure |
4655 | char *ADLParser::get_rep_var_ident_dup(void) { |
4656 | if( _curchar != '$' ) return NULL__null; |
4657 | |
4658 | next_char(); // Move past the '$' |
4659 | char *rep_var = _ptr; // Remember starting point |
4660 | |
4661 | // Check for a subfield indicator, a second '$': |
4662 | if ( _curchar == '$' ) { |
4663 | next_char(); |
4664 | } |
4665 | |
4666 | // Check for a control indicator, a third '$': |
4667 | if ( _curchar == '$' ) { |
4668 | next_char(); |
4669 | } |
4670 | |
4671 | // Check for more than three '$'s in sequence, SYNERR |
4672 | if( _curchar == '$' ) { |
4673 | parse_err(SYNERR1, "Replacement variables and field specifiers can not start with '$$$$'"); |
4674 | next_char(); |
4675 | return NULL__null; |
4676 | } |
4677 | |
4678 | // Nil terminate the variable name following the '$' |
4679 | char *rep_var_name = get_ident(); |
4680 | assert( rep_var_name != NULL,{ if (!(rep_var_name != __null)) { fprintf(stderr, "assert fails %s %d: %s\n" , "/home/daniel/Projects/java/jdk/src/hotspot/share/adlc/adlparse.cpp" , 4681, "Missing identifier after replacement variable indicator '$'" ); abort(); }} |
4681 | "Missing identifier after replacement variable indicator '$'"){ if (!(rep_var_name != __null)) { fprintf(stderr, "assert fails %s %d: %s\n" , "/home/daniel/Projects/java/jdk/src/hotspot/share/adlc/adlparse.cpp" , 4681, "Missing identifier after replacement variable indicator '$'" ); abort(); }}; |
4682 | rep_var = strdup(rep_var); // Copy the string |
4683 | *_ptr = _curchar; // and replace Nil with original character |
4684 | |
4685 | return rep_var; |
4686 | } |
4687 | |
4688 | |
4689 | //------------------------------get_unique_ident------------------------------ |
4690 | // Looks for an identifier in the buffer, terminates it with a NULL, |
4691 | // and checks that it is unique |
4692 | char *ADLParser::get_unique_ident(FormDict& dict, const char* nameDescription){ |
4693 | char* ident = get_ident(); |
4694 | |
4695 | if (ident == NULL__null) { |
4696 | parse_err(SYNERR1, "missing %s identifier at %c\n", nameDescription, _curchar); |
4697 | } |
4698 | else { |
4699 | if (dict[ident] != NULL__null) { |
4700 | parse_err(SYNERR1, "duplicate name %s for %s\n", ident, nameDescription); |
4701 | ident = NULL__null; |
4702 | } |
4703 | } |
4704 | |
4705 | return ident; |
4706 | } |
4707 | |
4708 | |
4709 | //------------------------------get_int---------------------------------------- |
4710 | // Looks for a character string integer in the buffer, and turns it into an int |
4711 | // invokes a parse_err if the next token is not an integer. |
4712 | // This routine does not leave the integer null-terminated. |
4713 | int ADLParser::get_int(void) { |
4714 | char c; |
4715 | char *start; // Pointer to start of token |
4716 | char *end; // Pointer to end of token |
4717 | int result; // Storage for integer result |
4718 | |
4719 | if( _curline == NULL__null ) // Return NULL at EOF. |
4720 | return 0; |
4721 | |
4722 | skipws(); // Skip whitespace before identifier |
4723 | start = end = _ptr; // Start points at first character |
4724 | c = *end; // Grab character to test |
4725 | while ((c >= '0' && c <= '9') || (c == '-' && end == start)) { |
4726 | end++; // Increment end pointer |
4727 | c = *end; // Grab character to test |
4728 | } |
4729 | if (start == end) { // We popped out on the first try |
4730 | parse_err(SYNERR1, "integer expected at %c\n", c); |
4731 | result = 0; |
4732 | } |
4733 | else { |
4734 | _curchar = c; // Save the first character of next token |
4735 | *end = '\0'; // NULL terminate the string in place |
4736 | result = atoi(start); // Convert the string to an integer |
4737 | *end = _curchar; // Restore buffer to original condition |
4738 | } |
4739 | |
4740 | // Reset _ptr to next char after token |
4741 | _ptr = end; |
4742 | |
4743 | return result; // integer |
4744 | } |
4745 | |
4746 | |
4747 | //------------------------------get_relation_dup------------------------------ |
4748 | // Looks for a relational operator in the buffer |
4749 | // invokes a parse_err if the next token is not a relation |
4750 | // This routine creates a duplicate of the string in the buffer. |
4751 | char *ADLParser::get_relation_dup(void) { |
4752 | char *result = NULL__null; // relational operator being returned |
4753 | |
4754 | if( _curline == NULL__null ) // Return NULL at EOF. |
4755 | return NULL__null; |
4756 | |
4757 | skipws(); // Skip whitespace before relation |
4758 | char *start = _ptr; // Store start of relational operator |
4759 | char first = *_ptr; // the first character |
4760 | if( (first == '=') || (first == '!') || (first == '<') || (first == '>') ) { |
4761 | next_char(); |
4762 | char second = *_ptr; // the second character |
4763 | if( second == '=' ) { |
4764 | next_char(); |
4765 | char tmp = *_ptr; |
4766 | *_ptr = '\0'; // NULL terminate |
4767 | result = strdup(start); // Duplicate the string |
4768 | *_ptr = tmp; // restore buffer |
4769 | } else { |
4770 | parse_err(SYNERR1, "relational operator expected at %s\n", _ptr); |
4771 | } |
4772 | } else { |
4773 | parse_err(SYNERR1, "relational operator expected at %s\n", _ptr); |
4774 | } |
4775 | |
4776 | return result; |
4777 | } |
4778 | |
4779 | |
4780 | |
4781 | //------------------------------get_oplist------------------------------------- |
4782 | // Looks for identifier pairs where first must be the name of an operand, and |
4783 | // second must be a name unique in the scope of this instruction. Stores the |
4784 | // names with a pointer to the OpClassForm of their type in a local name table. |
4785 | void ADLParser::get_oplist(NameList ¶meters, FormDict &operands) { |
4786 | OpClassForm *opclass = NULL__null; |
4787 | char *ident = NULL__null; |
4788 | |
4789 | do { |
4790 | next_char(); // skip open paren & comma characters |
4791 | skipws(); |
4792 | if (_curchar == ')') break; |
4793 | |
4794 | // Get operand type, and check it against global name table |
4795 | ident = get_ident(); |
4796 | if (ident == NULL__null) { |
4797 | parse_err(SYNERR1, "optype identifier expected at %c\n", _curchar); |
4798 | return; |
4799 | } |
4800 | else { |
4801 | const Form *form = _globalNames[ident]; |
4802 | if( form == NULL__null ) { |
4803 | parse_err(SYNERR1, "undefined operand type %s\n", ident); |
4804 | return; |
4805 | } |
4806 | |
4807 | // Check for valid operand type |
4808 | OpClassForm *opc = form->is_opclass(); |
4809 | OperandForm *oper = form->is_operand(); |
4810 | if((oper == NULL__null) && (opc == NULL__null)) { |
4811 | parse_err(SYNERR1, "identifier %s not operand type\n", ident); |
4812 | return; |
4813 | } |
4814 | opclass = opc; |
4815 | } |
4816 | // Debugging Stuff |
4817 | if (_AD._adl_debug > 1) fprintf(stderrstderr, "\tOperand Type: %s\t", ident); |
4818 | |
4819 | // Get name of operand and add it to local name table |
4820 | if( (ident = get_unique_ident(operands, "operand")) == NULL__null) { |
4821 | return; |
4822 | } |
4823 | // Parameter names must not be global names. |
4824 | if( _globalNames[ident] != NULL__null ) { |
4825 | parse_err(SYNERR1, "Reuse of global name %s as operand.\n",ident); |
4826 | return; |
4827 | } |
4828 | operands.Insert(ident, opclass); |
4829 | parameters.addName(ident); |
4830 | |
4831 | // Debugging Stuff |
4832 | if (_AD._adl_debug > 1) fprintf(stderrstderr, "\tOperand Name: %s\n", ident); |
4833 | skipws(); |
4834 | } while(_curchar == ','); |
4835 | |
4836 | if (_curchar != ')') parse_err(SYNERR1, "missing ')'\n"); |
4837 | else { |
4838 | next_char(); // set current character position past the close paren |
4839 | } |
4840 | } |
4841 | |
4842 | |
4843 | //------------------------------get_effectlist--------------------------------- |
4844 | // Looks for identifier pairs where first must be the name of a pre-defined, |
4845 | // effect, and the second must be the name of an operand defined in the |
4846 | // operand list of this instruction. Stores the names with a pointer to the |
4847 | // effect form in a local effects table. |
4848 | void ADLParser::get_effectlist(FormDict &effects, FormDict &operands, bool& has_call) { |
4849 | OperandForm *opForm; |
4850 | Effect *eForm; |
4851 | char *ident; |
4852 | |
4853 | do { |
4854 | next_char(); // skip open paren & comma characters |
4855 | skipws(); |
4856 | if (_curchar == ')') break; |
4857 | |
4858 | // Get effect type, and check it against global name table |
4859 | ident = get_ident(); |
4860 | if (ident == NULL__null) { |
4861 | parse_err(SYNERR1, "effect type identifier expected at %c\n", _curchar); |
4862 | return; |
4863 | } |
4864 | else { |
4865 | // Check for valid effect type |
4866 | const Form *form = _globalNames[ident]; |
4867 | if( form == NULL__null ) { |
4868 | parse_err(SYNERR1, "undefined effect type %s\n", ident); |
4869 | return; |
4870 | } |
4871 | else { |
4872 | if( (eForm = form->is_effect()) == NULL__null) { |
4873 | parse_err(SYNERR1, "identifier %s not effect type\n", ident); |
4874 | return; |
4875 | } |
4876 | } |
4877 | } |
4878 | // Debugging Stuff |
4879 | if (_AD._adl_debug > 1) fprintf(stderrstderr, "\tEffect Type: %s\t", ident); |
4880 | skipws(); |
4881 | if (eForm->is(Component::CALL)) { |
4882 | if (_AD._adl_debug > 1) fprintf(stderrstderr, "\n"); |
4883 | has_call = true; |
4884 | } else { |
4885 | // Get name of operand and check that it is in the local name table |
4886 | if( (ident = get_unique_ident(effects, "effect")) == NULL__null) { |
4887 | parse_err(SYNERR1, "missing operand identifier in effect list\n"); |
4888 | return; |
4889 | } |
4890 | const Form *form = operands[ident]; |
4891 | opForm = form ? form->is_operand() : NULL__null; |
4892 | if( opForm == NULL__null ) { |
4893 | if( form && form->is_opclass() ) { |
4894 | const char* cname = form->is_opclass()->_ident; |
4895 | parse_err(SYNERR1, "operand classes are illegal in effect lists (found %s %s)\n", cname, ident); |
4896 | } else { |
4897 | parse_err(SYNERR1, "undefined operand %s in effect list\n", ident); |
4898 | } |
4899 | return; |
4900 | } |
4901 | // Add the pair to the effects table |
4902 | effects.Insert(ident, eForm); |
4903 | // Debugging Stuff |
4904 | if (_AD._adl_debug > 1) fprintf(stderrstderr, "\tOperand Name: %s\n", ident); |
4905 | } |
4906 | skipws(); |
4907 | } while(_curchar == ','); |
4908 | |
4909 | if (_curchar != ')') parse_err(SYNERR1, "missing ')'\n"); |
4910 | else { |
4911 | next_char(); // set current character position past the close paren |
4912 | } |
4913 | } |
4914 | |
4915 | |
4916 | //-------------------------------preproc_line---------------------------------- |
4917 | // A "#line" keyword has been seen, so parse the rest of the line. |
4918 | void ADLParser::preproc_line(void) { |
4919 | int line = get_int(); |
4920 | skipws_no_preproc(); |
4921 | const char* file = NULL__null; |
4922 | if (_curchar == '"') { |
4923 | next_char(); // Move past the initial '"' |
4924 | file = _ptr; |
4925 | while (true) { |
4926 | if (_curchar == '\n') { |
4927 | parse_err(SYNERR1, "missing '\"' at end of #line directive"); |
4928 | return; |
4929 | } |
4930 | if (_curchar == '"') { |
4931 | *_ptr = '\0'; // Terminate the string |
4932 | next_char(); |
4933 | skipws_no_preproc(); |
4934 | break; |
4935 | } |
4936 | next_char(); |
4937 | } |
4938 | } |
4939 | ensure_end_of_line(); |
4940 | if (file != NULL__null) |
4941 | _AD._ADL_file._name = file; |
4942 | _buf.set_linenum(line); |
4943 | } |
4944 | |
4945 | //------------------------------preproc_define--------------------------------- |
4946 | // A "#define" keyword has been seen, so parse the rest of the line. |
4947 | void ADLParser::preproc_define(void) { |
4948 | char* flag = get_ident_no_preproc(); |
4949 | skipws_no_preproc(); |
4950 | // only #define x y is supported for now |
4951 | char* def = get_ident_no_preproc(); |
4952 | _AD.set_preproc_def(flag, def); |
4953 | skipws_no_preproc(); |
4954 | if (_curchar != '\n') { |
4955 | parse_err(SYNERR1, "non-identifier in preprocessor definition\n"); |
4956 | } |
4957 | } |
4958 | |
4959 | //------------------------------preproc_undef---------------------------------- |
4960 | // An "#undef" keyword has been seen, so parse the rest of the line. |
4961 | void ADLParser::preproc_undef(void) { |
4962 | char* flag = get_ident_no_preproc(); |
4963 | skipws_no_preproc(); |
4964 | ensure_end_of_line(); |
4965 | _AD.set_preproc_def(flag, NULL__null); |
4966 | } |
4967 | |
4968 | |
4969 | |
4970 | //------------------------------parse_err-------------------------------------- |
4971 | // Issue a parser error message, and skip to the end of the current line |
4972 | void ADLParser::parse_err(int flag, const char *fmt, ...) { |
4973 | va_list args; |
4974 | |
4975 | va_start(args, fmt)__builtin_va_start(args, fmt); |
4976 | if (flag == 1) |
4977 | _AD._syntax_errs += _AD.emit_msg(0, flag, linenum(), fmt, args); |
4978 | else if (flag == 2) |
4979 | _AD._semantic_errs += _AD.emit_msg(0, flag, linenum(), fmt, args); |
4980 | else |
4981 | _AD._warnings += _AD.emit_msg(0, flag, linenum(), fmt, args); |
4982 | |
4983 | int error_char = _curchar; |
4984 | char* error_ptr = _ptr+1; |
4985 | for(;*_ptr != '\n'; _ptr++) ; // Skip to the end of the current line |
4986 | _curchar = '\n'; |
4987 | va_end(args)__builtin_va_end(args); |
4988 | _AD._no_output = 1; |
4989 | |
4990 | if (flag == 1) { |
4991 | char* error_tail = strchr(error_ptr, '\n'); |
4992 | char tem = *error_ptr; |
4993 | error_ptr[-1] = '\0'; |
4994 | char* error_head = error_ptr-1; |
4995 | while (error_head > _curline && *error_head) --error_head; |
4996 | if (error_tail) *error_tail = '\0'; |
4997 | fprintf(stderrstderr, "Error Context: %s>>>%c<<<%s\n", |
4998 | error_head, error_char, error_ptr); |
4999 | if (error_tail) *error_tail = '\n'; |
5000 | error_ptr[-1] = tem; |
5001 | } |
5002 | } |
5003 | |
5004 | //---------------------------ensure_start_of_line------------------------------ |
5005 | // A preprocessor directive has been encountered. Be sure it has fallen at |
5006 | // the beginning of a line, or else report an error. |
5007 | void ADLParser::ensure_start_of_line(void) { |
5008 | if (_curchar == '\n') { next_line(); return; } |
5009 | assert( _ptr >= _curline && _ptr < _curline+strlen(_curline),{ if (!(_ptr >= _curline && _ptr < _curline+strlen (_curline))) { fprintf(stderr, "assert fails %s %d: %s\n", "/home/daniel/Projects/java/jdk/src/hotspot/share/adlc/adlparse.cpp" , 5010, "Must be able to find which line we are in"); abort() ; }} |
5010 | "Must be able to find which line we are in" ){ if (!(_ptr >= _curline && _ptr < _curline+strlen (_curline))) { fprintf(stderr, "assert fails %s %d: %s\n", "/home/daniel/Projects/java/jdk/src/hotspot/share/adlc/adlparse.cpp" , 5010, "Must be able to find which line we are in"); abort() ; }}; |
5011 | |
5012 | for (char *s = _curline; s < _ptr; s++) { |
5013 | if (*s > ' ') { |
5014 | parse_err(SYNERR1, "'%c' must be at beginning of line\n", _curchar); |
5015 | break; |
5016 | } |
5017 | } |
5018 | } |
5019 | |
5020 | //---------------------------ensure_end_of_line-------------------------------- |
5021 | // A preprocessor directive has been parsed. Be sure there is no trailing |
5022 | // garbage at the end of this line. Set the scan point to the beginning of |
5023 | // the next line. |
5024 | void ADLParser::ensure_end_of_line(void) { |
5025 | skipws_no_preproc(); |
5026 | if (_curchar != '\n' && _curchar != '\0') { |
5027 | parse_err(SYNERR1, "garbage char '%c' at end of line\n", _curchar); |
5028 | } else { |
5029 | next_char_or_line(); |
5030 | } |
5031 | } |
5032 | |
5033 | //---------------------------handle_preproc------------------------------------ |
5034 | // The '#' character introducing a preprocessor directive has been found. |
5035 | // Parse the whole directive name (e.g., #define, #endif) and take appropriate |
5036 | // action. If we are in an "untaken" span of text, simply keep track of |
5037 | // #ifdef nesting structure, so we can find out when to start taking text |
5038 | // again. (In this state, we "sort of support" C's #if directives, enough |
5039 | // to disregard their associated #else and #endif lines.) If we are in a |
5040 | // "taken" span of text, there are two cases: "#define" and "#undef" |
5041 | // directives are preserved and passed up to the caller, which eventually |
5042 | // passes control to the top-level parser loop, which handles #define and |
5043 | // #undef directly. (This prevents these directives from occurring in |
5044 | // arbitrary positions in the AD file--we require better structure than C.) |
5045 | // In the other case, and #ifdef, #ifndef, #else, or #endif is silently |
5046 | // processed as whitespace, with the "taken" state of the text correctly |
5047 | // updated. This routine returns "false" exactly in the case of a "taken" |
5048 | // #define or #undef, which tells the caller that a preprocessor token |
5049 | // has appeared which must be handled explicitly by the parse loop. |
5050 | bool ADLParser::handle_preproc_token() { |
5051 | assert(*_ptr == '#', "must be at start of preproc"){ if (!(*_ptr == '#')) { fprintf(stderr, "assert fails %s %d: %s\n" , "/home/daniel/Projects/java/jdk/src/hotspot/share/adlc/adlparse.cpp" , 5051, "must be at start of preproc"); abort(); }}; |
5052 | ensure_start_of_line(); |
5053 | next_char(); |
5054 | skipws_no_preproc(); |
5055 | char* start_ident = _ptr; |
5056 | char* ident = (_curchar == '\n') ? NULL__null : get_ident_no_preproc(); |
5057 | if (ident == NULL__null) { |
5058 | parse_err(SYNERR1, "expected preprocessor command, got end of line\n"); |
5059 | } else if (!strcmp(ident, "ifdef") || |
5060 | !strcmp(ident, "ifndef")) { |
5061 | char* flag = get_ident_no_preproc(); |
5062 | ensure_end_of_line(); |
5063 | // Test the identifier only if we are already in taken code: |
5064 | bool flag_def = preproc_taken() && (_AD.get_preproc_def(flag) != NULL__null); |
5065 | bool now_taken = !strcmp(ident, "ifdef") ? flag_def : !flag_def; |
5066 | begin_if_def(now_taken); |
5067 | } else if (!strcmp(ident, "if")) { |
5068 | if (preproc_taken()) |
5069 | parse_err(SYNERR1, "unimplemented: #%s %s", ident, _ptr+1); |
5070 | next_line(); |
5071 | // Intelligently skip this nested C preprocessor directive: |
5072 | begin_if_def(true); |
5073 | } else if (!strcmp(ident, "else")) { |
5074 | ensure_end_of_line(); |
5075 | invert_if_def(); |
5076 | } else if (!strcmp(ident, "endif")) { |
5077 | ensure_end_of_line(); |
5078 | end_if_def(); |
5079 | } else if (preproc_taken()) { |
5080 | // pass this token up to the main parser as "#define" or "#undef" |
5081 | _ptr = start_ident; |
5082 | _curchar = *--_ptr; |
5083 | if( _curchar != '#' ) { |
5084 | parse_err(SYNERR1, "no space allowed after # in #define or #undef"); |
5085 | assert(_curchar == '#', "no space allowed after # in #define or #undef"){ if (!(_curchar == '#')) { fprintf(stderr, "assert fails %s %d: %s\n" , "/home/daniel/Projects/java/jdk/src/hotspot/share/adlc/adlparse.cpp" , 5085, "no space allowed after # in #define or #undef"); abort (); }}; |
5086 | } |
5087 | return false; |
5088 | } |
5089 | return true; |
5090 | } |
5091 | |
5092 | //---------------------------skipws_common------------------------------------- |
5093 | // Skip whitespace, including comments and newlines, while keeping an accurate |
5094 | // line count. |
5095 | // Maybe handle certain preprocessor constructs: #ifdef, #ifndef, #else, #endif |
5096 | void ADLParser::skipws_common(bool do_preproc) { |
5097 | char *start = _ptr; |
5098 | char *next = _ptr + 1; |
5099 | |
5100 | if (*_ptr == '\0') { |
5101 | // Check for string terminator |
5102 | if (_curchar > ' ') return; |
5103 | if (_curchar == '\n') { |
5104 | if (!do_preproc) return; // let caller handle the newline |
5105 | next_line(); |
5106 | _ptr = _curline; next = _ptr + 1; |
5107 | } |
5108 | else if (_curchar == '#' || |
5109 | (_curchar == '/' && (*next == '/' || *next == '*'))) { |
5110 | parse_err(SYNERR1, "unimplemented: comment token in a funny place"); |
5111 | } |
5112 | } |
5113 | while(_curline != NULL__null) { // Check for end of file |
5114 | if (*_ptr == '\n') { // keep proper track of new lines |
5115 | if (!do_preproc) break; // let caller handle the newline |
5116 | next_line(); |
5117 | _ptr = _curline; next = _ptr + 1; |
5118 | } |
5119 | else if ((*_ptr == '/') && (*next == '/')) // C++ comment |
5120 | do { _ptr++; next++; } while(*_ptr != '\n'); // So go to end of line |
5121 | else if ((*_ptr == '/') && (*next == '*')) { // C comment |
5122 | _ptr++; next++; |
5123 | do { |
5124 | _ptr++; next++; |
5125 | if (*_ptr == '\n') { // keep proper track of new lines |
5126 | next_line(); // skip newlines within comments |
5127 | if (_curline == NULL__null) { // check for end of file |
5128 | parse_err(SYNERR1, "end-of-file detected inside comment\n"); |
5129 | break; |
5130 | } |
5131 | _ptr = _curline; next = _ptr + 1; |
5132 | } |
5133 | } while(!((*_ptr == '*') && (*next == '/'))); // Go to end of comment |
5134 | _ptr = ++next; next++; // increment _ptr past comment end |
5135 | } |
5136 | else if (do_preproc && *_ptr == '#') { |
5137 | // Note that this calls skipws_common(false) recursively! |
5138 | bool preproc_handled = handle_preproc_token(); |
5139 | if (!preproc_handled) { |
5140 | if (preproc_taken()) { |
5141 | return; // short circuit |
5142 | } |
5143 | ++_ptr; // skip the preprocessor character |
5144 | } |
5145 | next = _ptr+1; |
5146 | } else if(*_ptr > ' ' && !(do_preproc && !preproc_taken())) { |
5147 | break; |
5148 | } |
5149 | else if (*_ptr == '"' || *_ptr == '\'') { |
5150 | assert(do_preproc, "only skip strings if doing preproc"){ if (!(do_preproc)) { fprintf(stderr, "assert fails %s %d: %s\n" , "/home/daniel/Projects/java/jdk/src/hotspot/share/adlc/adlparse.cpp" , 5150, "only skip strings if doing preproc"); abort(); }}; |
5151 | // skip untaken quoted string |
5152 | int qchar = *_ptr; |
5153 | while (true) { |
5154 | ++_ptr; |
5155 | if (*_ptr == qchar) { ++_ptr; break; } |
5156 | if (*_ptr == '\\') ++_ptr; |
5157 | if (*_ptr == '\n' || *_ptr == '\0') { |
5158 | parse_err(SYNERR1, "newline in string"); |
5159 | break; |
5160 | } |
5161 | } |
5162 | next = _ptr + 1; |
5163 | } |
5164 | else { ++_ptr; ++next; } |
5165 | } |
5166 | if( _curline != NULL__null ) // at end of file _curchar isn't valid |
5167 | _curchar = *_ptr; // reset _curchar to maintain invariant |
5168 | } |
5169 | |
5170 | //---------------------------cur_char----------------------------------------- |
5171 | char ADLParser::cur_char() { |
5172 | return (_curchar); |
5173 | } |
5174 | |
5175 | //---------------------------next_char----------------------------------------- |
5176 | void ADLParser::next_char() { |
5177 | if (_curchar == '\n') parse_err(WARN0, "must call next_line!"); |
5178 | _curchar = *++_ptr; |
5179 | // if ( _curchar == '\n' ) { |
5180 | // next_line(); |
5181 | // } |
5182 | } |
5183 | |
5184 | //---------------------------next_char_or_line--------------------------------- |
5185 | void ADLParser::next_char_or_line() { |
5186 | if ( _curchar != '\n' ) { |
5187 | _curchar = *++_ptr; |
5188 | } else { |
5189 | next_line(); |
5190 | _ptr = _curline; |
5191 | _curchar = *_ptr; // maintain invariant |
5192 | } |
5193 | } |
5194 | |
5195 | //---------------------------next_line----------------------------------------- |
5196 | void ADLParser::next_line() { |
5197 | _curline = _buf.get_line(); |
5198 | _curchar = ' '; |
5199 | } |
5200 | |
5201 | //------------------------get_line_string-------------------------------------- |
5202 | // Prepended location descriptor, for debugging. |
5203 | // Must return a malloced string (that can be freed if desired). |
5204 | char* ADLParser::get_line_string(int linenum) { |
5205 | const char* file = _AD._ADL_file._name; |
5206 | int line = linenum ? linenum : this->linenum(); |
5207 | char* location = (char *)AllocateHeap(strlen(file) + 100); |
5208 | sprintf(location, "\n#line %d \"%s\"\n", line, file); |
5209 | return location; |
5210 | } |
5211 | |
5212 | //-------------------------is_literal_constant--------------------------------- |
5213 | bool ADLParser::is_literal_constant(const char *param) { |
5214 | if (param[0] == 0) return false; // null string |
5215 | if (param[0] == '(') return true; // parenthesized expression |
5216 | if (param[0] == '0' && (param[1] == 'x' || param[1] == 'X')) { |
5217 | // Make sure it's a hex constant. |
5218 | int i = 2; |
5219 | do { |
5220 | if( !ADLParser::is_hex_digit(*(param+i)) ) return false; |
5221 | ++i; |
5222 | } while( *(param+i) != 0 ); |
5223 | return true; |
5224 | } |
5225 | return false; |
5226 | } |
5227 | |
5228 | //---------------------------is_hex_digit-------------------------------------- |
5229 | bool ADLParser::is_hex_digit(char digit) { |
5230 | return ((digit >= '0') && (digit <= '9')) |
5231 | ||((digit >= 'a') && (digit <= 'f')) |
5232 | ||((digit >= 'A') && (digit <= 'F')); |
5233 | } |
5234 | |
5235 | //---------------------------is_int_token-------------------------------------- |
5236 | bool ADLParser::is_int_token(const char* token, int& intval) { |
5237 | const char* cp = token; |
5238 | while (*cp != '\0' && *cp <= ' ') cp++; |
5239 | if (*cp == '-') cp++; |
5240 | int ndigit = 0; |
5241 | while (*cp >= '0' && *cp <= '9') { cp++; ndigit++; } |
5242 | while (*cp != '\0' && *cp <= ' ') cp++; |
5243 | if (ndigit == 0 || *cp != '\0') { |
5244 | return false; |
5245 | } |
5246 | intval = atoi(token); |
5247 | return true; |
5248 | } |
5249 | |
5250 | static const char* skip_expr_ws(const char* str) { |
5251 | const char * cp = str; |
5252 | while (cp[0]) { |
5253 | if (cp[0] <= ' ') { |
5254 | ++cp; |
5255 | } else if (cp[0] == '#') { |
5256 | ++cp; |
5257 | while (cp[0] == ' ') ++cp; |
5258 | assert(0 == strncmp(cp, "line", 4), "must be a #line directive"){ if (!(0 == strncmp(cp, "line", 4))) { fprintf(stderr, "assert fails %s %d: %s\n" , "/home/daniel/Projects/java/jdk/src/hotspot/share/adlc/adlparse.cpp" , 5258, "must be a #line directive"); abort(); }}; |
5259 | const char* eol = strchr(cp, '\n'); |
5260 | assert(eol != NULL, "must find end of line"){ if (!(eol != __null)) { fprintf(stderr, "assert fails %s %d: %s\n" , "/home/daniel/Projects/java/jdk/src/hotspot/share/adlc/adlparse.cpp" , 5260, "must find end of line"); abort(); }}; |
5261 | if (eol == NULL__null) eol = cp + strlen(cp); |
5262 | cp = eol; |
5263 | } else { |
5264 | break; |
5265 | } |
5266 | } |
5267 | return cp; |
5268 | } |
5269 | |
5270 | //-----------------------equivalent_expressions-------------------------------- |
5271 | bool ADLParser::equivalent_expressions(const char* str1, const char* str2) { |
5272 | if (str1 == str2) |
5273 | return true; |
5274 | else if (str1 == NULL__null || str2 == NULL__null) |
5275 | return false; |
5276 | const char* cp1 = str1; |
5277 | const char* cp2 = str2; |
5278 | char in_quote = '\0'; |
5279 | while (cp1[0] && cp2[0]) { |
5280 | if (!in_quote) { |
5281 | // skip spaces and/or cpp directives |
5282 | const char* cp1a = skip_expr_ws(cp1); |
5283 | const char* cp2a = skip_expr_ws(cp2); |
5284 | if (cp1a > cp1 && cp2a > cp2) { |
5285 | cp1 = cp1a; cp2 = cp2a; |
5286 | continue; |
5287 | } |
5288 | if (cp1a > cp1 || cp2a > cp2) break; // fail |
5289 | } |
5290 | // match one non-space char |
5291 | if (cp1[0] != cp2[0]) break; // fail |
5292 | char ch = cp1[0]; |
5293 | cp1++; cp2++; |
5294 | // watch for quotes |
5295 | if (in_quote && ch == '\\') { |
5296 | if (cp1[0] != cp2[0]) break; // fail |
5297 | if (!cp1[0]) break; |
5298 | cp1++; cp2++; |
5299 | } |
5300 | if (in_quote && ch == in_quote) { |
5301 | in_quote = '\0'; |
5302 | } else if (!in_quote && (ch == '"' || ch == '\'')) { |
5303 | in_quote = ch; |
5304 | } |
5305 | } |
5306 | return (!cp1[0] && !cp2[0]); |
5307 | } |
5308 | |
5309 | |
5310 | //-------------------------------trim------------------------------------------ |
5311 | void ADLParser::trim(char* &token) { |
5312 | while (*token <= ' ') token++; |
5313 | char* end = token + strlen(token); |
5314 | while (end > token && *(end-1) <= ' ') --end; |
5315 | *end = '\0'; |
5316 | } |