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