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