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
ADLParser(FileBuff & buffer,ArchDesc & archDesc)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; // 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.
~ADLParser()47 ADLParser::~ADLParser() {
48 if (!_AD._quiet_mode)
49 fprintf(stderr,"---------------------------- Errors and Warnings ----------------------------\n");
50 #ifndef ASSERT
51 if (!_AD._quiet_mode) {
52 fprintf(stderr, "**************************************************************\n");
53 fprintf(stderr, "***** WARNING: ASSERT is undefined, assertions disabled. *****\n");
54 fprintf(stderr, "**************************************************************\n");
55 }
56 #endif
57 if( _AD._syntax_errs + _AD._semantic_errs + _AD._warnings == 0 ) {
58 if (!_AD._quiet_mode)
59 fprintf(stderr,"No errors or warnings to report from phase-1 parse.\n" );
60 }
61 else {
62 if( _AD._syntax_errs ) { // Any syntax errors?
63 fprintf(stderr,"%s: Found %d syntax error", _buf._fp->_name, _AD._syntax_errs);
64 if( _AD._syntax_errs > 1 ) fprintf(stderr,"s.\n\n");
65 else fprintf(stderr,".\n\n");
66 }
67 if( _AD._semantic_errs ) { // Any semantic errors?
68 fprintf(stderr,"%s: Found %d semantic error", _buf._fp->_name, _AD._semantic_errs);
69 if( _AD._semantic_errs > 1 ) fprintf(stderr,"s.\n\n");
70 else fprintf(stderr,".\n\n");
71 }
72 if( _AD._warnings ) { // Any warnings?
73 fprintf(stderr,"%s: Found %d warning", _buf._fp->_name, _AD._warnings);
74 if( _AD._warnings > 1 ) fprintf(stderr,"s.\n\n");
75 else fprintf(stderr,".\n\n");
76 }
77 }
78 if (!_AD._quiet_mode)
79 fprintf(stderr,"-----------------------------------------------------------------------------\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 //
parse()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; 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) { // 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(SYNERR, "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) {
123 parse_err(SEMERR, "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(SYNERR, "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) {
136 parse_err(SEMERR, "Did not declare 'ins_cost' attribute");
137 }
138 if (_globalNames[AttributeForm::_op_cost] == NULL) {
139 parse_err(SEMERR, "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.
instr_parse(void)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 )
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(stderr,"Parsing Instruction Form %s\n", ident);
162
163 // Then get the operands
164 skipws();
165 if (_curchar != '(') {
166 parse_err(SYNERR, "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(SYNERR, "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) {
181 parse_err(SYNERR, "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) {
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)
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(SYNERR, "unique match rule expected for %s\n", rule->_name);
211 return;
212 }
213 assert(match_rules_cnt < 100," too many match rule clones");
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(SYNERR, "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(SYNERR, "Instructions do not specify a constraint\n");
235 }
236 else if (!strcmp(ident, "construct")) {
237 parse_err(SYNERR, "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(SYNERR, "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;
248 if (attr && (attr->_atype == INS_ATTR)) {
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(SYNERR, "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(SYNERR, "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(WARN, "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(WARN, "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) {
286 rule = rule->_next;
287 while (rule != 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(stderr,"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; // 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.
matchrule_clone_and_swap(MatchRule * rule,const char * instr_ident,int & match_rules_cnt)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
adjust_set_rule(InstructForm * instr)319 void ADLParser::adjust_set_rule(InstructForm *instr) {
320 if (instr->_matrule == NULL || instr->_matrule->_rChild == 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;
328 const char *name = NULL;
329 const char *optype = 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;
334 const char *name2 = NULL;
335 const char *optype2 = 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)
339 parse_err(SYNERR, "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) {
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) {
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 || frm->is_operand()->_predicate == 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) {
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) {
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;
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) {
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) {
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-------------------------------------
oper_parse(void)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 )
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(stderr,"Parsing Operand Form %s\n", ident);
425
426 // Get the component operands
427 skipws();
428 if (_curchar != '(') {
429 parse_err(SYNERR, "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(SYNERR, "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) {
443 parse_err(SYNERR, "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(SYNERR, "Operands specify 'encode', not 'ins_encode'\n");
469 }
470 else if (!strcmp(ident, "opcode")) {
471 parse_err(SYNERR, "Operands do not specify an opcode\n");
472 }
473 else if (!strcmp(ident, "effect")) {
474 parse_err(SYNERR, "Operands do not specify an effect\n");
475 }
476 else if (!strcmp(ident, "expand")) {
477 parse_err(SYNERR, "Operands do not specify an expand\n");
478 }
479 else if (!strcmp(ident, "rewrite")) {
480 parse_err(SYNERR, "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) &&
488 (attr->_atype == OP_ATTR)) oper->_attribs = attr_parse(ident);
489 else {
490 parse_err(SYNERR, "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(SYNERR, "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
opclass_parse(void)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 )
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(stderr,"Parsing Operand Class Form %s\n", ident);
520
521 // Get the list of operands
522 skipws();
523 if (_curchar != '(') {
524 parse_err(SYNERR, "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) {
531 parse_err(SYNERR, "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;
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(SYNERR, "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(SYNERR, "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(SYNERR, "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---------------------------------
ins_attr_parse(void)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 )
572 return;
573 // Debugging Stuff
574 if (_AD._adl_debug > 1) fprintf(stderr,"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) {
579 parse_err(SYNERR, "missing '(' in ins_attrib definition\n");
580 return;
581 }
582 // Debug Stuff
583 if (_AD._adl_debug > 1) fprintf(stderr,"Attribute Expression: %s\n", aexpr);
584
585 // Check for terminator
586 if (_curchar != ';') {
587 parse_err(SYNERR, "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_ATTR, aexpr);
594 _globalNames.Insert(ident, attrib); // Add name to the name table
595 _AD.addForm(attrib);
596 }
597
598 //------------------------------op_attr_parse----------------------------------
op_attr_parse(void)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 )
607 return;
608 // Debugging Stuff
609 if (_AD._adl_debug > 1) fprintf(stderr,"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) {
614 parse_err(SYNERR, "missing '(' in op_attrib definition\n");
615 return;
616 }
617 // Debug Stuff
618 if (_AD._adl_debug > 1) fprintf(stderr,"Attribute Expression: %s\n", aexpr);
619
620 // Check for terminator
621 if (_curchar != ';') {
622 parse_err(SYNERR, "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_ATTR, aexpr);
629 _globalNames.Insert(ident, attrib);
630 _AD.addForm(attrib);
631 }
632
633 //------------------------------definitions_parse-----------------------------------
definitions_parse(void)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) {
643 parse_err(SYNERR, "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(SYNERR, "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 //
int_def_parse(void)662 void ADLParser::int_def_parse(void) {
663 char *name = NULL; // Name of definition
664 char *value = NULL; // its value,
665 int int_value = -1; // positive values only
666 char *description = NULL; // textual description
667
668 // Get definition name
669 skipws(); // Skip whitespace
670 name = get_ident();
671 if (name == NULL) {
672 parse_err(SYNERR, "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) {
684 parse_err(SYNERR, "missing value in int_def\n");
685 return;
686 }
687 if( !is_int_token(value, int_value) ) {
688 parse_err(SYNERR, "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) {
699 parse_err(SYNERR, "invalid or missing description in int_def\n");
700 return;
701 }
702 trim(description);
703 }
704
705 if (_curchar != ')') {
706 parse_err(SYNERR, "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(SYNERR, "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(stderr,"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) {
730 parse_err(SYNERR, "Duplicate definition\n");
731 return;
732 }
733
734 return;
735 }
736
737
738 //------------------------------source_parse-----------------------------------
source_parse(void)739 void ADLParser::source_parse(void) {
740 SourceForm *source; // Encode class for instruction/operand
741 char *rule = NULL; // String representation of encode rule
742
743 skipws(); // Skip leading whitespace
744 if ( (rule = find_cpp_block("source block")) == NULL ) {
745 parse_err(SYNERR, "incorrect or missing block for 'source'.\n");
746 return;
747 }
748 // Debug Stuff
749 if (_AD._adl_debug > 1) fprintf(stderr,"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.
source_hpp_parse(void)763 void ADLParser::source_hpp_parse(void) {
764 char *rule = NULL; // String representation of encode rule
765
766 skipws(); // Skip leading whitespace
767 if ( (rule = find_cpp_block("source_hpp block")) == NULL ) {
768 parse_err(SYNERR, "incorrect or missing block for 'source_hpp'.\n");
769 return;
770 }
771 // Debug Stuff
772 if (_AD._adl_debug > 1) fprintf(stderr,"Header Form: %s\n", rule);
773
774 if (_AD.get_registers() == 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--------------------------------------
reg_parse(void)786 void ADLParser::reg_parse(void) {
787 RegisterForm *regBlock = _AD.get_registers(); // Information about registers encoding
788 if (regBlock == 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) {
801 parse_err(SYNERR, "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(SYNERR, "bad token %s inside register block.\n", token); break; }
810 skipws();
811 }
812 }
813 else {
814 parse_err(SYNERR, "Missing %c{ ... %c} block after register keyword.\n",'%','%');
815 return;
816 }
817 }
818
819 //------------------------------encode_parse-----------------------------------
encode_parse(void)820 void ADLParser::encode_parse(void) {
821 EncodeForm *encBlock; // Information about instruction/operand encoding
822
823 _AD.getForm(&encBlock);
824 if ( encBlock == 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) {
837 parse_err(SYNERR, "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(SYNERR, "Missing %c{ ... %c} block after encode keyword.\n",'%','%');
846 return;
847 }
848 }
849
850 //------------------------------enc_class_parse--------------------------------
enc_class_parse(void)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) {
858 parse_err(SYNERR, "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; // parameter type
870 char *pName = 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) {
879 parse_err(SYNERR, "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) {
887 parse_err(SYNERR, "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(SYNERR, "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(SYNERR, "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
enc_class_parse_block(EncClass * encoding,char * ec_name)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(stderr,"EncodingClass Form: %s\n", ec_name);
967 }
968
969 //------------------------------frame_parse-----------------------------------
frame_parse(void)970 void ADLParser::frame_parse(void) {
971 FrameForm *frame; // Information about stack-frame layout
972 char *desc = 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) {
985 parse_err(SYNERR, "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(WARN, "Using obsolete Token, compiler_method_oop_reg");
1002 skipws();
1003 }
1004 if (strcmp(token,"interpreter_method_oop_reg")==0) {
1005 parse_err(WARN, "Using obsolete Token, interpreter_method_oop_reg");
1006 skipws();
1007 }
1008 if (strcmp(token,"interpreter_method_reg")==0) {
1009 parse_err(WARN, "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(WARN, "Using obsolete token, in_preserve_stack_slots");
1023 skipws();
1024 }
1025 if (strcmp(token,"out_preserve_stack_slots")==0) {
1026 parse_err(WARN, "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(WARN, "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(WARN, "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(SYNERR, "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) {
1062 parse_err(SYNERR, "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) {
1071 parse_err(SYNERR, "missing alignment definition in frame section.\n");
1072 return;
1073 }
1074 if(frame->_return_addr == NULL) {
1075 parse_err(SYNERR, "missing return address location in frame section.\n");
1076 return;
1077 }
1078 if(frame->_varargs_C_out_slots_killed == NULL) {
1079 parse_err(SYNERR, "missing varargs C out slots killed definition in frame section.\n");
1080 return;
1081 }
1082 if(frame->_return_value == NULL) {
1083 parse_err(SYNERR, "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) {
1088 frame->_c_frame_pointer = frame->_frame_pointer;
1089 }
1090 if(frame->_c_return_addr == 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) {
1095 frame->_c_return_value = frame->_return_value;
1096 }
1097
1098 // Debug Stuff
1099 if (_AD._adl_debug > 1) fprintf(stderr,"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-------------------------
sync_stack_slots_parse(FrameForm * frame)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----------------------------
frame_pointer_parse(FrameForm * frame,bool native)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----------------------------
interpreter_frame_pointer_parse(FrameForm * frame,bool native)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-----------------------------
inline_cache_parse(FrameForm * frame,bool native)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---------------------
cisc_spilling_operand_name_parse(FrameForm * frame,bool native)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--------------------------
stack_alignment_parse(FrameForm * frame)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-------------------------------
parse_one_arg(const char * description)1143 char *ADLParser::parse_one_arg(const char *description) {
1144 char *token = NULL;
1145 if(_curchar == '(') {
1146 next_char();
1147 skipws();
1148 token = get_expr(description, ")");
1149 if (token == NULL) {
1150 parse_err(SYNERR, "missing value inside %s.\n", description);
1151 return NULL;
1152 }
1153 next_char(); // skip the close paren
1154 if(_curchar != ';') { // check for semi-colon
1155 parse_err(SYNERR, "missing %c in.\n", ';', description);
1156 return NULL;
1157 }
1158 next_char(); // skip the semi-colon
1159 }
1160 else {
1161 parse_err(SYNERR, "Missing %c in.\n", '(', description);
1162 return NULL;
1163 }
1164
1165 trim(token);
1166 return token;
1167 }
1168
1169 //------------------------------return_addr_parse------------------------------
return_addr_parse(FrameForm * frame,bool native)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) {
1177 parse_err(SYNERR, "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(SYNERR, "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) {
1198 parse_err(SYNERR, "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(SYNERR, "missing %c in return address entry.\n", ';');
1207 return;
1208 }
1209 next_char(); // skip the semi-colon
1210 }
1211 else {
1212 parse_err(SYNERR, "Missing %c in return_address entry.\n", '(');
1213 }
1214 }
1215
1216 //------------------------------return_value_parse-----------------------------
return_value_parse()1217 char *ADLParser::return_value_parse() {
1218 char *desc = NULL; // String representation of return_value
1219
1220 skipws(); // Skip leading whitespace
1221 if ( (desc = find_cpp_block("return value block")) == NULL ) {
1222 parse_err(SYNERR, "incorrect or missing block for 'return_value'.\n");
1223 }
1224 return desc;
1225 }
1226
1227 //------------------------------ins_pipe_parse---------------------------------
ins_pipe_parse(InstructForm & instr)1228 void ADLParser::ins_pipe_parse(InstructForm &instr) {
1229 char * ident;
1230
1231 skipws();
1232 if ( _curchar != '(' ) { // Check for delimiter
1233 parse_err(SYNERR, "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) {
1241 parse_err(SYNERR, "keyword identifier expected at %c\n", _curchar);
1242 return;
1243 }
1244
1245 skipws();
1246 if ( _curchar != ')' ) { // Check for delimiter
1247 parse_err(SYNERR, "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(SYNERR, "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(SYNERR, "\"%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-------------------------------------
pipe_parse(void)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(SYNERR, "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) {
1291 parse_err(SYNERR, "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(SYNERR, "expected '%%{'\n");
1302 return;
1303 }
1304 next_char(); skipws();
1305
1306 char *node_class = get_ident();
1307 if (node_class == NULL) {
1308 parse_err(SYNERR, "expected identifier, found \"%c\"\n", _curchar);
1309 return;
1310 }
1311
1312 skipws();
1313 if (_curchar != ',' && _curchar != '=') {
1314 parse_err(SYNERR, "expected `=`, found '%c'\n", _curchar);
1315 break;
1316 }
1317 next_char(); skipws();
1318
1319 char *pipe_class = get_ident();
1320 if (pipe_class == NULL) {
1321 parse_err(SYNERR, "expected identifier, found \"%c\"\n", _curchar);
1322 return;
1323 }
1324 if (_curchar != ';' ) {
1325 parse_err(SYNERR, "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(SYNERR, "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(SYNERR, "\"%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(SYNERR, "expected '%%{'\n");
1358 return;
1359 }
1360 next_char(); skipws();
1361
1362 while (_curchar != '%') {
1363 ident = get_ident();
1364 if (ident == 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(SYNERR, "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(SYNERR, "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(SYNERR, "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(SYNERR, "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(SYNERR, "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(SYNERR, "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(SYNERR, "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) {
1519 parse_err(SYNERR, "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(SYNERR, "unknown specifier \"%s\"\n", ident);
1542 }
1543
1544 if ( (_curchar != '%')
1545 || ( next_char(), (_curchar != '}')) ) {
1546 parse_err(SYNERR, "expected '%%}', found \"%c\"\n", _curchar);
1547 }
1548 next_char(); skipws();
1549
1550 if (pipeline->_maxInstrsPerBundle == 0)
1551 parse_err(SYNERR, "\"max_instructions_per_bundle\" unspecified\n");
1552 if (pipeline->_instrUnitSize == 0 && pipeline->_bundleUnitSize == 0)
1553 parse_err(SYNERR, "\"instruction_unit_size\" and \"bundle_unit_size\" unspecified\n");
1554 if (pipeline->_instrFetchUnitSize == 0)
1555 parse_err(SYNERR, "\"instruction_fetch_unit_size\" unspecified\n");
1556 if (pipeline->_instrFetchUnits == 0)
1557 parse_err(SYNERR, "\"instruction_fetch_units\" unspecified\n");
1558 if (!vsi_seen)
1559 parse_err(SYNERR, "\"variable_size_instruction\" or \"fixed_size_instruction\" unspecified\n");
1560 }
1561 else { // Done with staticly defined parts of instruction definition
1562 parse_err(SYNERR, "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(SYNERR, "missing \"%%}\" in pipeline definition\n");
1573 return;
1574 }
1575
1576 next_char();
1577 }
1578
1579 //------------------------------resource_parse----------------------------
resource_parse(PipelineForm & pipeline)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(SYNERR, "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) {
1600 fprintf(stderr, "resource_parse: identifier: %s\n", ident);
1601 }
1602 }
1603
1604 if (ident == NULL) {
1605 parse_err(SYNERR, "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) {
1617 parse_err(SYNERR, "keyword identifier expected at \"%c\"\n", _curchar);
1618 return;
1619 }
1620 resource = (ResourceForm *) pipeline._resdict[expr];
1621 if (resource == NULL) {
1622 parse_err(SYNERR, "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) {
1633 parse_err(SYNERR, "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) {
1639 parse_err(SYNERR, "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(SYNERR, "\")\" 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----------------------------
pipe_desc_parse(PipelineForm & pipeline)1665 void ADLParser::pipe_desc_parse(PipelineForm &pipeline) {
1666 char * ident;
1667
1668 skipws(); // Skip leading whitespace
1669
1670 if (_curchar != '(') {
1671 parse_err(SYNERR, "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) {
1679 parse_err(SYNERR, "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(SYNERR, "\")\" 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--------------------------
pipe_class_parse(PipelineForm & pipeline)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) {
1715 parse_err(SYNERR, "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(SYNERR, "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(SYNERR, "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) {
1743 parse_err(SYNERR, "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(SYNERR, "missing \"(\" in latency definition\n");
1752 return;
1753 }
1754 next_char(); skipws();
1755 if( !isdigit(_curchar) ) {
1756 parse_err(SYNERR, "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(SYNERR, "missing \")\" in latency definition\n");
1763 return;
1764 }
1765 next_char(); skipws();
1766 if (_curchar != ';') {
1767 parse_err(SYNERR, "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(SYNERR, "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(SYNERR, "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(SYNERR, "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(SYNERR, "\"(\" 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(SYNERR, "\")\" expected at \"%c\"\n", _curchar);
1833 continue;
1834 }
1835
1836 next_char(); skipws();
1837 if (_curchar != ';') {
1838 parse_err(SYNERR, "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(SYNERR, "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(SYNERR, "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(SYNERR, "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(SYNERR, "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) {
1897 oper = parm->is_operand();
1898 if (oper == NULL && !parm->is_opclass()) {
1899 parse_err(SYNERR, "operand name expected at %s\n", ident);
1900 continue;
1901 }
1902
1903 if (_curchar != ':') {
1904 parse_err(SYNERR, "\":\" expected at \"%c\"\n", _curchar);
1905 continue;
1906 }
1907 next_char(); skipws();
1908 stage = get_ident();
1909 if (stage == NULL) {
1910 parse_err(SYNERR, "pipeline stage identifier expected at \"%c\"\n", _curchar);
1911 continue;
1912 }
1913
1914 skipws();
1915 if (_curchar != '(') {
1916 parse_err(SYNERR, "\"(\" expected at \"%c\"\n", _curchar);
1917 continue;
1918 }
1919
1920 next_char();
1921 read_or_write = get_ident();
1922 if (read_or_write == NULL) {
1923 parse_err(SYNERR, "\"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(SYNERR, "\"read\" or \"write\" expected at \"%c\"\n", _curchar);
1931 continue;
1932 }
1933
1934 skipws();
1935 if (_curchar != ')') {
1936 parse_err(SYNERR, "\")\" 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(SYNERR, "<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(SYNERR, "\";\" 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) {
1973 int cyclecnt = 1;
1974 if (_curchar != ':') {
1975 parse_err(SYNERR, "\":\" expected at \"%c\"\n", _curchar);
1976 continue;
1977 }
1978 next_char(); skipws();
1979 stage = get_ident();
1980 if (stage == NULL) {
1981 parse_err(SYNERR, "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(SYNERR, "\")\" 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(SYNERR, "\";\" expected at \"%c\"\n", _curchar);
2010 continue;
2011 }
2012 next_char(); skipws();
2013 continue;
2014 }
2015
2016 parse_err(SYNERR, "resource expected at \"%s\"\n", ident);
2017 return;
2018 } while(_curchar != '%');
2019
2020 next_char();
2021 if (_curchar != '}') {
2022 parse_err(SYNERR, "missing \"%%}\" in pipe_class definition\n");
2023 return;
2024 }
2025
2026 next_char();
2027 }
2028
2029 //------------------------------peep_parse-------------------------------------
peep_parse(void)2030 void ADLParser::peep_parse(void) {
2031 Peephole *peep; // Pointer to current peephole rule form
2032 char *desc = 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) {
2045 parse_err(SYNERR, "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(SYNERR, "expected peepmatch, peepconstraint, or peepreplace for identifier %s.\n", token);
2057 }
2058 skipws();
2059 }
2060 }
2061 else {
2062 parse_err(SYNERR, "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------------------------------
constraint_parse(void)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(SYNERR, "missing constraint expression, (...)\n");
2079 return NULL;
2080 }
2081 next_char(); // Skip past '('
2082
2083 // Get constraint function
2084 skipws();
2085 func = get_ident();
2086 if (func == NULL) {
2087 parse_err(SYNERR, "missing function in constraint expression.\n");
2088 return 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(SYNERR, "missing '(' for constraint function's argument.\n");
2096 return NULL;
2097 }
2098 next_char();
2099
2100 // Get it's argument
2101 skipws();
2102 arg = get_ident();
2103 if (arg == NULL) {
2104 parse_err(SYNERR, "missing argument for constraint function %s\n",func);
2105 return NULL;
2106 }
2107 // Check for ')' after argument
2108 skipws();
2109 if (_curchar != ')') {
2110 parse_err(SYNERR, "missing ')' after constraint function argument %s\n",arg);
2111 return NULL;
2112 }
2113 next_char();
2114 } else {
2115 parse_err(SYNERR, "Invalid constraint function %s\n",func);
2116 return NULL;
2117 }
2118
2119 // Check for closing paren and ';'
2120 skipws();
2121 if (_curchar != ')') {
2122 parse_err(SYNERR, "Missing ')' for constraint function %s\n",func);
2123 return NULL;
2124 }
2125 next_char();
2126 skipws();
2127 if (_curchar != ';') {
2128 parse_err(SYNERR, "Missing ';' after constraint.\n");
2129 return 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-----------------------------------
construct_parse(void)2139 ConstructRule *ADLParser::construct_parse(void) {
2140 return NULL;
2141 }
2142
2143
2144 //------------------------------reg_def_parse----------------------------------
reg_def_parse(void)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) {
2152 parse_err(SYNERR, "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;
2160 char *c_conv = NULL;
2161 char *idealtype = NULL;
2162 char *encoding = NULL;
2163 char *concrete = 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) {
2169 parse_err(SYNERR, "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(SYNERR, "invalid value for register calling convention\n");
2175 }
2176 skipws();
2177 if (_curchar != ',') {
2178 parse_err(SYNERR, "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) {
2186 parse_err(SYNERR, "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(SYNERR, "invalid value for register calling convention\n");
2192 }
2193 skipws();
2194 if (_curchar != ',') {
2195 parse_err(SYNERR, "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) {
2204 parse_err(SYNERR, "missing register save type value\n");
2205 return;
2206 }
2207 skipws();
2208 if (_curchar != ',') {
2209 parse_err(SYNERR, "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) {
2218 parse_err(SYNERR, "missing register encoding value\n");
2219 return;
2220 }
2221 trim(encoding);
2222 if (_curchar != ',') {
2223 parse_err(SYNERR, "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) {
2232 parse_err(SYNERR, "missing vm register name value\n");
2233 return;
2234 }
2235
2236 if (_curchar != ')') {
2237 parse_err(SYNERR, "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(SYNERR, "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(stderr,"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--------------------------------
reg_class_parse(void)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) {
2270 parse_err(SYNERR, "missing register class name after 'reg_class'\n");
2271 return;
2272 }
2273 // Debug Stuff
2274 if (_AD._adl_debug >1) fprintf(stderr,"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) {
2287 parse_err(SYNERR, "missing identifier inside reg_class list.\n");
2288 return;
2289 }
2290 RegDef *regDef = _AD._register->getRegDef(rname);
2291 if (!regDef) {
2292 parse_err(SEMERR, "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) {
2311 parse_err(SYNERR, "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(SYNERR, "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------------------------
reg_class_dynamic_parse(void)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) {
2339 parse_err(SYNERR, "missing dynamic register class name after 'reg_class_dynamic'\n");
2340 return;
2341 }
2342
2343 if (_AD._adl_debug > 1) {
2344 fprintf(stdout, "Dynamic Register Class: %s\n", cname);
2345 }
2346
2347 skipws();
2348 if (_curchar != '(') {
2349 parse_err(SYNERR, "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) {
2362 parse_err(SYNERR, "missing class identifier inside reg_class_dynamic list.\n");
2363 return;
2364 }
2365 RegClass* rc = _AD._register->getRegClass(name);
2366 if (rc == NULL) {
2367 parse_err(SEMERR, "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(SYNERR, "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) {
2386 parse_err(SYNERR, "missing code declaration for reg_class_dynamic.\n");
2387 return;
2388 }
2389 reg_class->set_condition_code(code);
2390 } else {
2391 parse_err(SYNERR, "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(SYNERR, "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(SYNERR, "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------------------------------
alloc_class_parse(void)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) {
2420 parse_err(SYNERR, "missing allocation class name after 'reg_class'\n");
2421 return;
2422 }
2423 // Debug Stuff
2424 if (_AD._adl_debug >1) fprintf(stderr,"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) {
2436 parse_err(SYNERR, "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(SYNERR, "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(SYNERR, "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-------------------------
peep_match_child_parse(PeepMatch & match,int parent,int & position,int input)2472 InstructForm *ADLParser::peep_match_child_parse(PeepMatch &match, int parent, int &position, int input){
2473 char *token = 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;
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 ')'");
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) {
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 ) {
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(SYNERR, "instruction name expected at identifier %s.\n",
2520 token);
2521 return inst_seen;
2522 }
2523 }
2524 else {
2525 parse_err(SYNERR, "missing identifier in peepmatch rule.\n");
2526 return NULL;
2527 }
2528 }
2529 else {
2530 parse_err(SYNERR, "missing identifier in peepmatch rule.\n");
2531 return NULL;
2532 }
2533
2534 } // end while
2535
2536 assert( false, "ShouldNotReachHere();");
2537 return NULL;
2538 }
2539
2540 //------------------------------peep_match_parse-------------------------------
2541 // Syntax for a peepmatch rule
2542 //
2543 // peepmatch ( root_instr_name [(instruction subtree)] [,(instruction subtree)]* );
2544 //
peep_match_parse(Peephole & peep)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(SYNERR, "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 ) {
2563 parse_err(SYNERR, "missing instruction-name at start of peepmatch.\n");
2564 return;
2565 }
2566
2567 if( _curchar != ')' ) {
2568 parse_err(SYNERR, "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(SYNERR, "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 //
peep_constraint_parse(Peephole & peep)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(SYNERR, "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(SYNERR, "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(SYNERR, "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(SYNERR, "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(SYNERR, "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 //
peep_replace_parse(Peephole & peep)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;
2691 char *token = NULL;
2692
2693 skipws();
2694 // Check for open paren
2695 if (_curchar != '(') {
2696 parse_err(SYNERR, "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 || form->is_instruction() == NULL ) {
2708 parse_err(SYNERR, "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(SYNERR, "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(SYNERR, "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 ) {
2742 parse_err(SYNERR, "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 ')'.");
2754 next_char(); // Skip ')'
2755
2756 skipws();
2757 // Check for end of peepreplace
2758 if( _curchar != ')' ) {
2759 parse_err(SYNERR, "missing ')' at end of peepmatch.\n");
2760 parse_err(SYNERR, "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(SYNERR, "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-------------------------------------
pred_parse(void)2778 Predicate *ADLParser::pred_parse(void) {
2779 Predicate *predicate; // Predicate class for operand
2780 char *rule = NULL; // String representation of predicate
2781
2782 skipws(); // Skip leading whitespace
2783 int line = linenum();
2784 if ( (rule = get_paren_expr("pred expression", true)) == NULL ) {
2785 parse_err(SYNERR, "incorrect or missing expression for 'predicate'\n");
2786 return NULL;
2787 }
2788 // Debug Stuff
2789 if (_AD._adl_debug > 1) fprintf(stderr,"Predicate: %s\n", rule);
2790 if (_curchar != ';') {
2791 parse_err(SYNERR, "missing ';' in predicate definition\n");
2792 return 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
ins_encode_parse_block(InstructForm & inst)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");
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;
2818 inst._parameters.reset();
2819 while ((param = inst._parameters.iter()) != NULL) {
2820 OpClassForm* opForm = inst._localNames[param]->is_opclass();
2821 assert(opForm != NULL, "sanity");
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) {
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) {
2848 parse_err(SYNERR, "Multiple ins_encode sections defined\n");
2849 return;
2850 }
2851
2852 // Set encode class of this instruction.
2853 inst._insencode = encrule;
2854 }
2855
2856
ins_encode_parse_block_impl(InstructForm & inst,EncClass * encoding,char * ec_name)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(SYNERR, "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(stderr, "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.
ins_encode_parse(InstructForm & inst)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(SYNERR, "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; // String representation of encode rule
2981 // identifier is optional.
2982 while (_curchar != ')') {
2983 ec_name = get_ident();
2984 if (ec_name == NULL) {
2985 parse_err(SYNERR, "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) {
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 ) {
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(SYNERR, "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) &&
3029 !ADLParser::is_literal_constant(param) &&
3030 (Opcode::as_opcode_type(param) == Opcode::NOT_AN_OPCODE) &&
3031 ((_AD._register == NULL ) || (_AD._register->getRegDef(param) == NULL)) ) {
3032 parse_err(SYNERR, "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(SYNERR, "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(SYNERR, "Expected encode parameter before ',' in encoding %s.\n", ec_name);
3059 return;
3060 }
3061 if (_curchar != ')') {
3062 parse_err(SYNERR, "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(SYNERR, "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(SYNERR, "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(SYNERR, "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) {
3107 parse_err(SYNERR, "Multiple ins_encode sections defined\n");
3108 return;
3109 }
3110
3111 // Debug Stuff
3112 if (_AD._adl_debug > 1) fprintf(stderr,"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.
postalloc_expand_parse(InstructForm & inst)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(SYNERR, "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; // String representation of encode rule.
3151 // identifier is optional.
3152 if (_curchar != ')') {
3153 ec_name = get_ident();
3154 if (ec_name == NULL) {
3155 parse_err(SYNERR, "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) {
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(SYNERR, "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) &&
3206 !ADLParser::is_literal_constant(param) &&
3207 (Opcode::as_opcode_type(param) == Opcode::NOT_AN_OPCODE) &&
3208 ((_AD._register == NULL) || (_AD._register->getRegDef(param) == NULL))) {
3209 parse_err(SYNERR, "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(SYNERR, "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(SYNERR, "Expected encode parameter before ',' in postalloc_expand %s.\n", ec_name);
3232 return;
3233 }
3234 if (_curchar != ')') {
3235 parse_err(SYNERR, "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(SYNERR, "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(SYNERR, "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(SYNERR, "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(stderr, "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.
constant_parse(InstructForm & inst)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");
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;
3289 inst._parameters.reset();
3290 while ((param = inst._parameters.iter()) != NULL) {
3291 OpClassForm* opForm = inst._localNames[param]->is_opclass();
3292 assert(opForm != NULL, "sanity");
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) {
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----------------------
constant_parse_expression(EncClass * encoding,char * ec_name)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(stderr, "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.
size_parse(InstructForm * instr)3384 char* ADLParser::size_parse(InstructForm *instr) {
3385 char* sizeOfInstr = 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) {
3393 parse_err(SYNERR, "size of opcode expected at %c\n", _curchar);
3394 return NULL;
3395 }
3396
3397 skipws();
3398
3399 // Check for terminator
3400 if (_curchar != ';') {
3401 parse_err(SYNERR, "missing ';' in ins_attrib definition\n");
3402 return 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) {
3410 fprintf(stderr,"size of opcode: %s\n", sizeOfInstr);
3411 }
3412 }
3413
3414 return sizeOfInstr;
3415 }
3416
3417
3418 //------------------------------opcode_parse-----------------------------------
opcode_parse(InstructForm * instr)3419 Opcode * ADLParser::opcode_parse(InstructForm *instr) {
3420 char *primary = NULL;
3421 char *secondary = NULL;
3422 char *tertiary = NULL;
3423
3424 char *val = NULL;
3425 Opcode *opcode = NULL;
3426
3427 // Get value of the instruction's opcode
3428 skipws();
3429 if (_curchar != '(') { // Check for parenthesized operand list
3430 parse_err(SYNERR, "missing '(' in expand instruction declaration\n");
3431 return 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 ) {
3438 parse_err(SYNERR, "primary hex opcode expected at %c\n", _curchar);
3439 return 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 ) {
3447 parse_err(SYNERR, "secondary hex opcode expected at %c\n", _curchar);
3448 return 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 ) {
3456 parse_err(SYNERR,"tertiary hex opcode expected at %c\n", _curchar);
3457 return NULL;
3458 }
3459 skipws();
3460 }
3461 }
3462 skipws();
3463 if (_curchar != ')') {
3464 parse_err(SYNERR, "Missing ')' in opcode description\n");
3465 return NULL;
3466 }
3467 }
3468 next_char(); // Skip ')'
3469 skipws();
3470 // Check for terminator
3471 if (_curchar != ';') {
3472 parse_err(SYNERR, "missing ';' in ins_attrib definition\n");
3473 return 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) fprintf(stderr,"primary opcode: %s\n", primary);
3481 if (secondary != NULL) fprintf(stderr,"secondary opcode: %s\n", secondary);
3482 if (tertiary != NULL) fprintf(stderr,"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--------------------------------
interface_parse(void)3492 Interface *ADLParser::interface_parse(void) {
3493 char *iface_name = NULL; // Name of interface class being used
3494 char *iface_code = NULL; // Describe components of this class
3495
3496 // Get interface class name
3497 skipws(); // Skip whitespace
3498 if (_curchar != '(') {
3499 parse_err(SYNERR, "Missing '(' at start of interface description.\n");
3500 return NULL;
3501 }
3502 next_char(); // move past '('
3503 skipws();
3504 iface_name = get_ident();
3505 if (iface_name == NULL) {
3506 parse_err(SYNERR, "missing interface name after 'interface'.\n");
3507 return NULL;
3508 }
3509 skipws();
3510 if (_curchar != ')') {
3511 parse_err(SYNERR, "Missing ')' after name of interface.\n");
3512 return 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;
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(SYNERR, "Extra ';' after defining interface block.\n");
3532 next_char(); // Skip ';'
3533 return 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(stderr,"Interface Form: %s\n", iface_name);
3549
3550 // Create appropriate interface object and return.
3551 return inter;
3552 }
3553
3554
3555 //------------------------------mem_interface_parse----------------------------
mem_interface_parse(void)3556 Interface *ADLParser::mem_interface_parse(void) {
3557 // Fields for MemInterface
3558 char *base = NULL;
3559 char *index = NULL;
3560 char *scale = NULL;
3561 char *disp = NULL;
3562
3563 if (_curchar != '%') {
3564 parse_err(SYNERR, "Missing '%%{' for 'interface' block.\n");
3565 return NULL;
3566 }
3567 next_char(); // Skip '%'
3568 if (_curchar != '{') {
3569 parse_err(SYNERR, "Missing '%%{' for 'interface' block.\n");
3570 return NULL;
3571 }
3572 next_char(); // Skip '{'
3573 skipws();
3574 do {
3575 char *field = get_ident();
3576 if (field == NULL) {
3577 parse_err(SYNERR, "Expected keyword, base|index|scale|disp, or '%%}' ending interface.\n");
3578 return 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(SYNERR, "Expected keyword, base|index|scale|disp, or '%%}' ending interface.\n");
3594 return NULL;
3595 }
3596 } while( _curchar != '%' );
3597 next_char(); // Skip '%'
3598 if ( _curchar != '}' ) {
3599 parse_err(SYNERR, "Missing '%%}' for 'interface' block.\n");
3600 return 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---------------------------
cond_interface_parse(void)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(SYNERR, "Missing '%%{' for 'cond_interface' block.\n");
3631 return NULL;
3632 }
3633 next_char(); // Skip '%'
3634 if (_curchar != '{') {
3635 parse_err(SYNERR, "Missing '%%{' for 'cond_interface' block.\n");
3636 return NULL;
3637 }
3638 next_char(); // Skip '{'
3639 skipws();
3640 do {
3641 char *field = get_ident();
3642 if (field == NULL) {
3643 parse_err(SYNERR, "Expected keyword, base|index|scale|disp, or '%%}' ending interface.\n");
3644 return 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(SYNERR, "Expected keyword, base|index|scale|disp, or '%%}' ending interface.\n");
3672 return NULL;
3673 }
3674 } while( _curchar != '%' );
3675 next_char(); // Skip '%'
3676 if ( _curchar != '}' ) {
3677 parse_err(SYNERR, "Missing '%%}' for 'interface' block.\n");
3678 return 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--------------------------
interface_field_parse(const char ** format)3696 char *ADLParser::interface_field_parse(const char ** format) {
3697 char *iface_field = NULL;
3698
3699 // Get interface field
3700 skipws(); // Skip whitespace
3701 if (_curchar != '(') {
3702 parse_err(SYNERR, "Missing '(' at start of interface field.\n");
3703 return NULL;
3704 }
3705 next_char(); // move past '('
3706 skipws();
3707 if ( _curchar != '0' && _curchar != '$' ) {
3708 parse_err(SYNERR, "missing or invalid interface field contents.\n");
3709 return NULL;
3710 }
3711 iface_field = get_rep_var_ident();
3712 if (iface_field == NULL) {
3713 parse_err(SYNERR, "missing or invalid interface field contents.\n");
3714 return NULL;
3715 }
3716 skipws();
3717 if (format != NULL && _curchar == ',') {
3718 next_char();
3719 skipws();
3720 if (_curchar != '"') {
3721 parse_err(SYNERR, "Missing '\"' in field format .\n");
3722 return 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(SYNERR, "newline in string"); // unimplemented!
3729 next_char();
3730 }
3731 if (_curchar != '"') {
3732 parse_err(SYNERR, "Missing '\"' at end of field format .\n");
3733 return 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(SYNERR, "Missing ')' after interface field.\n");
3745 return NULL;
3746 }
3747 next_char(); // move past ')'
3748 skipws();
3749 if ( _curchar != ';' ) {
3750 parse_err(SYNERR, "Missing ';' at end of interface field.\n");
3751 return 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------------------------------------
match_parse(FormDict & operands)3761 MatchRule *ADLParser::match_parse(FormDict &operands) {
3762 MatchRule *match; // Match Rule class for instruction/operand
3763 char *cnstr = 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; // 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 ) {
3777 parse_err(SYNERR, "invalid construction of match rule\n"
3778 "Missing ';' or invalid '%%{' and '%%}' constructor\n");
3779 return NULL; // No MatchRule to return
3780 }
3781 if (_AD._adl_debug > 1)
3782 if (cnstr) fprintf(stderr,"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-----------------------------------
format_parse(void)3790 FormatRule* ADLParser::format_parse(void) {
3791 char *desc = 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; // 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(SYNERR, "Unknown \"%s\" directive in format", ident);
3809 return 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(SYNERR, "missing '\"' at end of format block");
3827 return 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(SYNERR, "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(SYNERR, "non-blank characters between closing '\"' and '%%' in format");
3882 return NULL;
3883 }
3884 } // Done with format description inside
3885
3886 skipws();
3887 // Past format description, at '%'
3888 if ( _curchar != '%' || *(_ptr+1) != '}' ) {
3889 parse_err(SYNERR, "missing '%%}' at end of format block");
3890 return 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(SYNERR, "missing ';' after Format expression");
3897 return NULL;
3898 }
3899 // Debug Stuff
3900 if (_AD._adl_debug > 1) fprintf(stderr,"Format Rule: %s\n", desc);
3901
3902 skipws();
3903 return format;
3904 }
3905
3906
3907 //------------------------------template_parse-----------------------------------
template_parse(void)3908 FormatRule* ADLParser::template_parse(void) {
3909 char *desc = 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(SYNERR, "missing '\"' at end of format block");
3963 return 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(SYNERR, "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(SYNERR, "missing '%%}' at end of format block");
4021 return 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(stderr,"Format Rule: %s\n", desc);
4028
4029 skipws();
4030 return format;
4031 }
4032
4033
4034 //------------------------------effect_parse-----------------------------------
effect_parse(InstructForm * instr)4035 void ADLParser::effect_parse(InstructForm *instr) {
4036 char* desc = NULL;
4037
4038 skipws(); // Skip whitespace
4039 if (_curchar != '(') {
4040 parse_err(SYNERR, "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(stderr,"Effect description: %s\n", desc);
4048 if (_curchar != ';') {
4049 parse_err(SYNERR, "missing ';' in Effect definition\n");
4050 }
4051 next_char(); // Skip ';'
4052
4053 }
4054
4055 //------------------------------expand_parse-----------------------------------
expand_parse(InstructForm * instr)4056 ExpandRule* ADLParser::expand_parse(InstructForm *instr) {
4057 char *ident, *ident2;
4058 NameAndList *instr_and_operands = 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(SYNERR, "missing '%%{' in expand definition\n");
4068 return(NULL);
4069 }
4070 next_char(); // Maintain the invariant
4071 do {
4072 ident = get_ident(); // Grab next identifier
4073 if (ident == NULL) {
4074 parse_err(SYNERR, "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) {
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(SYNERR, "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) {
4101 parse_err(SYNERR, "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) {
4108 parse_err(SYNERR, "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;
4116 skipws();
4117 if (_curchar == '%') { // Need a constructor for the operand
4118 c = find_cpp_block("Operand Constructor");
4119 if (c == NULL) {
4120 parse_err(SYNERR, "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(SYNERR, "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");
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(SYNERR, "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) {
4150 parse_err(SYNERR, "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(SYNERR, "operand name expected at %s\n", ident2);
4156 continue;
4157 }
4158 OperandForm *oper = form2->is_operand();
4159 if (oper == NULL && !form2->is_opclass()) {
4160 parse_err(SYNERR, "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(SYNERR, "missing ')'in expand instruction declaration\n");
4167 continue;
4168 }
4169 next_char();
4170 if (_curchar != ';') {
4171 parse_err(SYNERR, "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(SYNERR, "missing '%%}' in expand rule definition\n");
4186 return(NULL);
4187 }
4188 next_char();
4189
4190 // Debug Stuff
4191 if (_AD._adl_debug > 1) fprintf(stderr,"Expand Rule:\n");
4192
4193 skipws();
4194 return (exp);
4195 }
4196
4197 //------------------------------rewrite_parse----------------------------------
rewrite_parse(void)4198 RewriteRule* ADLParser::rewrite_parse(void) {
4199 char* params = NULL;
4200 char* desc = 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) {
4208 parse_err(SYNERR, "missing '(' in rewrite rule\n");
4209 return NULL;
4210 }
4211 // Debug Stuff
4212 if (_AD._adl_debug > 1) fprintf(stderr,"Rewrite parameters: %s\n", params);
4213
4214 // For now, grab entire block;
4215 skipws();
4216 if ( (desc = find_cpp_block("rewrite block")) == NULL ) {
4217 parse_err(SYNERR, "incorrect or missing block for 'rewrite'.\n");
4218 return NULL;
4219 }
4220 // Debug Stuff
4221 if (_AD._adl_debug > 1) fprintf(stderr,"Rewrite Rule: %s\n", desc);
4222
4223 skipws();
4224 return (new RewriteRule(params,desc));
4225 }
4226
4227 //------------------------------attr_parse-------------------------------------
attr_parse(char * ident)4228 Attribute *ADLParser::attr_parse(char* ident) {
4229 Attribute *attrib; // Attribute class
4230 char *cost = NULL; // String representation of cost attribute
4231
4232 skipws(); // Skip leading whitespace
4233 if ( (cost = get_paren_expr("attribute")) == NULL ) {
4234 parse_err(SYNERR, "incorrect or missing expression for 'attribute'\n");
4235 return NULL;
4236 }
4237 // Debug Stuff
4238 if (_AD._adl_debug > 1) fprintf(stderr,"Attribute: %s\n", cost);
4239 if (_curchar != ';') {
4240 parse_err(SYNERR, "missing ';' in attribute definition\n");
4241 return NULL;
4242 }
4243 next_char(); // Point after the terminator
4244
4245 skipws();
4246 attrib = new Attribute(ident,cost,INS_ATTR); // Build new predicate object
4247 return attrib;
4248 }
4249
4250
4251 //------------------------------matchNode_parse--------------------------------
matchNode_parse(FormDict & operands,int & depth,int & numleaves,bool atroot)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;
4259 MatchNode *rChild = 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;
4265
4266 next_char(); // advance past '('
4267
4268 // Parse the opcode
4269 token = get_ident(); // Get identifier, opcode
4270 if (token == NULL) {
4271 parse_err(SYNERR, "missing opcode in match expression\n");
4272 return 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; // 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;
4292 if (opcForm != 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;
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(SYNERR, "missing ')' in match expression\n");
4325 return 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-------------------------------
matchChild_parse(FormDict & operands,int & parens,int & numleaves,bool atroot)4343 MatchNode *ADLParser::matchChild_parse(FormDict &operands, int &parens, int &numleaves, bool atroot) {
4344 MatchNode *child = NULL;
4345 const char *result = NULL;
4346 const char *token = NULL;
4347 const char *opType = 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;
4357 if (opcForm != NULL) {
4358 opType = opcForm->_ident;
4359 result = opcForm->_ident; // an operand's result matches its type
4360 } else {
4361 parse_err(SYNERR, "undefined operand %s in match rule\n", token);
4362 return NULL;
4363 }
4364
4365 if (opType == NULL) {
4366 parse_err(SYNERR, "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
find_cpp_block(const char * description)4381 char* ADLParser::find_cpp_block(const char* description) {
4382 char *next; // Pointer for finding block delimiters
4383 char* cppBlock = NULL; // Beginning of C++ code block
4384
4385 if (_curchar == '%') { // Encoding is a C++ expression
4386 next_char();
4387 if (_curchar != '{') {
4388 parse_err(SYNERR, "missing '{' in %s \n", description);
4389 return 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(SYNERR, "invalid termination of %s \n", description);
4402 return 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.
get_expr(const char * desc,const char * stop_chars)4426 char* ADLParser::get_expr(const char *desc, const char *stop_chars) {
4427 char* expr = 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(SYNERR, "too many )'s, did not find %s after %s\n",
4440 stop_chars, desc);
4441 return 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(SYNERR, "newline in string in %s\n", desc);
4454 return 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(SYNERR, "unexpected %%%c in %s\n", _ptr[1], desc);
4461 return NULL;
4462 }
4463 else if (_curchar == '\0') {
4464 parse_err(SYNERR, "unexpected EOF in %s\n", desc);
4465 return 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(SYNERR, "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");
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 ')'
get_paren_expr(const char * description,bool include_location)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;
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.
get_ident_common(bool do_preproc)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 ) // Return NULL at EOF.
4521 return 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(SYNERR, "Identifier expected, but found '%s'.", buf);
4541 } else {
4542 parse_err(SYNERR, "Identifier expected, but found '%s'.", start);
4543 }
4544 start = 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) {
4555 const char* def = _AD.get_preproc_def(start);
4556 if (def != 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 && strcmp(def2, def1)) {
4561 def = def2;
4562 const char* def3 = _AD.get_preproc_def(def2);
4563 if (def3 != NULL && strcmp(def3, def2) && strcmp(def3, def1)) {
4564 parse_err(SYNERR, "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.
get_ident_dup(void)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 ) {
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.
get_ident_or_literal_constant(const char * description)4592 char *ADLParser::get_ident_or_literal_constant(const char* description) {
4593 char* param = 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),
4604 "expr must be recognizable as a constant");
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
get_rep_var_ident(void)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(SYNERR, "Replacement variables and field specifiers can not start with '$$$$'");
4636 next_char();
4637 return NULL;
4638 }
4639
4640 // Nil terminate the variable name following the '$'
4641 char *rep_var_name = get_ident();
4642 assert( rep_var_name != NULL,
4643 "Missing identifier after replacement variable indicator '$'");
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
get_rep_var_ident_dup(void)4655 char *ADLParser::get_rep_var_ident_dup(void) {
4656 if( _curchar != '$' ) return 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(SYNERR, "Replacement variables and field specifiers can not start with '$$$$'");
4674 next_char();
4675 return NULL;
4676 }
4677
4678 // Nil terminate the variable name following the '$'
4679 char *rep_var_name = get_ident();
4680 assert( rep_var_name != NULL,
4681 "Missing identifier after replacement variable indicator '$'");
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
get_unique_ident(FormDict & dict,const char * nameDescription)4692 char *ADLParser::get_unique_ident(FormDict& dict, const char* nameDescription){
4693 char* ident = get_ident();
4694
4695 if (ident == NULL) {
4696 parse_err(SYNERR, "missing %s identifier at %c\n", nameDescription, _curchar);
4697 }
4698 else {
4699 if (dict[ident] != NULL) {
4700 parse_err(SYNERR, "duplicate name %s for %s\n", ident, nameDescription);
4701 ident = 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.
get_int(void)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 ) // 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(SYNERR, "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.
get_relation_dup(void)4751 char *ADLParser::get_relation_dup(void) {
4752 char *result = NULL; // relational operator being returned
4753
4754 if( _curline == NULL ) // Return NULL at EOF.
4755 return 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(SYNERR, "relational operator expected at %s\n", _ptr);
4771 }
4772 } else {
4773 parse_err(SYNERR, "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.
get_oplist(NameList & parameters,FormDict & operands)4785 void ADLParser::get_oplist(NameList ¶meters, FormDict &operands) {
4786 OpClassForm *opclass = NULL;
4787 char *ident = 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) {
4797 parse_err(SYNERR, "optype identifier expected at %c\n", _curchar);
4798 return;
4799 }
4800 else {
4801 const Form *form = _globalNames[ident];
4802 if( form == NULL ) {
4803 parse_err(SYNERR, "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) && (opc == NULL)) {
4811 parse_err(SYNERR, "identifier %s not operand type\n", ident);
4812 return;
4813 }
4814 opclass = opc;
4815 }
4816 // Debugging Stuff
4817 if (_AD._adl_debug > 1) fprintf(stderr, "\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) {
4821 return;
4822 }
4823 // Parameter names must not be global names.
4824 if( _globalNames[ident] != NULL ) {
4825 parse_err(SYNERR, "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(stderr, "\tOperand Name: %s\n", ident);
4833 skipws();
4834 } while(_curchar == ',');
4835
4836 if (_curchar != ')') parse_err(SYNERR, "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.
get_effectlist(FormDict & effects,FormDict & operands,bool & has_call)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) {
4861 parse_err(SYNERR, "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 ) {
4868 parse_err(SYNERR, "undefined effect type %s\n", ident);
4869 return;
4870 }
4871 else {
4872 if( (eForm = form->is_effect()) == NULL) {
4873 parse_err(SYNERR, "identifier %s not effect type\n", ident);
4874 return;
4875 }
4876 }
4877 }
4878 // Debugging Stuff
4879 if (_AD._adl_debug > 1) fprintf(stderr, "\tEffect Type: %s\t", ident);
4880 skipws();
4881 if (eForm->is(Component::CALL)) {
4882 if (_AD._adl_debug > 1) fprintf(stderr, "\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) {
4887 parse_err(SYNERR, "missing operand identifier in effect list\n");
4888 return;
4889 }
4890 const Form *form = operands[ident];
4891 opForm = form ? form->is_operand() : NULL;
4892 if( opForm == NULL ) {
4893 if( form && form->is_opclass() ) {
4894 const char* cname = form->is_opclass()->_ident;
4895 parse_err(SYNERR, "operand classes are illegal in effect lists (found %s %s)\n", cname, ident);
4896 } else {
4897 parse_err(SYNERR, "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(stderr, "\tOperand Name: %s\n", ident);
4905 }
4906 skipws();
4907 } while(_curchar == ',');
4908
4909 if (_curchar != ')') parse_err(SYNERR, "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.
preproc_line(void)4918 void ADLParser::preproc_line(void) {
4919 int line = get_int();
4920 skipws_no_preproc();
4921 const char* file = NULL;
4922 if (_curchar == '"') {
4923 next_char(); // Move past the initial '"'
4924 file = _ptr;
4925 while (true) {
4926 if (_curchar == '\n') {
4927 parse_err(SYNERR, "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)
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.
preproc_define(void)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(SYNERR, "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.
preproc_undef(void)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);
4966 }
4967
4968
4969
4970 //------------------------------parse_err--------------------------------------
4971 // Issue a parser error message, and skip to the end of the current line
parse_err(int flag,const char * fmt,...)4972 void ADLParser::parse_err(int flag, const char *fmt, ...) {
4973 va_list args;
4974
4975 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);
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(stderr, "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.
ensure_start_of_line(void)5007 void ADLParser::ensure_start_of_line(void) {
5008 if (_curchar == '\n') { next_line(); return; }
5009 assert( _ptr >= _curline && _ptr < _curline+strlen(_curline),
5010 "Must be able to find which line we are in" );
5011
5012 for (char *s = _curline; s < _ptr; s++) {
5013 if (*s > ' ') {
5014 parse_err(SYNERR, "'%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.
ensure_end_of_line(void)5024 void ADLParser::ensure_end_of_line(void) {
5025 skipws_no_preproc();
5026 if (_curchar != '\n' && _curchar != '\0') {
5027 parse_err(SYNERR, "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.
handle_preproc_token()5050 bool ADLParser::handle_preproc_token() {
5051 assert(*_ptr == '#', "must be at start of preproc");
5052 ensure_start_of_line();
5053 next_char();
5054 skipws_no_preproc();
5055 char* start_ident = _ptr;
5056 char* ident = (_curchar == '\n') ? NULL : get_ident_no_preproc();
5057 if (ident == NULL) {
5058 parse_err(SYNERR, "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);
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(SYNERR, "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(SYNERR, "no space allowed after # in #define or #undef");
5085 assert(_curchar == '#', "no space allowed after # in #define or #undef");
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
skipws_common(bool do_preproc)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(SYNERR, "unimplemented: comment token in a funny place");
5111 }
5112 }
5113 while(_curline != 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) { // check for end of file
5128 parse_err(SYNERR, "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");
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(SYNERR, "newline in string");
5159 break;
5160 }
5161 }
5162 next = _ptr + 1;
5163 }
5164 else { ++_ptr; ++next; }
5165 }
5166 if( _curline != NULL ) // at end of file _curchar isn't valid
5167 _curchar = *_ptr; // reset _curchar to maintain invariant
5168 }
5169
5170 //---------------------------cur_char-----------------------------------------
cur_char()5171 char ADLParser::cur_char() {
5172 return (_curchar);
5173 }
5174
5175 //---------------------------next_char-----------------------------------------
next_char()5176 void ADLParser::next_char() {
5177 if (_curchar == '\n') parse_err(WARN, "must call next_line!");
5178 _curchar = *++_ptr;
5179 // if ( _curchar == '\n' ) {
5180 // next_line();
5181 // }
5182 }
5183
5184 //---------------------------next_char_or_line---------------------------------
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-----------------------------------------
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).
get_line_string(int linenum)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---------------------------------
is_literal_constant(const char * param)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--------------------------------------
is_hex_digit(char 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--------------------------------------
is_int_token(const char * token,int & intval)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
skip_expr_ws(const char * str)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");
5259 const char* eol = strchr(cp, '\n');
5260 assert(eol != NULL, "must find end of line");
5261 if (eol == NULL) eol = cp + strlen(cp);
5262 cp = eol;
5263 } else {
5264 break;
5265 }
5266 }
5267 return cp;
5268 }
5269
5270 //-----------------------equivalent_expressions--------------------------------
equivalent_expressions(const char * str1,const char * str2)5271 bool ADLParser::equivalent_expressions(const char* str1, const char* str2) {
5272 if (str1 == str2)
5273 return true;
5274 else if (str1 == NULL || str2 == 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------------------------------------------
trim(char * & token)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 }
5317