duke@435: /* twisti@1038: * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. duke@435: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. duke@435: * duke@435: * This code is free software; you can redistribute it and/or modify it duke@435: * under the terms of the GNU General Public License version 2 only, as duke@435: * published by the Free Software Foundation. duke@435: * duke@435: * This code is distributed in the hope that it will be useful, but WITHOUT duke@435: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or duke@435: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License duke@435: * version 2 for more details (a copy is included in the LICENSE file that duke@435: * accompanied this code). duke@435: * duke@435: * You should have received a copy of the GNU General Public License version duke@435: * 2 along with this work; if not, write to the Free Software Foundation, duke@435: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. duke@435: * duke@435: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, duke@435: * CA 95054 USA or visit www.sun.com if you need additional information or duke@435: * have any questions. duke@435: * duke@435: */ duke@435: duke@435: // ADLPARSE.CPP - Architecture Description Language Parser duke@435: // Authors: Chris Vick and Mike Paleczny duke@435: #include "adlc.hpp" duke@435: duke@435: //----------------------------ADLParser---------------------------------------- duke@435: // Create a new ADL parser duke@435: ADLParser::ADLParser(FileBuff& buffer, ArchDesc& archDesc) duke@435: : _buf(buffer), _AD(archDesc), duke@435: _globalNames(archDesc.globalNames()) { duke@435: _AD._syntax_errs = _AD._semantic_errs = 0; // No errors so far this file duke@435: _AD._warnings = 0; // No warnings either duke@435: _curline = _ptr = NULL; // No pointers into buffer yet duke@435: duke@435: _preproc_depth = 0; duke@435: _preproc_not_taken = 0; duke@435: duke@435: // Delimit command-line definitions from in-file definitions: duke@435: _AD._preproc_list.add_signal(); duke@435: } duke@435: duke@435: //------------------------------~ADLParser------------------------------------- duke@435: // Delete an ADL parser. duke@435: ADLParser::~ADLParser() { duke@435: if (!_AD._quiet_mode) duke@435: fprintf(stderr,"---------------------------- Errors and Warnings ----------------------------\n"); duke@435: #ifndef ASSERT duke@435: fprintf(stderr, "**************************************************************\n"); duke@435: fprintf(stderr, "***** WARNING: ASSERT is undefined, assertions disabled. *****\n"); duke@435: fprintf(stderr, "**************************************************************\n"); duke@435: #endif duke@435: if( _AD._syntax_errs + _AD._semantic_errs + _AD._warnings == 0 ) { duke@435: if (!_AD._quiet_mode) duke@435: fprintf(stderr,"No errors or warnings to report from phase-1 parse.\n" ); duke@435: } duke@435: else { duke@435: if( _AD._syntax_errs ) { // Any syntax errors? duke@435: fprintf(stderr,"%s: Found %d syntax error", _buf._fp->_name, _AD._syntax_errs); duke@435: if( _AD._syntax_errs > 1 ) fprintf(stderr,"s.\n\n"); duke@435: else fprintf(stderr,".\n\n"); duke@435: } duke@435: if( _AD._semantic_errs ) { // Any semantic errors? duke@435: fprintf(stderr,"%s: Found %d semantic error", _buf._fp->_name, _AD._semantic_errs); duke@435: if( _AD._semantic_errs > 1 ) fprintf(stderr,"s.\n\n"); duke@435: else fprintf(stderr,".\n\n"); duke@435: } duke@435: if( _AD._warnings ) { // Any warnings? duke@435: fprintf(stderr,"%s: Found %d warning", _buf._fp->_name, _AD._warnings); duke@435: if( _AD._warnings > 1 ) fprintf(stderr,"s.\n\n"); duke@435: else fprintf(stderr,".\n\n"); duke@435: } duke@435: } duke@435: if (!_AD._quiet_mode) duke@435: fprintf(stderr,"-----------------------------------------------------------------------------\n"); never@850: _AD._TotalLines += linenum()-1; // -1 for overshoot in "nextline" routine duke@435: duke@435: // Write out information we have stored duke@435: // // UNIXism == fsync(stderr); duke@435: } duke@435: duke@435: //------------------------------parse------------------------------------------ duke@435: // Each top-level keyword should appear as the first non-whitespace on a line. duke@435: // duke@435: void ADLParser::parse() { duke@435: char *ident; duke@435: duke@435: // Iterate over the lines in the file buffer parsing Level 1 objects duke@435: for( next_line(); _curline != NULL; next_line()) { duke@435: _ptr = _curline; // Reset ptr to start of new line duke@435: skipws(); // Skip any leading whitespace duke@435: ident = get_ident(); // Get first token duke@435: if (ident == NULL) { // Empty line duke@435: continue; // Get the next line duke@435: } duke@435: if (!strcmp(ident, "instruct")) instr_parse(); duke@435: else if (!strcmp(ident, "operand")) oper_parse(); duke@435: else if (!strcmp(ident, "opclass")) opclass_parse(); duke@435: else if (!strcmp(ident, "ins_attrib")) ins_attr_parse(); duke@435: else if (!strcmp(ident, "op_attrib")) op_attr_parse(); duke@435: else if (!strcmp(ident, "source")) source_parse(); duke@435: else if (!strcmp(ident, "source_hpp")) source_hpp_parse(); duke@435: else if (!strcmp(ident, "register")) reg_parse(); duke@435: else if (!strcmp(ident, "frame")) frame_parse(); duke@435: else if (!strcmp(ident, "encode")) encode_parse(); duke@435: else if (!strcmp(ident, "pipeline")) pipe_parse(); duke@435: else if (!strcmp(ident, "definitions")) definitions_parse(); duke@435: else if (!strcmp(ident, "peephole")) peep_parse(); jrose@910: else if (!strcmp(ident, "#line")) preproc_line(); duke@435: else if (!strcmp(ident, "#define")) preproc_define(); duke@435: else if (!strcmp(ident, "#undef")) preproc_undef(); duke@435: else { duke@435: parse_err(SYNERR, "expected one of - instruct, operand, ins_attrib, op_attrib, source, register, pipeline, encode\n Found %s",ident); duke@435: } duke@435: } duke@435: duke@435: // Done with parsing, check consistency. duke@435: duke@435: if (_preproc_depth != 0) { duke@435: parse_err(SYNERR, "End of file inside #ifdef"); duke@435: } duke@435: duke@435: // AttributeForms ins_cost and op_cost must be defined for default behaviour duke@435: if (_globalNames[AttributeForm::_ins_cost] == NULL) { duke@435: parse_err(SEMERR, "Did not declare 'ins_cost' attribute"); duke@435: } duke@435: if (_globalNames[AttributeForm::_ins_pc_relative] == NULL) { duke@435: parse_err(SEMERR, "Did not declare 'ins_pc_relative' attribute"); duke@435: } duke@435: if (_globalNames[AttributeForm::_op_cost] == NULL) { duke@435: parse_err(SEMERR, "Did not declare 'op_cost' attribute"); duke@435: } duke@435: } duke@435: duke@435: // ******************** Private Level 1 Parse Functions ******************** duke@435: //------------------------------instr_parse------------------------------------ duke@435: // Parse the contents of an instruction definition, build the InstructForm to duke@435: // represent that instruction, and add it to the InstructForm list. duke@435: void ADLParser::instr_parse(void) { duke@435: char *ident; duke@435: InstructForm *instr; duke@435: MatchRule *rule; duke@435: int match_rules_cnt = 0; duke@435: duke@435: // First get the name of the instruction duke@435: if( (ident = get_unique_ident(_globalNames,"instruction")) == NULL ) duke@435: return; duke@435: instr = new InstructForm(ident); // Create new instruction form never@850: instr->_linenum = linenum(); duke@435: _globalNames.Insert(ident, instr); // Add name to the name table duke@435: // Debugging Stuff duke@435: if (_AD._adl_debug > 1) duke@435: fprintf(stderr,"Parsing Instruction Form %s\n", ident); duke@435: duke@435: // Then get the operands duke@435: skipws(); duke@435: if (_curchar != '(') { duke@435: parse_err(SYNERR, "missing '(' in instruct definition\n"); duke@435: } duke@435: // Parse the operand list duke@435: else get_oplist(instr->_parameters, instr->_localNames); duke@435: skipws(); // Skip leading whitespace duke@435: // Check for block delimiter duke@435: if ( (_curchar != '%') duke@435: || ( next_char(), (_curchar != '{')) ) { duke@435: parse_err(SYNERR, "missing '%{' in instruction definition\n"); duke@435: return; duke@435: } duke@435: next_char(); // Maintain the invariant duke@435: do { duke@435: ident = get_ident(); // Grab next identifier duke@435: if (ident == NULL) { duke@435: parse_err(SYNERR, "keyword identifier expected at %c\n", _curchar); duke@435: continue; duke@435: } duke@435: if (!strcmp(ident, "predicate")) instr->_predicate = pred_parse(); duke@435: else if (!strcmp(ident, "match")) { duke@435: // Allow one instruction have several match rules. duke@435: rule = instr->_matrule; duke@435: if (rule == NULL) { duke@435: // This is first match rule encountered duke@435: rule = match_parse(instr->_localNames); duke@435: if (rule) { duke@435: instr->_matrule = rule; duke@435: // Special case the treatment of Control instructions. duke@435: if( instr->is_ideal_control() ) { duke@435: // Control instructions return a special result, 'Universe' duke@435: rule->_result = "Universe"; duke@435: } duke@435: // Check for commutative operations with tree operands. duke@435: matchrule_clone_and_swap(rule, instr->_ident, match_rules_cnt); duke@435: } duke@435: } else { duke@435: // Find the end of the match rule list duke@435: while (rule->_next != NULL) duke@435: rule = rule->_next; duke@435: // Add the new match rule to the list duke@435: rule->_next = match_parse(instr->_localNames); duke@435: if (rule->_next) { duke@435: rule = rule->_next; duke@435: if( instr->is_ideal_control() ) { duke@435: parse_err(SYNERR, "unique match rule expected for %s\n", rule->_name); duke@435: return; duke@435: } duke@435: assert(match_rules_cnt < 100," too many match rule clones"); duke@435: char* buf = (char*) malloc(strlen(instr->_ident) + 4); duke@435: sprintf(buf, "%s_%d", instr->_ident, match_rules_cnt++); duke@435: rule->_result = buf; duke@435: // Check for commutative operations with tree operands. duke@435: matchrule_clone_and_swap(rule, instr->_ident, match_rules_cnt); duke@435: } duke@435: } duke@435: } duke@435: else if (!strcmp(ident, "encode")) { duke@435: parse_err(SYNERR, "Instructions specify ins_encode, not encode\n"); duke@435: } duke@435: else if (!strcmp(ident, "ins_encode")) duke@435: instr->_insencode = ins_encode_parse(*instr); duke@435: else if (!strcmp(ident, "opcode")) instr->_opcode = opcode_parse(instr); duke@435: else if (!strcmp(ident, "size")) instr->_size = size_parse(instr); duke@435: else if (!strcmp(ident, "effect")) effect_parse(instr); duke@435: else if (!strcmp(ident, "expand")) instr->_exprule = expand_parse(instr); duke@435: else if (!strcmp(ident, "rewrite")) instr->_rewrule = rewrite_parse(); duke@435: else if (!strcmp(ident, "constraint")) { duke@435: parse_err(SYNERR, "Instructions do not specify a constraint\n"); duke@435: } duke@435: else if (!strcmp(ident, "construct")) { duke@435: parse_err(SYNERR, "Instructions do not specify a construct\n"); duke@435: } duke@435: else if (!strcmp(ident, "format")) instr->_format = format_parse(); duke@435: else if (!strcmp(ident, "interface")) { duke@435: parse_err(SYNERR, "Instructions do not specify an interface\n"); duke@435: } duke@435: else if (!strcmp(ident, "ins_pipe")) ins_pipe_parse(*instr); duke@435: else { // Done with staticly defined parts of instruction definition duke@435: // Check identifier to see if it is the name of an attribute duke@435: const Form *form = _globalNames[ident]; duke@435: AttributeForm *attr = form ? form->is_attribute() : NULL; duke@435: if( attr && (attr->_atype == INS_ATTR) ) { duke@435: // Insert the new attribute into the linked list. duke@435: Attribute *temp = attr_parse(ident); duke@435: temp->_next = instr->_attribs; duke@435: instr->_attribs = temp; duke@435: } else { duke@435: parse_err(SYNERR, "expected one of:\n predicate, match, encode, or the name of an instruction attribute at %s\n", ident); duke@435: } duke@435: } duke@435: skipws(); duke@435: } while(_curchar != '%'); duke@435: next_char(); duke@435: if (_curchar != '}') { duke@435: parse_err(SYNERR, "missing '%}' in instruction definition\n"); duke@435: return; duke@435: } duke@435: // Check for "Set" form of chain rule duke@435: adjust_set_rule(instr); duke@435: if (_AD._pipeline ) { duke@435: if( instr->expands() ) { duke@435: if( instr->_ins_pipe ) duke@435: parse_err(WARN, "ins_pipe and expand rule both specified for instruction \"%s\"; ins_pipe will be unused\n", instr->_ident); duke@435: } else { duke@435: if( !instr->_ins_pipe ) duke@435: parse_err(WARN, "No ins_pipe specified for instruction \"%s\"\n", instr->_ident); duke@435: } duke@435: } duke@435: // Add instruction to tail of instruction list duke@435: _AD.addForm(instr); duke@435: duke@435: // Create instruction form for each additional match rule duke@435: rule = instr->_matrule; duke@435: if (rule != NULL) { duke@435: rule = rule->_next; duke@435: while (rule != NULL) { duke@435: ident = (char*)rule->_result; duke@435: InstructForm *clone = new InstructForm(ident, instr, rule); // Create new instruction form duke@435: _globalNames.Insert(ident, clone); // Add name to the name table duke@435: // Debugging Stuff duke@435: if (_AD._adl_debug > 1) duke@435: fprintf(stderr,"Parsing Instruction Form %s\n", ident); duke@435: // Check for "Set" form of chain rule duke@435: adjust_set_rule(clone); duke@435: // Add instruction to tail of instruction list duke@435: _AD.addForm(clone); duke@435: rule = rule->_next; duke@435: clone->_matrule->_next = NULL; // One match rule per clone duke@435: } duke@435: } duke@435: } duke@435: duke@435: //------------------------------matchrule_clone_and_swap----------------------- duke@435: // Check for commutative operations with subtree operands, duke@435: // create clones and swap operands. duke@435: void ADLParser::matchrule_clone_and_swap(MatchRule* rule, const char* instr_ident, int& match_rules_cnt) { duke@435: // Check for commutative operations with tree operands. duke@435: int count = 0; duke@435: rule->count_commutative_op(count); duke@435: if (count > 0) { duke@435: // Clone match rule and swap commutative operation's operands. twisti@1038: rule->matchrule_swap_commutative_op(instr_ident, count, match_rules_cnt); duke@435: } duke@435: } duke@435: duke@435: //------------------------------adjust_set_rule-------------------------------- duke@435: // Check for "Set" form of chain rule duke@435: void ADLParser::adjust_set_rule(InstructForm *instr) { duke@435: if (instr->_matrule == NULL || instr->_matrule->_rChild == NULL) return; duke@435: const char *rch = instr->_matrule->_rChild->_opType; duke@435: const Form *frm = _globalNames[rch]; duke@435: if( (! strcmp(instr->_matrule->_opType,"Set")) && duke@435: frm && frm->is_operand() && (! frm->ideal_only()) ) { duke@435: // Previous implementation, which missed leaP*, but worked for loadCon* duke@435: unsigned position = 0; duke@435: const char *result = NULL; duke@435: const char *name = NULL; duke@435: const char *optype = NULL; duke@435: MatchNode *right = instr->_matrule->_rChild; duke@435: if (right->base_operand(position, _globalNames, result, name, optype)) { duke@435: position = 1; duke@435: const char *result2 = NULL; duke@435: const char *name2 = NULL; duke@435: const char *optype2 = NULL; duke@435: // Can not have additional base operands in right side of match! duke@435: if ( ! right->base_operand( position, _globalNames, result2, name2, optype2) ) { duke@435: assert( instr->_predicate == NULL, "ADLC does not support instruction chain rules with predicates"); duke@435: // Chain from input _ideal_operand_type_, duke@435: // Needed for shared roots of match-trees duke@435: ChainList *lst = (ChainList *)_AD._chainRules[optype]; duke@435: if (lst == NULL) { duke@435: lst = new ChainList(); duke@435: _AD._chainRules.Insert(optype, lst); duke@435: } duke@435: if (!lst->search(instr->_matrule->_lChild->_opType)) { duke@435: const char *cost = instr->cost(); duke@435: if (cost == NULL) { duke@435: cost = ((AttributeForm*)_globalNames[AttributeForm::_ins_cost])->_attrdef; duke@435: } duke@435: // The ADLC does not support chaining from the ideal operand type duke@435: // of a predicated user-defined operand duke@435: if( frm->is_operand() == NULL || frm->is_operand()->_predicate == NULL ) { duke@435: lst->insert(instr->_matrule->_lChild->_opType,cost,instr->_ident); duke@435: } duke@435: } duke@435: // Chain from input _user_defined_operand_type_, duke@435: lst = (ChainList *)_AD._chainRules[result]; duke@435: if (lst == NULL) { duke@435: lst = new ChainList(); duke@435: _AD._chainRules.Insert(result, lst); duke@435: } duke@435: if (!lst->search(instr->_matrule->_lChild->_opType)) { duke@435: const char *cost = instr->cost(); duke@435: if (cost == NULL) { duke@435: cost = ((AttributeForm*)_globalNames[AttributeForm::_ins_cost])->_attrdef; duke@435: } duke@435: // It is safe to chain from the top-level user-defined operand even duke@435: // if it has a predicate, since the predicate is checked before duke@435: // the user-defined type is available. duke@435: lst->insert(instr->_matrule->_lChild->_opType,cost,instr->_ident); duke@435: } duke@435: } else { duke@435: // May have instruction chain rule if root of right-tree is an ideal duke@435: OperandForm *rightOp = _globalNames[right->_opType]->is_operand(); duke@435: if( rightOp ) { duke@435: const Form *rightRoot = _globalNames[rightOp->_matrule->_opType]; duke@435: if( rightRoot && rightRoot->ideal_only() ) { duke@435: const char *chain_op = NULL; duke@435: if( rightRoot->is_instruction() ) duke@435: chain_op = rightOp->_ident; duke@435: if( chain_op ) { duke@435: // Look-up the operation in chain rule table duke@435: ChainList *lst = (ChainList *)_AD._chainRules[chain_op]; duke@435: if (lst == NULL) { duke@435: lst = new ChainList(); duke@435: _AD._chainRules.Insert(chain_op, lst); duke@435: } duke@435: // if (!lst->search(instr->_matrule->_lChild->_opType)) { duke@435: const char *cost = instr->cost(); duke@435: if (cost == NULL) { duke@435: cost = ((AttributeForm*)_globalNames[AttributeForm::_ins_cost])->_attrdef; duke@435: } duke@435: // This chains from a top-level operand whose predicate, if any, duke@435: // has been checked. duke@435: lst->insert(instr->_matrule->_lChild->_opType,cost,instr->_ident); duke@435: // } duke@435: } duke@435: } duke@435: } duke@435: } // end chain rule from right-tree's ideal root duke@435: } duke@435: } duke@435: } duke@435: duke@435: duke@435: //------------------------------oper_parse------------------------------------- duke@435: void ADLParser::oper_parse(void) { duke@435: char *ident; duke@435: OperandForm *oper; duke@435: AttributeForm *attr; duke@435: MatchRule *rule; duke@435: duke@435: // First get the name of the operand duke@435: skipws(); duke@435: if( (ident = get_unique_ident(_globalNames,"operand")) == NULL ) duke@435: return; duke@435: oper = new OperandForm(ident); // Create new operand form never@850: oper->_linenum = linenum(); duke@435: _globalNames.Insert(ident, oper); // Add name to the name table duke@435: duke@435: // Debugging Stuff duke@435: if (_AD._adl_debug > 1) fprintf(stderr,"Parsing Operand Form %s\n", ident); duke@435: duke@435: // Get the component operands duke@435: skipws(); duke@435: if (_curchar != '(') { duke@435: parse_err(SYNERR, "missing '(' in operand definition\n"); duke@435: return; duke@435: } duke@435: else get_oplist(oper->_parameters, oper->_localNames); // Parse the component operand list duke@435: skipws(); duke@435: // Check for block delimiter duke@435: if ((_curchar != '%') || (*(_ptr+1) != '{')) { // If not open block duke@435: parse_err(SYNERR, "missing '%c{' in operand definition\n","%"); duke@435: return; duke@435: } duke@435: next_char(); next_char(); // Skip over "%{" symbol duke@435: do { duke@435: ident = get_ident(); // Grab next identifier duke@435: if (ident == NULL) { duke@435: parse_err(SYNERR, "keyword identifier expected at %c\n", _curchar); duke@435: continue; duke@435: } duke@435: if (!strcmp(ident, "predicate")) oper->_predicate = pred_parse(); duke@435: else if (!strcmp(ident, "match")) { duke@435: // Find the end of the match rule list duke@435: rule = oper->_matrule; duke@435: if (rule) { duke@435: while (rule->_next) rule = rule->_next; duke@435: // Add the new match rule to the list duke@435: rule->_next = match_parse(oper->_localNames); duke@435: if (rule->_next) { duke@435: rule->_next->_result = oper->_ident; duke@435: } duke@435: } duke@435: else { duke@435: // This is first match rule encountered duke@435: oper->_matrule = match_parse(oper->_localNames); duke@435: if (oper->_matrule) { duke@435: oper->_matrule->_result = oper->_ident; duke@435: } duke@435: } duke@435: } duke@435: else if (!strcmp(ident, "encode")) oper->_interface = interface_parse(); duke@435: else if (!strcmp(ident, "ins_encode")) { duke@435: parse_err(SYNERR, "Operands specify 'encode', not 'ins_encode'\n"); duke@435: } duke@435: else if (!strcmp(ident, "opcode")) { duke@435: parse_err(SYNERR, "Operands do not specify an opcode\n"); duke@435: } duke@435: else if (!strcmp(ident, "effect")) { duke@435: parse_err(SYNERR, "Operands do not specify an effect\n"); duke@435: } duke@435: else if (!strcmp(ident, "expand")) { duke@435: parse_err(SYNERR, "Operands do not specify an expand\n"); duke@435: } duke@435: else if (!strcmp(ident, "rewrite")) { duke@435: parse_err(SYNERR, "Operands do not specify a rewrite\n"); duke@435: } duke@435: else if (!strcmp(ident, "constraint"))oper->_constraint= constraint_parse(); duke@435: else if (!strcmp(ident, "construct")) oper->_construct = construct_parse(); duke@435: else if (!strcmp(ident, "format")) oper->_format = format_parse(); duke@435: else if (!strcmp(ident, "interface")) oper->_interface = interface_parse(); duke@435: // Check identifier to see if it is the name of an attribute duke@435: else if (((attr = _globalNames[ident]->is_attribute()) != NULL) && duke@435: (attr->_atype == OP_ATTR)) oper->_attribs = attr_parse(ident); duke@435: else { duke@435: parse_err(SYNERR, "expected one of - constraint, predicate, match, encode, format, construct, or the name of a defined operand attribute at %s\n", ident); duke@435: } duke@435: skipws(); duke@435: } while(_curchar != '%'); duke@435: next_char(); duke@435: if (_curchar != '}') { duke@435: parse_err(SYNERR, "missing '%}' in operand definition\n"); duke@435: return; duke@435: } duke@435: // Add operand to tail of operand list duke@435: _AD.addForm(oper); duke@435: } duke@435: duke@435: //------------------------------opclass_parse---------------------------------- duke@435: // Operand Classes are a block with a comma delimited list of operand names duke@435: void ADLParser::opclass_parse(void) { duke@435: char *ident; duke@435: OpClassForm *opc; duke@435: OperandForm *opForm; duke@435: duke@435: // First get the name of the operand class duke@435: skipws(); duke@435: if( (ident = get_unique_ident(_globalNames,"opclass")) == NULL ) duke@435: return; duke@435: opc = new OpClassForm(ident); // Create new operand class form duke@435: _globalNames.Insert(ident, opc); // Add name to the name table duke@435: duke@435: // Debugging Stuff duke@435: if (_AD._adl_debug > 1) duke@435: fprintf(stderr,"Parsing Operand Class Form %s\n", ident); duke@435: duke@435: // Get the list of operands duke@435: skipws(); duke@435: if (_curchar != '(') { duke@435: parse_err(SYNERR, "missing '(' in operand definition\n"); duke@435: return; duke@435: } duke@435: do { duke@435: next_char(); // Skip past open paren or comma duke@435: ident = get_ident(); // Grab next identifier duke@435: if (ident == NULL) { duke@435: parse_err(SYNERR, "keyword identifier expected at %c\n", _curchar); duke@435: continue; duke@435: } duke@435: // Check identifier to see if it is the name of an operand duke@435: const Form *form = _globalNames[ident]; duke@435: opForm = form ? form->is_operand() : NULL; duke@435: if ( opForm ) { duke@435: opc->_oplst.addName(ident); // Add operand to opclass list duke@435: opForm->_classes.addName(opc->_ident);// Add opclass to operand list duke@435: } duke@435: else { duke@435: parse_err(SYNERR, "expected name of a defined operand at %s\n", ident); duke@435: } duke@435: skipws(); // skip trailing whitespace duke@435: } while (_curchar == ','); // Check for the comma duke@435: // Check for closing ')' duke@435: if (_curchar != ')') { duke@435: parse_err(SYNERR, "missing ')' or ',' in opclass definition\n"); duke@435: return; duke@435: } duke@435: next_char(); // Consume the ')' duke@435: skipws(); duke@435: // Check for closing ';' duke@435: if (_curchar != ';') { duke@435: parse_err(SYNERR, "missing ';' in opclass definition\n"); duke@435: return; duke@435: } duke@435: next_char(); // Consume the ';' duke@435: // Add operand to tail of operand list duke@435: _AD.addForm(opc); duke@435: } duke@435: duke@435: //------------------------------ins_attr_parse--------------------------------- duke@435: void ADLParser::ins_attr_parse(void) { duke@435: char *ident; duke@435: char *aexpr; duke@435: AttributeForm *attrib; duke@435: duke@435: // get name for the instruction attribute duke@435: skipws(); // Skip leading whitespace duke@435: if( (ident = get_unique_ident(_globalNames,"inst_attrib")) == NULL ) duke@435: return; duke@435: // Debugging Stuff duke@435: if (_AD._adl_debug > 1) fprintf(stderr,"Parsing Ins_Attribute Form %s\n", ident); duke@435: duke@435: // Get default value of the instruction attribute duke@435: skipws(); // Skip whitespace duke@435: if ((aexpr = get_paren_expr("attribute default expression string")) == NULL) { duke@435: parse_err(SYNERR, "missing '(' in ins_attrib definition\n"); duke@435: return; duke@435: } duke@435: // Debug Stuff duke@435: if (_AD._adl_debug > 1) fprintf(stderr,"Attribute Expression: %s\n", aexpr); duke@435: duke@435: // Check for terminator duke@435: if (_curchar != ';') { duke@435: parse_err(SYNERR, "missing ';' in ins_attrib definition\n"); duke@435: return; duke@435: } duke@435: next_char(); // Advance past the ';' duke@435: duke@435: // Construct the attribute, record global name, and store in ArchDesc duke@435: attrib = new AttributeForm(ident, INS_ATTR, aexpr); duke@435: _globalNames.Insert(ident, attrib); // Add name to the name table duke@435: _AD.addForm(attrib); duke@435: } duke@435: duke@435: //------------------------------op_attr_parse---------------------------------- duke@435: void ADLParser::op_attr_parse(void) { duke@435: char *ident; duke@435: char *aexpr; duke@435: AttributeForm *attrib; duke@435: duke@435: // get name for the operand attribute duke@435: skipws(); // Skip leading whitespace duke@435: if( (ident = get_unique_ident(_globalNames,"op_attrib")) == NULL ) duke@435: return; duke@435: // Debugging Stuff duke@435: if (_AD._adl_debug > 1) fprintf(stderr,"Parsing Op_Attribute Form %s\n", ident); duke@435: duke@435: // Get default value of the instruction attribute duke@435: skipws(); // Skip whitespace duke@435: if ((aexpr = get_paren_expr("attribute default expression string")) == NULL) { duke@435: parse_err(SYNERR, "missing '(' in op_attrib definition\n"); duke@435: return; duke@435: } duke@435: // Debug Stuff duke@435: if (_AD._adl_debug > 1) fprintf(stderr,"Attribute Expression: %s\n", aexpr); duke@435: duke@435: // Check for terminator duke@435: if (_curchar != ';') { duke@435: parse_err(SYNERR, "missing ';' in op_attrib definition\n"); duke@435: return; duke@435: } duke@435: next_char(); // Advance past the ';' duke@435: duke@435: // Construct the attribute, record global name, and store in ArchDesc duke@435: attrib = new AttributeForm(ident, OP_ATTR, aexpr); duke@435: _globalNames.Insert(ident, attrib); duke@435: _AD.addForm(attrib); duke@435: } duke@435: duke@435: //------------------------------definitions_parse----------------------------------- duke@435: void ADLParser::definitions_parse(void) { duke@435: skipws(); // Skip leading whitespace duke@435: if (_curchar == '%' && *(_ptr+1) == '{') { duke@435: next_char(); next_char(); // Skip "%{" duke@435: skipws(); duke@435: while (_curchar != '%' && *(_ptr+1) != '}') { duke@435: // Process each definition until finding closing string "%}" duke@435: char *token = get_ident(); duke@435: if (token == NULL) { duke@435: parse_err(SYNERR, "missing identifier inside definitions block.\n"); duke@435: return; duke@435: } duke@435: if (strcmp(token,"int_def")==0) { int_def_parse(); } duke@435: // if (strcmp(token,"str_def")==0) { str_def_parse(); } duke@435: skipws(); duke@435: } duke@435: } duke@435: else { duke@435: parse_err(SYNERR, "Missing %%{ ... %%} block after definitions keyword.\n"); duke@435: return; duke@435: } duke@435: } duke@435: duke@435: //------------------------------int_def_parse---------------------------------- duke@435: // Parse Example: duke@435: // int_def MEMORY_REF_COST ( 200, DEFAULT_COST * 2); duke@435: // ( , ); duke@435: // duke@435: void ADLParser::int_def_parse(void) { duke@435: char *name = NULL; // Name of definition duke@435: char *value = NULL; // its value, duke@435: int int_value = -1; // positive values only duke@435: char *description = NULL; // textual description duke@435: duke@435: // Get definition name duke@435: skipws(); // Skip whitespace duke@435: name = get_ident(); duke@435: if (name == NULL) { duke@435: parse_err(SYNERR, "missing definition name after int_def\n"); duke@435: return; duke@435: } duke@435: duke@435: // Check for value of int_def dname( integer_value [, string_expression ] ) duke@435: skipws(); duke@435: if (_curchar == '(') { duke@435: duke@435: // Parse the integer value. duke@435: next_char(); duke@435: value = get_ident(); duke@435: if (value == NULL) { duke@435: parse_err(SYNERR, "missing value in int_def\n"); duke@435: return; duke@435: } duke@435: if( !is_int_token(value, int_value) ) { duke@435: parse_err(SYNERR, "value in int_def is not recognized as integer\n"); duke@435: return; duke@435: } duke@435: skipws(); duke@435: duke@435: // Check for description duke@435: if (_curchar == ',') { duke@435: next_char(); // skip ',' duke@435: duke@435: description = get_expr("int_def description", ")"); duke@435: if (description == NULL) { duke@435: parse_err(SYNERR, "invalid or missing description in int_def\n"); duke@435: return; duke@435: } duke@435: trim(description); duke@435: } duke@435: duke@435: if (_curchar != ')') { duke@435: parse_err(SYNERR, "missing ')' in register definition statement\n"); duke@435: return; duke@435: } duke@435: next_char(); duke@435: } duke@435: duke@435: // Check for closing ';' duke@435: skipws(); duke@435: if (_curchar != ';') { duke@435: parse_err(SYNERR, "missing ';' after int_def\n"); duke@435: return; duke@435: } duke@435: next_char(); // move past ';' duke@435: duke@435: // Debug Stuff duke@435: if (_AD._adl_debug > 1) { duke@435: fprintf(stderr,"int_def: %s ( %s, %s )\n", name, duke@435: (value), (description ? description : "")); duke@435: } duke@435: duke@435: // Record new definition. duke@435: Expr *expr = new Expr(name, description, int_value, int_value); duke@435: const Expr *old_expr = _AD.globalDefs().define(name, expr); duke@435: if (old_expr != NULL) { duke@435: parse_err(SYNERR, "Duplicate definition\n"); duke@435: return; duke@435: } duke@435: duke@435: return; duke@435: } duke@435: duke@435: duke@435: //------------------------------source_parse----------------------------------- duke@435: void ADLParser::source_parse(void) { duke@435: SourceForm *source; // Encode class for instruction/operand duke@435: char *rule = NULL; // String representation of encode rule duke@435: duke@435: skipws(); // Skip leading whitespace duke@435: if ( (rule = find_cpp_block("source block")) == NULL ) { duke@435: parse_err(SYNERR, "incorrect or missing block for 'source'.\n"); duke@435: return; duke@435: } duke@435: // Debug Stuff duke@435: if (_AD._adl_debug > 1) fprintf(stderr,"Source Form: %s\n", rule); duke@435: duke@435: source = new SourceForm(rule); // Build new Source object duke@435: _AD.addForm(source); duke@435: // skipws(); duke@435: } duke@435: duke@435: //------------------------------source_hpp_parse------------------------------- duke@435: // Parse a source_hpp %{ ... %} block. duke@435: // The code gets stuck into the ad_.hpp file. duke@435: // If the source_hpp block appears before the register block in the AD duke@435: // file, it goes up at the very top of the ad_.hpp file, so that duke@435: // it can be used by register encodings, etc. Otherwise, it goes towards duke@435: // the bottom, where it's useful as a global definition to *.cpp files. duke@435: void ADLParser::source_hpp_parse(void) { duke@435: char *rule = NULL; // String representation of encode rule duke@435: duke@435: skipws(); // Skip leading whitespace duke@435: if ( (rule = find_cpp_block("source_hpp block")) == NULL ) { duke@435: parse_err(SYNERR, "incorrect or missing block for 'source_hpp'.\n"); duke@435: return; duke@435: } duke@435: // Debug Stuff duke@435: if (_AD._adl_debug > 1) fprintf(stderr,"Header Form: %s\n", rule); duke@435: duke@435: if (_AD.get_registers() == NULL) { duke@435: // Very early in the file, before reg_defs, we collect pre-headers. duke@435: PreHeaderForm* pre_header = new PreHeaderForm(rule); duke@435: _AD.addForm(pre_header); duke@435: } else { duke@435: // Normally, we collect header info, placed at the bottom of the hpp file. duke@435: HeaderForm* header = new HeaderForm(rule); duke@435: _AD.addForm(header); duke@435: } duke@435: } duke@435: duke@435: //------------------------------reg_parse-------------------------------------- duke@435: void ADLParser::reg_parse(void) { duke@435: duke@435: // Create the RegisterForm for the architecture description. duke@435: RegisterForm *regBlock = new RegisterForm(); // Build new Source object never@850: regBlock->_linenum = linenum(); duke@435: _AD.addForm(regBlock); duke@435: duke@435: skipws(); // Skip leading whitespace duke@435: if (_curchar == '%' && *(_ptr+1) == '{') { duke@435: next_char(); next_char(); // Skip "%{" duke@435: skipws(); duke@435: while (_curchar != '%' && *(_ptr+1) != '}') { duke@435: char *token = get_ident(); duke@435: if (token == NULL) { duke@435: parse_err(SYNERR, "missing identifier inside register block.\n"); duke@435: return; duke@435: } jrose@910: if (strcmp(token,"reg_def")==0) { reg_def_parse(); } jrose@910: else if (strcmp(token,"reg_class")==0) { reg_class_parse(); } jrose@910: else if (strcmp(token,"alloc_class")==0) { alloc_class_parse(); } jrose@910: else if (strcmp(token,"#define")==0) { preproc_define(); } jrose@910: else { parse_err(SYNERR, "bad token %s inside register block.\n", token); break; } duke@435: skipws(); duke@435: } duke@435: } duke@435: else { duke@435: parse_err(SYNERR, "Missing %c{ ... %c} block after register keyword.\n",'%','%'); duke@435: return; duke@435: } duke@435: duke@435: // Add reg_class spill_regs duke@435: regBlock->addSpillRegClass(); duke@435: } duke@435: duke@435: //------------------------------encode_parse----------------------------------- duke@435: void ADLParser::encode_parse(void) { duke@435: EncodeForm *encBlock; // Information about instruction/operand encoding duke@435: char *desc = NULL; // String representation of encode rule duke@435: duke@435: _AD.getForm(&encBlock); duke@435: if ( encBlock == NULL) { duke@435: // Create the EncodeForm for the architecture description. duke@435: encBlock = new EncodeForm(); // Build new Source object duke@435: _AD.addForm(encBlock); duke@435: } duke@435: duke@435: skipws(); // Skip leading whitespace duke@435: if (_curchar == '%' && *(_ptr+1) == '{') { duke@435: next_char(); next_char(); // Skip "%{" duke@435: skipws(); duke@435: while (_curchar != '%' && *(_ptr+1) != '}') { duke@435: char *token = get_ident(); duke@435: if (token == NULL) { duke@435: parse_err(SYNERR, "missing identifier inside encoding block.\n"); duke@435: return; duke@435: } duke@435: if (strcmp(token,"enc_class")==0) { enc_class_parse(); } duke@435: skipws(); duke@435: } duke@435: } duke@435: else { duke@435: parse_err(SYNERR, "Missing %c{ ... %c} block after encode keyword.\n",'%','%'); duke@435: return; duke@435: } duke@435: } duke@435: duke@435: //------------------------------enc_class_parse-------------------------------- duke@435: void ADLParser::enc_class_parse(void) { duke@435: char *ec_name; // Name of encoding class being defined duke@435: duke@435: // Get encoding class name duke@435: skipws(); // Skip whitespace duke@435: ec_name = get_ident(); duke@435: if (ec_name == NULL) { duke@435: parse_err(SYNERR, "missing encoding class name after encode.\n"); duke@435: return; duke@435: } duke@435: duke@435: EncClass *encoding = _AD._encode->add_EncClass(ec_name); never@850: encoding->_linenum = linenum(); duke@435: duke@435: skipws(); // Skip leading whitespace duke@435: // Check for optional parameter list duke@435: if (_curchar == '(') { duke@435: do { duke@435: char *pType = NULL; // parameter type duke@435: char *pName = NULL; // parameter name duke@435: duke@435: next_char(); // skip open paren & comma characters duke@435: skipws(); duke@435: if (_curchar == ')') break; duke@435: duke@435: // Get parameter type duke@435: pType = get_ident(); duke@435: if (pType == NULL) { duke@435: parse_err(SYNERR, "parameter type expected at %c\n", _curchar); duke@435: return; duke@435: } duke@435: duke@435: skipws(); duke@435: // Get parameter name duke@435: pName = get_ident(); duke@435: if (pName == NULL) { duke@435: parse_err(SYNERR, "parameter name expected at %c\n", _curchar); duke@435: return; duke@435: } duke@435: duke@435: // Record parameter type and name duke@435: encoding->add_parameter( pType, pName ); duke@435: duke@435: skipws(); duke@435: } while(_curchar == ','); duke@435: duke@435: if (_curchar != ')') parse_err(SYNERR, "missing ')'\n"); duke@435: else { duke@435: next_char(); // Skip ')' duke@435: } duke@435: } // Done with parameter list duke@435: duke@435: skipws(); duke@435: // Check for block starting delimiters duke@435: if ((_curchar != '%') || (*(_ptr+1) != '{')) { // If not open block duke@435: parse_err(SYNERR, "missing '%c{' in enc_class definition\n", '%'); duke@435: return; duke@435: } duke@435: next_char(); // Skip '%' duke@435: next_char(); // Skip '{' duke@435: duke@435: enc_class_parse_block(encoding, ec_name); duke@435: } duke@435: duke@435: duke@435: void ADLParser::enc_class_parse_block(EncClass* encoding, char* ec_name) { duke@435: skipws_no_preproc(); // Skip leading whitespace duke@435: // Prepend location descriptor, for debugging; cf. ADLParser::find_cpp_block duke@435: if (_AD._adlocation_debug) { jrose@910: encoding->add_code(get_line_string()); duke@435: } duke@435: duke@435: // Collect the parts of the encode description duke@435: // (1) strings that are passed through to output duke@435: // (2) replacement/substitution variable, preceeded by a '$' duke@435: while ( (_curchar != '%') && (*(_ptr+1) != '}') ) { duke@435: duke@435: // (1) duke@435: // Check if there is a string to pass through to output duke@435: char *start = _ptr; // Record start of the next string duke@435: while ((_curchar != '$') && ((_curchar != '%') || (*(_ptr+1) != '}')) ) { duke@435: // If at the start of a comment, skip past it duke@435: if( (_curchar == '/') && ((*(_ptr+1) == '/') || (*(_ptr+1) == '*')) ) { duke@435: skipws_no_preproc(); duke@435: } else { duke@435: // ELSE advance to the next character, or start of the next line duke@435: next_char_or_line(); duke@435: } duke@435: } duke@435: // If a string was found, terminate it and record in EncClass duke@435: if ( start != _ptr ) { duke@435: *_ptr = '\0'; // Terminate the string duke@435: encoding->add_code(start); duke@435: } duke@435: duke@435: // (2) duke@435: // If we are at a replacement variable, duke@435: // copy it and record in EncClass duke@435: if ( _curchar == '$' ) { duke@435: // Found replacement Variable duke@435: char *rep_var = get_rep_var_ident_dup(); duke@435: // Add flag to _strings list indicating we should check _rep_vars duke@435: encoding->add_rep_var(rep_var); duke@435: } duke@435: } // end while part of format description duke@435: next_char(); // Skip '%' duke@435: next_char(); // Skip '}' duke@435: duke@435: skipws(); duke@435: jrose@910: if (_AD._adlocation_debug) { jrose@910: encoding->add_code(end_line_marker()); jrose@910: } jrose@910: duke@435: // Debug Stuff duke@435: if (_AD._adl_debug > 1) fprintf(stderr,"EncodingClass Form: %s\n", ec_name); duke@435: } duke@435: duke@435: //------------------------------frame_parse----------------------------------- duke@435: void ADLParser::frame_parse(void) { duke@435: FrameForm *frame; // Information about stack-frame layout duke@435: char *desc = NULL; // String representation of frame duke@435: duke@435: skipws(); // Skip leading whitespace duke@435: duke@435: frame = new FrameForm(); // Build new Frame object duke@435: // Check for open block sequence duke@435: skipws(); // Skip leading whitespace duke@435: if (_curchar == '%' && *(_ptr+1) == '{') { duke@435: next_char(); next_char(); // Skip "%{" duke@435: skipws(); duke@435: while (_curchar != '%' && *(_ptr+1) != '}') { duke@435: char *token = get_ident(); duke@435: if (token == NULL) { duke@435: parse_err(SYNERR, "missing identifier inside frame block.\n"); duke@435: return; duke@435: } duke@435: if (strcmp(token,"stack_direction")==0) { duke@435: stack_dir_parse(frame); duke@435: } duke@435: if (strcmp(token,"sync_stack_slots")==0) { duke@435: sync_stack_slots_parse(frame); duke@435: } duke@435: if (strcmp(token,"frame_pointer")==0) { duke@435: frame_pointer_parse(frame, false); duke@435: } duke@435: if (strcmp(token,"interpreter_frame_pointer")==0) { duke@435: interpreter_frame_pointer_parse(frame, false); duke@435: // Add reg_class interpreter_frame_pointer_reg duke@435: if( _AD._register != NULL ) { duke@435: RegClass *reg_class = _AD._register->addRegClass("interpreter_frame_pointer_reg"); duke@435: char *interpreter_frame_pointer_reg = frame->_interpreter_frame_pointer_reg; duke@435: if( interpreter_frame_pointer_reg != NULL ) { duke@435: RegDef *regDef = _AD._register->getRegDef(interpreter_frame_pointer_reg); duke@435: reg_class->addReg(regDef); // add regDef to regClass duke@435: } duke@435: } duke@435: } duke@435: if (strcmp(token,"inline_cache_reg")==0) { duke@435: inline_cache_parse(frame, false); duke@435: // Add reg_class inline_cache_reg duke@435: if( _AD._register != NULL ) { duke@435: RegClass *reg_class = _AD._register->addRegClass("inline_cache_reg"); duke@435: char *inline_cache_reg = frame->_inline_cache_reg; duke@435: if( inline_cache_reg != NULL ) { duke@435: RegDef *regDef = _AD._register->getRegDef(inline_cache_reg); duke@435: reg_class->addReg(regDef); // add regDef to regClass duke@435: } duke@435: } duke@435: } duke@435: if (strcmp(token,"compiler_method_oop_reg")==0) { duke@435: parse_err(WARN, "Using obsolete Token, compiler_method_oop_reg"); duke@435: skipws(); duke@435: } duke@435: if (strcmp(token,"interpreter_method_oop_reg")==0) { duke@435: interpreter_method_oop_parse(frame, false); duke@435: // Add reg_class interpreter_method_oop_reg duke@435: if( _AD._register != NULL ) { duke@435: RegClass *reg_class = _AD._register->addRegClass("interpreter_method_oop_reg"); duke@435: char *method_oop_reg = frame->_interpreter_method_oop_reg; duke@435: if( method_oop_reg != NULL ) { duke@435: RegDef *regDef = _AD._register->getRegDef(method_oop_reg); duke@435: reg_class->addReg(regDef); // add regDef to regClass duke@435: } duke@435: } duke@435: } duke@435: if (strcmp(token,"cisc_spilling_operand_name")==0) { duke@435: cisc_spilling_operand_name_parse(frame, false); duke@435: } duke@435: if (strcmp(token,"stack_alignment")==0) { duke@435: stack_alignment_parse(frame); duke@435: } duke@435: if (strcmp(token,"return_addr")==0) { duke@435: return_addr_parse(frame, false); duke@435: } duke@435: if (strcmp(token,"in_preserve_stack_slots")==0) { duke@435: preserve_stack_parse(frame); duke@435: } duke@435: if (strcmp(token,"out_preserve_stack_slots")==0) { duke@435: parse_err(WARN, "Using obsolete token, out_preserve_stack_slots"); duke@435: skipws(); duke@435: } duke@435: if (strcmp(token,"varargs_C_out_slots_killed")==0) { duke@435: frame->_varargs_C_out_slots_killed = parse_one_arg("varargs C out slots killed"); duke@435: } duke@435: if (strcmp(token,"calling_convention")==0) { duke@435: frame->_calling_convention = calling_convention_parse(); duke@435: } duke@435: if (strcmp(token,"return_value")==0) { duke@435: frame->_return_value = return_value_parse(); duke@435: } duke@435: if (strcmp(token,"c_frame_pointer")==0) { duke@435: frame_pointer_parse(frame, true); duke@435: } duke@435: if (strcmp(token,"c_return_addr")==0) { duke@435: return_addr_parse(frame, true); duke@435: } duke@435: if (strcmp(token,"c_calling_convention")==0) { duke@435: frame->_c_calling_convention = calling_convention_parse(); duke@435: } duke@435: if (strcmp(token,"c_return_value")==0) { duke@435: frame->_c_return_value = return_value_parse(); duke@435: } duke@435: duke@435: skipws(); duke@435: } duke@435: } duke@435: else { duke@435: parse_err(SYNERR, "Missing %c{ ... %c} block after encode keyword.\n",'%','%'); duke@435: return; duke@435: } duke@435: // All Java versions are required, native versions are optional duke@435: if(frame->_frame_pointer == NULL) { duke@435: parse_err(SYNERR, "missing frame pointer definition in frame section.\n"); duke@435: return; duke@435: } duke@435: // !!!!! !!!!! duke@435: // if(frame->_interpreter_frame_ptr_reg == NULL) { duke@435: // parse_err(SYNERR, "missing interpreter frame pointer definition in frame section.\n"); duke@435: // return; duke@435: // } duke@435: if(frame->_alignment == NULL) { duke@435: parse_err(SYNERR, "missing alignment definition in frame section.\n"); duke@435: return; duke@435: } duke@435: if(frame->_return_addr == NULL) { duke@435: parse_err(SYNERR, "missing return address location in frame section.\n"); duke@435: return; duke@435: } duke@435: if(frame->_in_preserve_slots == NULL) { duke@435: parse_err(SYNERR, "missing stack slot preservation definition in frame section.\n"); duke@435: return; duke@435: } duke@435: if(frame->_varargs_C_out_slots_killed == NULL) { duke@435: parse_err(SYNERR, "missing varargs C out slots killed definition in frame section.\n"); duke@435: return; duke@435: } duke@435: if(frame->_calling_convention == NULL) { duke@435: parse_err(SYNERR, "missing calling convention definition in frame section.\n"); duke@435: return; duke@435: } duke@435: if(frame->_return_value == NULL) { duke@435: parse_err(SYNERR, "missing return value definition in frame section.\n"); duke@435: return; duke@435: } duke@435: // Fill natives in identically with the Java versions if not present. duke@435: if(frame->_c_frame_pointer == NULL) { duke@435: frame->_c_frame_pointer = frame->_frame_pointer; duke@435: } duke@435: if(frame->_c_return_addr == NULL) { duke@435: frame->_c_return_addr = frame->_return_addr; duke@435: frame->_c_return_addr_loc = frame->_return_addr_loc; duke@435: } duke@435: if(frame->_c_calling_convention == NULL) { duke@435: frame->_c_calling_convention = frame->_calling_convention; duke@435: } duke@435: if(frame->_c_return_value == NULL) { duke@435: frame->_c_return_value = frame->_return_value; duke@435: } duke@435: duke@435: // Debug Stuff duke@435: if (_AD._adl_debug > 1) fprintf(stderr,"Frame Form: %s\n", desc); duke@435: duke@435: // Create the EncodeForm for the architecture description. duke@435: _AD.addForm(frame); duke@435: // skipws(); duke@435: } duke@435: duke@435: //------------------------------stack_dir_parse-------------------------------- duke@435: void ADLParser::stack_dir_parse(FrameForm *frame) { duke@435: char *direction = parse_one_arg("stack direction entry"); duke@435: if (strcmp(direction, "TOWARDS_LOW") == 0) { duke@435: frame->_direction = false; duke@435: } duke@435: else if (strcmp(direction, "TOWARDS_HIGH") == 0) { duke@435: frame->_direction = true; duke@435: } duke@435: else { duke@435: parse_err(SYNERR, "invalid value inside stack direction entry.\n"); duke@435: return; duke@435: } duke@435: } duke@435: duke@435: //------------------------------sync_stack_slots_parse------------------------- duke@435: void ADLParser::sync_stack_slots_parse(FrameForm *frame) { duke@435: // Assign value into frame form duke@435: frame->_sync_stack_slots = parse_one_arg("sync stack slots entry"); duke@435: } duke@435: duke@435: //------------------------------frame_pointer_parse---------------------------- duke@435: void ADLParser::frame_pointer_parse(FrameForm *frame, bool native) { duke@435: char *frame_pointer = parse_one_arg("frame pointer entry"); duke@435: // Assign value into frame form duke@435: if (native) { frame->_c_frame_pointer = frame_pointer; } duke@435: else { frame->_frame_pointer = frame_pointer; } duke@435: } duke@435: duke@435: //------------------------------interpreter_frame_pointer_parse---------------------------- duke@435: void ADLParser::interpreter_frame_pointer_parse(FrameForm *frame, bool native) { duke@435: frame->_interpreter_frame_pointer_reg = parse_one_arg("interpreter frame pointer entry"); duke@435: } duke@435: duke@435: //------------------------------inline_cache_parse----------------------------- duke@435: void ADLParser::inline_cache_parse(FrameForm *frame, bool native) { duke@435: frame->_inline_cache_reg = parse_one_arg("inline cache reg entry"); duke@435: } duke@435: duke@435: //------------------------------interpreter_method_oop_parse------------------ duke@435: void ADLParser::interpreter_method_oop_parse(FrameForm *frame, bool native) { duke@435: frame->_interpreter_method_oop_reg = parse_one_arg("method oop reg entry"); duke@435: } duke@435: duke@435: //------------------------------cisc_spilling_operand_parse--------------------- duke@435: void ADLParser::cisc_spilling_operand_name_parse(FrameForm *frame, bool native) { duke@435: frame->_cisc_spilling_operand_name = parse_one_arg("cisc spilling operand name"); duke@435: } duke@435: duke@435: //------------------------------stack_alignment_parse-------------------------- duke@435: void ADLParser::stack_alignment_parse(FrameForm *frame) { duke@435: char *alignment = parse_one_arg("stack alignment entry"); duke@435: // Assign value into frame duke@435: frame->_alignment = alignment; duke@435: } duke@435: duke@435: //------------------------------parse_one_arg------------------------------- duke@435: char *ADLParser::parse_one_arg(const char *description) { duke@435: char *token = NULL; duke@435: if(_curchar == '(') { duke@435: next_char(); duke@435: skipws(); duke@435: token = get_expr(description, ")"); duke@435: if (token == NULL) { duke@435: parse_err(SYNERR, "missing value inside %s.\n", description); duke@435: return NULL; duke@435: } duke@435: next_char(); // skip the close paren duke@435: if(_curchar != ';') { // check for semi-colon duke@435: parse_err(SYNERR, "missing %c in.\n", ';', description); duke@435: return NULL; duke@435: } duke@435: next_char(); // skip the semi-colon duke@435: } duke@435: else { duke@435: parse_err(SYNERR, "Missing %c in.\n", '(', description); duke@435: return NULL; duke@435: } duke@435: duke@435: trim(token); duke@435: return token; duke@435: } duke@435: duke@435: //------------------------------return_addr_parse------------------------------ duke@435: void ADLParser::return_addr_parse(FrameForm *frame, bool native) { duke@435: bool in_register = true; duke@435: if(_curchar == '(') { duke@435: next_char(); duke@435: skipws(); duke@435: char *token = get_ident(); duke@435: if (token == NULL) { duke@435: parse_err(SYNERR, "missing value inside return address entry.\n"); duke@435: return; duke@435: } duke@435: // check for valid values for stack/register duke@435: if (strcmp(token, "REG") == 0) { duke@435: in_register = true; duke@435: } duke@435: else if (strcmp(token, "STACK") == 0) { duke@435: in_register = false; duke@435: } duke@435: else { duke@435: parse_err(SYNERR, "invalid value inside return_address entry.\n"); duke@435: return; duke@435: } duke@435: if (native) { frame->_c_return_addr_loc = in_register; } duke@435: else { frame->_return_addr_loc = in_register; } duke@435: duke@435: // Parse expression that specifies register or stack position duke@435: skipws(); duke@435: char *token2 = get_expr("return address entry", ")"); duke@435: if (token2 == NULL) { duke@435: parse_err(SYNERR, "missing value inside return address entry.\n"); duke@435: return; duke@435: } duke@435: next_char(); // skip the close paren duke@435: if (native) { frame->_c_return_addr = token2; } duke@435: else { frame->_return_addr = token2; } duke@435: duke@435: if(_curchar != ';') { // check for semi-colon duke@435: parse_err(SYNERR, "missing %c in return address entry.\n", ';'); duke@435: return; duke@435: } duke@435: next_char(); // skip the semi-colon duke@435: } duke@435: else { duke@435: parse_err(SYNERR, "Missing %c in return_address entry.\n", '('); duke@435: } duke@435: } duke@435: duke@435: //------------------------------preserve_stack_parse--------------------------- duke@435: void ADLParser::preserve_stack_parse(FrameForm *frame) { duke@435: if(_curchar == '(') { duke@435: char *token = get_paren_expr("preserve_stack_slots"); duke@435: frame->_in_preserve_slots = token; duke@435: duke@435: if(_curchar != ';') { // check for semi-colon duke@435: parse_err(SYNERR, "missing %c in preserve stack slot entry.\n", ';'); duke@435: return; duke@435: } duke@435: next_char(); // skip the semi-colon duke@435: } duke@435: else { duke@435: parse_err(SYNERR, "Missing %c in preserve stack slot entry.\n", '('); duke@435: } duke@435: } duke@435: duke@435: //------------------------------calling_convention_parse----------------------- duke@435: char *ADLParser::calling_convention_parse() { duke@435: char *desc = NULL; // String representation of calling_convention duke@435: duke@435: skipws(); // Skip leading whitespace duke@435: if ( (desc = find_cpp_block("calling convention block")) == NULL ) { duke@435: parse_err(SYNERR, "incorrect or missing block for 'calling_convention'.\n"); duke@435: } duke@435: return desc; duke@435: } duke@435: duke@435: //------------------------------return_value_parse----------------------------- duke@435: char *ADLParser::return_value_parse() { duke@435: char *desc = NULL; // String representation of calling_convention duke@435: duke@435: skipws(); // Skip leading whitespace duke@435: if ( (desc = find_cpp_block("return value block")) == NULL ) { duke@435: parse_err(SYNERR, "incorrect or missing block for 'return_value'.\n"); duke@435: } duke@435: return desc; duke@435: } duke@435: duke@435: //------------------------------ins_pipe_parse--------------------------------- duke@435: void ADLParser::ins_pipe_parse(InstructForm &instr) { duke@435: char * ident; duke@435: duke@435: skipws(); duke@435: if ( _curchar != '(' ) { // Check for delimiter duke@435: parse_err(SYNERR, "missing \"(\" in ins_pipe definition\n"); duke@435: return; duke@435: } duke@435: duke@435: next_char(); duke@435: ident = get_ident(); // Grab next identifier duke@435: duke@435: if (ident == NULL) { duke@435: parse_err(SYNERR, "keyword identifier expected at %c\n", _curchar); duke@435: return; duke@435: } duke@435: duke@435: skipws(); duke@435: if ( _curchar != ')' ) { // Check for delimiter duke@435: parse_err(SYNERR, "missing \")\" in ins_pipe definition\n"); duke@435: return; duke@435: } duke@435: duke@435: next_char(); // skip the close paren duke@435: if(_curchar != ';') { // check for semi-colon duke@435: parse_err(SYNERR, "missing %c in return value entry.\n", ';'); duke@435: return; duke@435: } duke@435: next_char(); // skip the semi-colon duke@435: duke@435: // Check ident for validity duke@435: if (_AD._pipeline && !_AD._pipeline->_classlist.search(ident)) { duke@435: parse_err(SYNERR, "\"%s\" is not a valid pipeline class\n", ident); duke@435: return; duke@435: } duke@435: duke@435: // Add this instruction to the list in the pipeline class duke@435: _AD._pipeline->_classdict[ident]->is_pipeclass()->_instructs.addName(instr._ident); duke@435: duke@435: // Set the name of the pipeline class in the instruction duke@435: instr._ins_pipe = ident; duke@435: return; duke@435: } duke@435: duke@435: //------------------------------pipe_parse------------------------------------- duke@435: void ADLParser::pipe_parse(void) { duke@435: PipelineForm *pipeline; // Encode class for instruction/operand duke@435: char * ident; duke@435: duke@435: pipeline = new PipelineForm(); // Build new Source object duke@435: _AD.addForm(pipeline); duke@435: duke@435: skipws(); // Skip leading whitespace duke@435: // Check for block delimiter duke@435: if ( (_curchar != '%') duke@435: || ( next_char(), (_curchar != '{')) ) { duke@435: parse_err(SYNERR, "missing '%{' in pipeline definition\n"); duke@435: return; duke@435: } duke@435: next_char(); // Maintain the invariant duke@435: do { duke@435: ident = get_ident(); // Grab next identifier duke@435: if (ident == NULL) { duke@435: parse_err(SYNERR, "keyword identifier expected at %c\n", _curchar); duke@435: continue; duke@435: } duke@435: if (!strcmp(ident, "resources" )) resource_parse(*pipeline); duke@435: else if (!strcmp(ident, "pipe_desc" )) pipe_desc_parse(*pipeline); duke@435: else if (!strcmp(ident, "pipe_class")) pipe_class_parse(*pipeline); duke@435: else if (!strcmp(ident, "define")) { duke@435: skipws(); duke@435: if ( (_curchar != '%') duke@435: || ( next_char(), (_curchar != '{')) ) { duke@435: parse_err(SYNERR, "expected '%{'\n"); duke@435: return; duke@435: } duke@435: next_char(); skipws(); duke@435: duke@435: char *node_class = get_ident(); duke@435: if (node_class == NULL) { duke@435: parse_err(SYNERR, "expected identifier, found \"%c\"\n", _curchar); duke@435: return; duke@435: } duke@435: duke@435: skipws(); duke@435: if (_curchar != ',' && _curchar != '=') { duke@435: parse_err(SYNERR, "expected `=`, found '%c'\n", _curchar); duke@435: break; duke@435: } duke@435: next_char(); skipws(); duke@435: duke@435: char *pipe_class = get_ident(); duke@435: if (pipe_class == NULL) { duke@435: parse_err(SYNERR, "expected identifier, found \"%c\"\n", _curchar); duke@435: return; duke@435: } duke@435: if (_curchar != ';' ) { duke@435: parse_err(SYNERR, "expected `;`, found '%c'\n", _curchar); duke@435: break; duke@435: } duke@435: next_char(); // Skip over semi-colon duke@435: duke@435: skipws(); duke@435: if ( (_curchar != '%') duke@435: || ( next_char(), (_curchar != '}')) ) { duke@435: parse_err(SYNERR, "expected '%%}', found \"%c\"\n", _curchar); duke@435: } duke@435: next_char(); duke@435: duke@435: // Check ident for validity duke@435: if (_AD._pipeline && !_AD._pipeline->_classlist.search(pipe_class)) { duke@435: parse_err(SYNERR, "\"%s\" is not a valid pipeline class\n", pipe_class); duke@435: return; duke@435: } duke@435: duke@435: // Add this machine node to the list in the pipeline class duke@435: _AD._pipeline->_classdict[pipe_class]->is_pipeclass()->_instructs.addName(node_class); duke@435: duke@435: MachNodeForm *machnode = new MachNodeForm(node_class); // Create new machnode form duke@435: machnode->_machnode_pipe = pipe_class; duke@435: duke@435: _AD.addForm(machnode); duke@435: } duke@435: else if (!strcmp(ident, "attributes")) { duke@435: bool vsi_seen = false, bhds_seen = false; duke@435: duke@435: skipws(); duke@435: if ( (_curchar != '%') duke@435: || ( next_char(), (_curchar != '{')) ) { duke@435: parse_err(SYNERR, "expected '%{'\n"); duke@435: return; duke@435: } duke@435: next_char(); skipws(); duke@435: duke@435: while (_curchar != '%') { duke@435: ident = get_ident(); duke@435: if (ident == NULL) duke@435: break; duke@435: duke@435: if (!strcmp(ident, "variable_size_instructions")) { duke@435: skipws(); duke@435: if (_curchar == ';') { duke@435: next_char(); skipws(); duke@435: } duke@435: duke@435: pipeline->_variableSizeInstrs = true; duke@435: vsi_seen = true; duke@435: continue; duke@435: } duke@435: duke@435: if (!strcmp(ident, "fixed_size_instructions")) { duke@435: skipws(); duke@435: if (_curchar == ';') { duke@435: next_char(); skipws(); duke@435: } duke@435: duke@435: pipeline->_variableSizeInstrs = false; duke@435: vsi_seen = true; duke@435: continue; duke@435: } duke@435: duke@435: if (!strcmp(ident, "branch_has_delay_slot")) { duke@435: skipws(); duke@435: if (_curchar == ';') { duke@435: next_char(); skipws(); duke@435: } duke@435: duke@435: pipeline->_branchHasDelaySlot = true; duke@435: bhds_seen = true; duke@435: continue; duke@435: } duke@435: duke@435: if (!strcmp(ident, "max_instructions_per_bundle")) { duke@435: skipws(); duke@435: if (_curchar != '=') { duke@435: parse_err(SYNERR, "expected `=`\n"); duke@435: break; duke@435: } duke@435: duke@435: next_char(); skipws(); duke@435: pipeline->_maxInstrsPerBundle = get_int(); duke@435: skipws(); duke@435: duke@435: if (_curchar == ';') { duke@435: next_char(); skipws(); duke@435: } duke@435: duke@435: continue; duke@435: } duke@435: duke@435: if (!strcmp(ident, "max_bundles_per_cycle")) { duke@435: skipws(); duke@435: if (_curchar != '=') { duke@435: parse_err(SYNERR, "expected `=`\n"); duke@435: break; duke@435: } duke@435: duke@435: next_char(); skipws(); duke@435: pipeline->_maxBundlesPerCycle = get_int(); duke@435: skipws(); duke@435: duke@435: if (_curchar == ';') { duke@435: next_char(); skipws(); duke@435: } duke@435: duke@435: continue; duke@435: } duke@435: duke@435: if (!strcmp(ident, "instruction_unit_size")) { duke@435: skipws(); duke@435: if (_curchar != '=') { duke@435: parse_err(SYNERR, "expected `=`, found '%c'\n", _curchar); duke@435: break; duke@435: } duke@435: duke@435: next_char(); skipws(); duke@435: pipeline->_instrUnitSize = get_int(); duke@435: skipws(); duke@435: duke@435: if (_curchar == ';') { duke@435: next_char(); skipws(); duke@435: } duke@435: duke@435: continue; duke@435: } duke@435: duke@435: if (!strcmp(ident, "bundle_unit_size")) { duke@435: skipws(); duke@435: if (_curchar != '=') { duke@435: parse_err(SYNERR, "expected `=`, found '%c'\n", _curchar); duke@435: break; duke@435: } duke@435: duke@435: next_char(); skipws(); duke@435: pipeline->_bundleUnitSize = get_int(); duke@435: skipws(); duke@435: duke@435: if (_curchar == ';') { duke@435: next_char(); skipws(); duke@435: } duke@435: duke@435: continue; duke@435: } duke@435: duke@435: if (!strcmp(ident, "instruction_fetch_unit_size")) { duke@435: skipws(); duke@435: if (_curchar != '=') { duke@435: parse_err(SYNERR, "expected `=`, found '%c'\n", _curchar); duke@435: break; duke@435: } duke@435: duke@435: next_char(); skipws(); duke@435: pipeline->_instrFetchUnitSize = get_int(); duke@435: skipws(); duke@435: duke@435: if (_curchar == ';') { duke@435: next_char(); skipws(); duke@435: } duke@435: duke@435: continue; duke@435: } duke@435: duke@435: if (!strcmp(ident, "instruction_fetch_units")) { duke@435: skipws(); duke@435: if (_curchar != '=') { duke@435: parse_err(SYNERR, "expected `=`, found '%c'\n", _curchar); duke@435: break; duke@435: } duke@435: duke@435: next_char(); skipws(); duke@435: pipeline->_instrFetchUnits = get_int(); duke@435: skipws(); duke@435: duke@435: if (_curchar == ';') { duke@435: next_char(); skipws(); duke@435: } duke@435: duke@435: continue; duke@435: } duke@435: duke@435: if (!strcmp(ident, "nops")) { duke@435: skipws(); duke@435: if (_curchar != '(') { duke@435: parse_err(SYNERR, "expected `(`, found '%c'\n", _curchar); duke@435: break; duke@435: } duke@435: duke@435: next_char(); skipws(); duke@435: duke@435: while (_curchar != ')') { duke@435: ident = get_ident(); duke@435: if (ident == NULL) { duke@435: parse_err(SYNERR, "expected identifier for nop instruction, found '%c'\n", _curchar); duke@435: break; duke@435: } duke@435: duke@435: pipeline->_noplist.addName(ident); duke@435: pipeline->_nopcnt++; duke@435: skipws(); duke@435: duke@435: if (_curchar == ',') { duke@435: next_char(); skipws(); duke@435: } duke@435: } duke@435: duke@435: next_char(); skipws(); duke@435: duke@435: if (_curchar == ';') { duke@435: next_char(); skipws(); duke@435: } duke@435: duke@435: continue; duke@435: } duke@435: duke@435: parse_err(SYNERR, "unknown specifier \"%s\"\n", ident); duke@435: } duke@435: duke@435: if ( (_curchar != '%') duke@435: || ( next_char(), (_curchar != '}')) ) { duke@435: parse_err(SYNERR, "expected '%}', found \"%c\"\n", _curchar); duke@435: } duke@435: next_char(); skipws(); duke@435: duke@435: if (pipeline->_maxInstrsPerBundle == 0) duke@435: parse_err(SYNERR, "\"max_instructions_per_bundle\" unspecified\n"); duke@435: if (pipeline->_instrUnitSize == 0 && pipeline->_bundleUnitSize == 0) duke@435: parse_err(SYNERR, "\"instruction_unit_size\" and \"bundle_unit_size\" unspecified\n"); duke@435: if (pipeline->_instrFetchUnitSize == 0) duke@435: parse_err(SYNERR, "\"instruction_fetch_unit_size\" unspecified\n"); duke@435: if (pipeline->_instrFetchUnits == 0) duke@435: parse_err(SYNERR, "\"instruction_fetch_units\" unspecified\n"); duke@435: if (!vsi_seen) duke@435: parse_err(SYNERR, "\"variable_size_instruction\" or \"fixed_size_instruction\" unspecified\n"); duke@435: } duke@435: else { // Done with staticly defined parts of instruction definition duke@435: parse_err(SYNERR, "expected one of \"resources\", \"pipe_desc\", \"pipe_class\", found \"%s\"\n", ident); duke@435: return; duke@435: } duke@435: skipws(); duke@435: if (_curchar == ';') duke@435: skipws(); duke@435: } while(_curchar != '%'); duke@435: duke@435: next_char(); duke@435: if (_curchar != '}') { duke@435: parse_err(SYNERR, "missing \"%}\" in pipeline definition\n"); duke@435: return; duke@435: } duke@435: duke@435: next_char(); duke@435: } duke@435: duke@435: //------------------------------resource_parse---------------------------- duke@435: void ADLParser::resource_parse(PipelineForm &pipeline) { duke@435: ResourceForm *resource; duke@435: char * ident; duke@435: char * expr; duke@435: unsigned mask; duke@435: pipeline._rescount = 0; duke@435: duke@435: skipws(); // Skip leading whitespace duke@435: duke@435: if (_curchar != '(') { duke@435: parse_err(SYNERR, "missing \"(\" in resource definition\n"); duke@435: return; duke@435: } duke@435: duke@435: do { duke@435: next_char(); // Skip "(" or "," duke@435: ident = get_ident(); // Grab next identifier duke@435: duke@435: if (ident == NULL) { duke@435: parse_err(SYNERR, "keyword identifier expected at \"%c\"\n", _curchar); duke@435: return; duke@435: } duke@435: skipws(); duke@435: duke@435: if (_curchar != '=') { duke@435: mask = (1 << pipeline._rescount++); duke@435: } duke@435: else { duke@435: next_char(); skipws(); duke@435: expr = get_ident(); // Grab next identifier duke@435: if (expr == NULL) { duke@435: parse_err(SYNERR, "keyword identifier expected at \"%c\"\n", _curchar); duke@435: return; duke@435: } duke@435: resource = (ResourceForm *) pipeline._resdict[expr]; duke@435: if (resource == NULL) { duke@435: parse_err(SYNERR, "resource \"%s\" is not defined\n", expr); duke@435: return; duke@435: } duke@435: mask = resource->mask(); duke@435: duke@435: skipws(); duke@435: while (_curchar == '|') { duke@435: next_char(); skipws(); duke@435: duke@435: expr = get_ident(); // Grab next identifier duke@435: if (expr == NULL) { duke@435: parse_err(SYNERR, "keyword identifier expected at \"%c\"\n", _curchar); duke@435: return; duke@435: } duke@435: duke@435: resource = (ResourceForm *) pipeline._resdict[expr]; // Look up the value duke@435: if (resource == NULL) { duke@435: parse_err(SYNERR, "resource \"%s\" is not defined\n", expr); duke@435: return; duke@435: } duke@435: duke@435: mask |= resource->mask(); duke@435: skipws(); duke@435: } duke@435: } duke@435: duke@435: resource = new ResourceForm(mask); duke@435: duke@435: pipeline._resdict.Insert(ident, resource); duke@435: pipeline._reslist.addName(ident); duke@435: } while (_curchar == ','); duke@435: duke@435: if (_curchar != ')') { duke@435: parse_err(SYNERR, "\")\" expected at \"%c\"\n", _curchar); duke@435: return; duke@435: } duke@435: duke@435: next_char(); // Skip ")" duke@435: if (_curchar == ';') duke@435: next_char(); // Skip ";" duke@435: } duke@435: duke@435: //------------------------------resource_parse---------------------------- duke@435: void ADLParser::pipe_desc_parse(PipelineForm &pipeline) { duke@435: char * ident; duke@435: duke@435: skipws(); // Skip leading whitespace duke@435: duke@435: if (_curchar != '(') { duke@435: parse_err(SYNERR, "missing \"(\" in pipe_desc definition\n"); duke@435: return; duke@435: } duke@435: duke@435: do { duke@435: next_char(); // Skip "(" or "," duke@435: ident = get_ident(); // Grab next identifier duke@435: if (ident == NULL) { duke@435: parse_err(SYNERR, "keyword identifier expected at \"%c\"\n", _curchar); duke@435: return; duke@435: } duke@435: duke@435: // Add the name to the list duke@435: pipeline._stages.addName(ident); duke@435: pipeline._stagecnt++; duke@435: duke@435: skipws(); duke@435: } while (_curchar == ','); duke@435: duke@435: if (_curchar != ')') { duke@435: parse_err(SYNERR, "\")\" expected at \"%c\"\n", _curchar); duke@435: return; duke@435: } duke@435: duke@435: next_char(); // Skip ")" duke@435: if (_curchar == ';') duke@435: next_char(); // Skip ";" duke@435: } duke@435: duke@435: //------------------------------pipe_class_parse-------------------------- duke@435: void ADLParser::pipe_class_parse(PipelineForm &pipeline) { duke@435: PipeClassForm *pipe_class; duke@435: char * ident; duke@435: char * stage; duke@435: char * read_or_write; duke@435: int is_write; duke@435: int is_read; duke@435: OperandForm *oper; duke@435: duke@435: skipws(); // Skip leading whitespace duke@435: duke@435: ident = get_ident(); // Grab next identifier duke@435: duke@435: if (ident == NULL) { duke@435: parse_err(SYNERR, "keyword identifier expected at \"%c\"\n", _curchar); duke@435: return; duke@435: } duke@435: duke@435: // Create a record for the pipe_class duke@435: pipe_class = new PipeClassForm(ident, ++pipeline._classcnt); duke@435: pipeline._classdict.Insert(ident, pipe_class); duke@435: pipeline._classlist.addName(ident); duke@435: duke@435: // Then get the operands duke@435: skipws(); duke@435: if (_curchar != '(') { duke@435: parse_err(SYNERR, "missing \"(\" in pipe_class definition\n"); duke@435: } duke@435: // Parse the operand list duke@435: else get_oplist(pipe_class->_parameters, pipe_class->_localNames); duke@435: skipws(); // Skip leading whitespace duke@435: // Check for block delimiter duke@435: if ( (_curchar != '%') duke@435: || ( next_char(), (_curchar != '{')) ) { duke@435: parse_err(SYNERR, "missing \"%{\" in pipe_class definition\n"); duke@435: return; duke@435: } duke@435: next_char(); duke@435: duke@435: do { duke@435: ident = get_ident(); // Grab next identifier duke@435: if (ident == NULL) { duke@435: parse_err(SYNERR, "keyword identifier expected at \"%c\"\n", _curchar); duke@435: continue; duke@435: } duke@435: skipws(); duke@435: duke@435: if (!strcmp(ident, "fixed_latency")) { duke@435: skipws(); duke@435: if (_curchar != '(') { duke@435: parse_err(SYNERR, "missing \"(\" in latency definition\n"); duke@435: return; duke@435: } duke@435: next_char(); skipws(); duke@435: if( !isdigit(_curchar) ) { duke@435: parse_err(SYNERR, "number expected for \"%c\" in latency definition\n", _curchar); duke@435: return; duke@435: } duke@435: int fixed_latency = get_int(); duke@435: skipws(); duke@435: if (_curchar != ')') { duke@435: parse_err(SYNERR, "missing \")\" in latency definition\n"); duke@435: return; duke@435: } duke@435: next_char(); skipws(); duke@435: if (_curchar != ';') { duke@435: parse_err(SYNERR, "missing \";\" in latency definition\n"); duke@435: return; duke@435: } duke@435: duke@435: pipe_class->setFixedLatency(fixed_latency); duke@435: next_char(); skipws(); duke@435: continue; duke@435: } duke@435: duke@435: if (!strcmp(ident, "zero_instructions") || duke@435: !strcmp(ident, "no_instructions")) { duke@435: skipws(); duke@435: if (_curchar != ';') { duke@435: parse_err(SYNERR, "missing \";\" in latency definition\n"); duke@435: return; duke@435: } duke@435: duke@435: pipe_class->setInstructionCount(0); duke@435: next_char(); skipws(); duke@435: continue; duke@435: } duke@435: duke@435: if (!strcmp(ident, "one_instruction_with_delay_slot") || duke@435: !strcmp(ident, "single_instruction_with_delay_slot")) { duke@435: skipws(); duke@435: if (_curchar != ';') { duke@435: parse_err(SYNERR, "missing \";\" in latency definition\n"); duke@435: return; duke@435: } duke@435: duke@435: pipe_class->setInstructionCount(1); duke@435: pipe_class->setBranchDelay(true); duke@435: next_char(); skipws(); duke@435: continue; duke@435: } duke@435: duke@435: if (!strcmp(ident, "one_instruction") || duke@435: !strcmp(ident, "single_instruction")) { duke@435: skipws(); duke@435: if (_curchar != ';') { duke@435: parse_err(SYNERR, "missing \";\" in latency definition\n"); duke@435: return; duke@435: } duke@435: duke@435: pipe_class->setInstructionCount(1); duke@435: next_char(); skipws(); duke@435: continue; duke@435: } duke@435: duke@435: if (!strcmp(ident, "instructions_in_first_bundle") || duke@435: !strcmp(ident, "instruction_count")) { duke@435: skipws(); duke@435: duke@435: int number_of_instructions = 1; duke@435: duke@435: if (_curchar != '(') { duke@435: parse_err(SYNERR, "\"(\" expected at \"%c\"\n", _curchar); duke@435: continue; duke@435: } duke@435: duke@435: next_char(); skipws(); duke@435: number_of_instructions = get_int(); duke@435: duke@435: skipws(); duke@435: if (_curchar != ')') { duke@435: parse_err(SYNERR, "\")\" expected at \"%c\"\n", _curchar); duke@435: continue; duke@435: } duke@435: duke@435: next_char(); skipws(); duke@435: if (_curchar != ';') { duke@435: parse_err(SYNERR, "missing \";\" in latency definition\n"); duke@435: return; duke@435: } duke@435: duke@435: pipe_class->setInstructionCount(number_of_instructions); duke@435: next_char(); skipws(); duke@435: continue; duke@435: } duke@435: duke@435: if (!strcmp(ident, "multiple_bundles")) { duke@435: skipws(); duke@435: if (_curchar != ';') { duke@435: parse_err(SYNERR, "missing \";\" after multiple bundles\n"); duke@435: return; duke@435: } duke@435: duke@435: pipe_class->setMultipleBundles(true); duke@435: next_char(); skipws(); duke@435: continue; duke@435: } duke@435: duke@435: if (!strcmp(ident, "has_delay_slot")) { duke@435: skipws(); duke@435: if (_curchar != ';') { duke@435: parse_err(SYNERR, "missing \";\" after \"has_delay_slot\"\n"); duke@435: return; duke@435: } duke@435: duke@435: pipe_class->setBranchDelay(true); duke@435: next_char(); skipws(); duke@435: continue; duke@435: } duke@435: duke@435: if (!strcmp(ident, "force_serialization")) { duke@435: skipws(); duke@435: if (_curchar != ';') { duke@435: parse_err(SYNERR, "missing \";\" after \"force_serialization\"\n"); duke@435: return; duke@435: } duke@435: duke@435: pipe_class->setForceSerialization(true); duke@435: next_char(); skipws(); duke@435: continue; duke@435: } duke@435: duke@435: if (!strcmp(ident, "may_have_no_code")) { duke@435: skipws(); duke@435: if (_curchar != ';') { duke@435: parse_err(SYNERR, "missing \";\" after \"may_have_no_code\"\n"); duke@435: return; duke@435: } duke@435: duke@435: pipe_class->setMayHaveNoCode(true); duke@435: next_char(); skipws(); duke@435: continue; duke@435: } duke@435: duke@435: const Form *parm = pipe_class->_localNames[ident]; duke@435: if (parm != NULL) { duke@435: oper = parm->is_operand(); duke@435: if (oper == NULL && !parm->is_opclass()) { duke@435: parse_err(SYNERR, "operand name expected at %s\n", ident); duke@435: continue; duke@435: } duke@435: duke@435: if (_curchar != ':') { duke@435: parse_err(SYNERR, "\":\" expected at \"%c\"\n", _curchar); duke@435: continue; duke@435: } duke@435: next_char(); skipws(); duke@435: stage = get_ident(); duke@435: if (stage == NULL) { duke@435: parse_err(SYNERR, "pipeline stage identifier expected at \"%c\"\n", _curchar); duke@435: continue; duke@435: } duke@435: duke@435: skipws(); duke@435: if (_curchar != '(') { duke@435: parse_err(SYNERR, "\"(\" expected at \"%c\"\n", _curchar); duke@435: continue; duke@435: } duke@435: duke@435: next_char(); duke@435: read_or_write = get_ident(); duke@435: if (read_or_write == NULL) { duke@435: parse_err(SYNERR, "\"read\" or \"write\" expected at \"%c\"\n", _curchar); duke@435: continue; duke@435: } duke@435: duke@435: is_read = strcmp(read_or_write, "read") == 0; duke@435: is_write = strcmp(read_or_write, "write") == 0; duke@435: if (!is_read && !is_write) { duke@435: parse_err(SYNERR, "\"read\" or \"write\" expected at \"%c\"\n", _curchar); duke@435: continue; duke@435: } duke@435: duke@435: skipws(); duke@435: if (_curchar != ')') { duke@435: parse_err(SYNERR, "\")\" expected at \"%c\"\n", _curchar); duke@435: continue; duke@435: } duke@435: duke@435: next_char(); skipws(); duke@435: int more_instrs = 0; duke@435: if (_curchar == '+') { duke@435: next_char(); skipws(); duke@435: if (_curchar < '0' || _curchar > '9') { duke@435: parse_err(SYNERR, " expected at \"%c\"\n", _curchar); duke@435: continue; duke@435: } duke@435: while (_curchar >= '0' && _curchar <= '9') { duke@435: more_instrs *= 10; duke@435: more_instrs += _curchar - '0'; duke@435: next_char(); duke@435: } duke@435: skipws(); duke@435: } duke@435: duke@435: PipeClassOperandForm *pipe_operand = new PipeClassOperandForm(stage, is_write, more_instrs); duke@435: pipe_class->_localUsage.Insert(ident, pipe_operand); duke@435: duke@435: if (_curchar == '%') duke@435: continue; duke@435: duke@435: if (_curchar != ';') { duke@435: parse_err(SYNERR, "\";\" expected at \"%c\"\n", _curchar); duke@435: continue; duke@435: } duke@435: next_char(); skipws(); duke@435: continue; duke@435: } duke@435: duke@435: // Scan for Resource Specifier duke@435: const Form *res = pipeline._resdict[ident]; duke@435: if (res != NULL) { duke@435: int cyclecnt = 1; duke@435: if (_curchar != ':') { duke@435: parse_err(SYNERR, "\":\" expected at \"%c\"\n", _curchar); duke@435: continue; duke@435: } duke@435: next_char(); skipws(); duke@435: stage = get_ident(); duke@435: if (stage == NULL) { duke@435: parse_err(SYNERR, "pipeline stage identifier expected at \"%c\"\n", _curchar); duke@435: continue; duke@435: } duke@435: duke@435: skipws(); duke@435: if (_curchar == '(') { duke@435: next_char(); duke@435: cyclecnt = get_int(); duke@435: duke@435: skipws(); duke@435: if (_curchar != ')') { duke@435: parse_err(SYNERR, "\")\" expected at \"%c\"\n", _curchar); duke@435: continue; duke@435: } duke@435: duke@435: next_char(); skipws(); duke@435: } duke@435: duke@435: PipeClassResourceForm *resource = new PipeClassResourceForm(ident, stage, cyclecnt); duke@435: int stagenum = pipeline._stages.index(stage); duke@435: if (pipeline._maxcycleused < (stagenum+cyclecnt)) duke@435: pipeline._maxcycleused = (stagenum+cyclecnt); duke@435: pipe_class->_resUsage.addForm(resource); duke@435: duke@435: if (_curchar == '%') duke@435: continue; duke@435: duke@435: if (_curchar != ';') { duke@435: parse_err(SYNERR, "\";\" expected at \"%c\"\n", _curchar); duke@435: continue; duke@435: } duke@435: next_char(); skipws(); duke@435: continue; duke@435: } duke@435: duke@435: parse_err(SYNERR, "resource expected at \"%s\"\n", ident); duke@435: return; duke@435: } while(_curchar != '%'); duke@435: duke@435: next_char(); duke@435: if (_curchar != '}') { duke@435: parse_err(SYNERR, "missing \"%}\" in pipe_class definition\n"); duke@435: return; duke@435: } duke@435: duke@435: next_char(); duke@435: } duke@435: duke@435: //------------------------------peep_parse------------------------------------- duke@435: void ADLParser::peep_parse(void) { duke@435: Peephole *peep; // Pointer to current peephole rule form duke@435: char *desc = NULL; // String representation of rule duke@435: duke@435: skipws(); // Skip leading whitespace duke@435: duke@435: peep = new Peephole(); // Build new Peephole object duke@435: // Check for open block sequence duke@435: skipws(); // Skip leading whitespace duke@435: if (_curchar == '%' && *(_ptr+1) == '{') { duke@435: next_char(); next_char(); // Skip "%{" duke@435: skipws(); duke@435: while (_curchar != '%' && *(_ptr+1) != '}') { duke@435: char *token = get_ident(); duke@435: if (token == NULL) { duke@435: parse_err(SYNERR, "missing identifier inside peephole rule.\n"); duke@435: return; duke@435: } duke@435: // check for legal subsections of peephole rule duke@435: if (strcmp(token,"peepmatch")==0) { duke@435: peep_match_parse(*peep); } duke@435: else if (strcmp(token,"peepconstraint")==0) { duke@435: peep_constraint_parse(*peep); } duke@435: else if (strcmp(token,"peepreplace")==0) { duke@435: peep_replace_parse(*peep); } duke@435: else { duke@435: parse_err(SYNERR, "expected peepmatch, peepconstraint, or peepreplace for identifier %s.\n", token); duke@435: } duke@435: skipws(); duke@435: } duke@435: } duke@435: else { duke@435: parse_err(SYNERR, "Missing %%{ ... %%} block after peephole keyword.\n"); duke@435: return; duke@435: } duke@435: next_char(); // Skip past '%' duke@435: next_char(); // Skip past '}' duke@435: } duke@435: duke@435: // ******************** Private Level 2 Parse Functions ******************** duke@435: //------------------------------constraint_parse------------------------------ duke@435: Constraint *ADLParser::constraint_parse(void) { duke@435: char *func; duke@435: char *arg; duke@435: duke@435: // Check for constraint expression duke@435: skipws(); duke@435: if (_curchar != '(') { duke@435: parse_err(SYNERR, "missing constraint expression, (...)\n"); duke@435: return NULL; duke@435: } duke@435: next_char(); // Skip past '(' duke@435: duke@435: // Get constraint function duke@435: skipws(); duke@435: func = get_ident(); duke@435: if (func == NULL) { duke@435: parse_err(SYNERR, "missing function in constraint expression.\n"); duke@435: return NULL; duke@435: } duke@435: if (strcmp(func,"ALLOC_IN_RC")==0 duke@435: || strcmp(func,"IS_R_CLASS")==0) { duke@435: // Check for '(' before argument duke@435: skipws(); duke@435: if (_curchar != '(') { duke@435: parse_err(SYNERR, "missing '(' for constraint function's argument.\n"); duke@435: return NULL; duke@435: } duke@435: next_char(); duke@435: duke@435: // Get it's argument duke@435: skipws(); duke@435: arg = get_ident(); duke@435: if (arg == NULL) { duke@435: parse_err(SYNERR, "missing argument for constraint function %s\n",func); duke@435: return NULL; duke@435: } duke@435: // Check for ')' after argument duke@435: skipws(); duke@435: if (_curchar != ')') { duke@435: parse_err(SYNERR, "missing ')' after constraint function argument %s\n",arg); duke@435: return NULL; duke@435: } duke@435: next_char(); duke@435: } else { duke@435: parse_err(SYNERR, "Invalid constraint function %s\n",func); duke@435: return NULL; duke@435: } duke@435: duke@435: // Check for closing paren and ';' duke@435: skipws(); duke@435: if (_curchar != ')') { duke@435: parse_err(SYNERR, "Missing ')' for constraint function %s\n",func); duke@435: return NULL; duke@435: } duke@435: next_char(); duke@435: skipws(); duke@435: if (_curchar != ';') { duke@435: parse_err(SYNERR, "Missing ';' after constraint.\n"); duke@435: return NULL; duke@435: } duke@435: next_char(); duke@435: duke@435: // Create new "Constraint" duke@435: Constraint *constraint = new Constraint(func,arg); duke@435: return constraint; duke@435: } duke@435: duke@435: //------------------------------constr_parse----------------------------------- duke@435: ConstructRule *ADLParser::construct_parse(void) { duke@435: return NULL; duke@435: } duke@435: duke@435: duke@435: //------------------------------reg_def_parse---------------------------------- duke@435: void ADLParser::reg_def_parse(void) { duke@435: char *rname; // Name of register being defined duke@435: duke@435: // Get register name duke@435: skipws(); // Skip whitespace duke@435: rname = get_ident(); duke@435: if (rname == NULL) { duke@435: parse_err(SYNERR, "missing register name after reg_def\n"); duke@435: return; duke@435: } duke@435: duke@435: // Check for definition of register calling convention (save on call, ...), duke@435: // register save type, and register encoding value. duke@435: skipws(); duke@435: char *callconv = NULL; duke@435: char *c_conv = NULL; duke@435: char *idealtype = NULL; duke@435: char *encoding = NULL; duke@435: char *concrete = NULL; duke@435: if (_curchar == '(') { duke@435: next_char(); duke@435: callconv = get_ident(); duke@435: // Parse the internal calling convention, must be NS, SOC, SOE, or AS. duke@435: if (callconv == NULL) { duke@435: parse_err(SYNERR, "missing register calling convention value\n"); duke@435: return; duke@435: } duke@435: if(strcmp(callconv, "SOC") && strcmp(callconv,"SOE") && duke@435: strcmp(callconv, "NS") && strcmp(callconv, "AS")) { duke@435: parse_err(SYNERR, "invalid value for register calling convention\n"); duke@435: } duke@435: skipws(); duke@435: if (_curchar != ',') { duke@435: parse_err(SYNERR, "missing comma in register definition statement\n"); duke@435: return; duke@435: } duke@435: next_char(); duke@435: duke@435: // Parse the native calling convention, must be NS, SOC, SOE, AS duke@435: c_conv = get_ident(); duke@435: if (c_conv == NULL) { duke@435: parse_err(SYNERR, "missing register native calling convention value\n"); duke@435: return; duke@435: } duke@435: if(strcmp(c_conv, "SOC") && strcmp(c_conv,"SOE") && duke@435: strcmp(c_conv, "NS") && strcmp(c_conv, "AS")) { duke@435: parse_err(SYNERR, "invalid value for register calling convention\n"); duke@435: } duke@435: skipws(); duke@435: if (_curchar != ',') { duke@435: parse_err(SYNERR, "missing comma in register definition statement\n"); duke@435: return; duke@435: } duke@435: next_char(); duke@435: skipws(); duke@435: duke@435: // Parse the ideal save type duke@435: idealtype = get_ident(); duke@435: if (idealtype == NULL) { duke@435: parse_err(SYNERR, "missing register save type value\n"); duke@435: return; duke@435: } duke@435: skipws(); duke@435: if (_curchar != ',') { duke@435: parse_err(SYNERR, "missing comma in register definition statement\n"); duke@435: return; duke@435: } duke@435: next_char(); duke@435: skipws(); duke@435: duke@435: // Parse the encoding value duke@435: encoding = get_expr("encoding", ","); duke@435: if (encoding == NULL) { duke@435: parse_err(SYNERR, "missing register encoding value\n"); duke@435: return; duke@435: } duke@435: trim(encoding); duke@435: if (_curchar != ',') { duke@435: parse_err(SYNERR, "missing comma in register definition statement\n"); duke@435: return; duke@435: } duke@435: next_char(); duke@435: skipws(); duke@435: // Parse the concrete name type duke@435: // concrete = get_ident(); duke@435: concrete = get_expr("concrete", ")"); duke@435: if (concrete == NULL) { duke@435: parse_err(SYNERR, "missing vm register name value\n"); duke@435: return; duke@435: } duke@435: duke@435: if (_curchar != ')') { duke@435: parse_err(SYNERR, "missing ')' in register definition statement\n"); duke@435: return; duke@435: } duke@435: next_char(); duke@435: } duke@435: duke@435: // Check for closing ';' duke@435: skipws(); duke@435: if (_curchar != ';') { duke@435: parse_err(SYNERR, "missing ';' after reg_def\n"); duke@435: return; duke@435: } duke@435: next_char(); // move past ';' duke@435: duke@435: // Debug Stuff duke@435: if (_AD._adl_debug > 1) { duke@435: fprintf(stderr,"Register Definition: %s ( %s, %s %s )\n", rname, duke@435: (callconv ? callconv : ""), (c_conv ? c_conv : ""), concrete); duke@435: } duke@435: duke@435: // Record new register definition. duke@435: _AD._register->addRegDef(rname, callconv, c_conv, idealtype, encoding, concrete); duke@435: return; duke@435: } duke@435: duke@435: //------------------------------reg_class_parse-------------------------------- duke@435: void ADLParser::reg_class_parse(void) { duke@435: char *cname; // Name of register class being defined duke@435: duke@435: // Get register class name duke@435: skipws(); // Skip leading whitespace duke@435: cname = get_ident(); duke@435: if (cname == NULL) { duke@435: parse_err(SYNERR, "missing register class name after 'reg_class'\n"); duke@435: return; duke@435: } duke@435: // Debug Stuff duke@435: if (_AD._adl_debug >1) fprintf(stderr,"Register Class: %s\n", cname); duke@435: duke@435: RegClass *reg_class = _AD._register->addRegClass(cname); duke@435: duke@435: // Collect registers in class duke@435: skipws(); duke@435: if (_curchar == '(') { duke@435: next_char(); // Skip '(' duke@435: skipws(); duke@435: while (_curchar != ')') { duke@435: char *rname = get_ident(); duke@435: if (rname==NULL) { duke@435: parse_err(SYNERR, "missing identifier inside reg_class list.\n"); duke@435: return; duke@435: } duke@435: RegDef *regDef = _AD._register->getRegDef(rname); jrose@910: if (!regDef) { jrose@910: parse_err(SEMERR, "unknown identifier %s inside reg_class list.\n", rname); jrose@910: } else { jrose@910: reg_class->addReg(regDef); // add regDef to regClass jrose@910: } duke@435: duke@435: // Check for ',' and position to next token. duke@435: skipws(); duke@435: if (_curchar == ',') { duke@435: next_char(); // Skip trailing ',' duke@435: skipws(); duke@435: } duke@435: } duke@435: next_char(); // Skip closing ')' duke@435: } duke@435: duke@435: // Check for terminating ';' duke@435: skipws(); duke@435: if (_curchar != ';') { duke@435: parse_err(SYNERR, "missing ';' at end of reg_class definition.\n"); duke@435: return; duke@435: } duke@435: next_char(); // Skip trailing ';' duke@435: duke@435: // Check RegClass size, must be <= 32 registers in class. duke@435: duke@435: return; duke@435: } duke@435: duke@435: //------------------------------alloc_class_parse------------------------------ duke@435: void ADLParser::alloc_class_parse(void) { duke@435: char *name; // Name of allocation class being defined duke@435: duke@435: // Get allocation class name duke@435: skipws(); // Skip leading whitespace duke@435: name = get_ident(); duke@435: if (name == NULL) { duke@435: parse_err(SYNERR, "missing allocation class name after 'reg_class'\n"); duke@435: return; duke@435: } duke@435: // Debug Stuff duke@435: if (_AD._adl_debug >1) fprintf(stderr,"Allocation Class: %s\n", name); duke@435: duke@435: AllocClass *alloc_class = _AD._register->addAllocClass(name); duke@435: duke@435: // Collect registers in class duke@435: skipws(); duke@435: if (_curchar == '(') { duke@435: next_char(); // Skip '(' duke@435: skipws(); duke@435: while (_curchar != ')') { duke@435: char *rname = get_ident(); duke@435: if (rname==NULL) { duke@435: parse_err(SYNERR, "missing identifier inside reg_class list.\n"); duke@435: return; duke@435: } duke@435: // Check if name is a RegDef duke@435: RegDef *regDef = _AD._register->getRegDef(rname); duke@435: if (regDef) { duke@435: alloc_class->addReg(regDef); // add regDef to allocClass duke@435: } else { duke@435: duke@435: // name must be a RegDef or a RegClass duke@435: parse_err(SYNERR, "name %s should be a previously defined reg_def.\n", rname); duke@435: return; duke@435: } duke@435: duke@435: // Check for ',' and position to next token. duke@435: skipws(); duke@435: if (_curchar == ',') { duke@435: next_char(); // Skip trailing ',' duke@435: skipws(); duke@435: } duke@435: } duke@435: next_char(); // Skip closing ')' duke@435: } duke@435: duke@435: // Check for terminating ';' duke@435: skipws(); duke@435: if (_curchar != ';') { duke@435: parse_err(SYNERR, "missing ';' at end of reg_class definition.\n"); duke@435: return; duke@435: } duke@435: next_char(); // Skip trailing ';' duke@435: duke@435: return; duke@435: } duke@435: duke@435: //------------------------------peep_match_child_parse------------------------- duke@435: InstructForm *ADLParser::peep_match_child_parse(PeepMatch &match, int parent, int &position, int input){ duke@435: char *token = NULL; duke@435: int lparen = 0; // keep track of parenthesis nesting depth duke@435: int rparen = 0; // position of instruction at this depth duke@435: InstructForm *inst_seen = NULL; duke@435: InstructForm *child_seen = NULL; duke@435: duke@435: // Walk the match tree, duke@435: // Record duke@435: while ( lparen >= rparen ) { duke@435: skipws(); duke@435: // Left paren signals start of an input, collect with recursive call duke@435: if (_curchar == '(') { duke@435: ++lparen; duke@435: next_char(); duke@435: child_seen = peep_match_child_parse(match, parent, position, rparen); duke@435: } duke@435: // Right paren signals end of an input, may be more duke@435: else if (_curchar == ')') { duke@435: ++rparen; duke@435: if( rparen == lparen ) { // IF rparen matches an lparen I've seen duke@435: next_char(); // move past ')' duke@435: } else { // ELSE leave ')' for parent duke@435: assert( rparen == lparen + 1, "Should only see one extra ')'"); duke@435: // if an instruction was not specified for this paren-pair duke@435: if( ! inst_seen ) { // record signal entry duke@435: match.add_instruction( parent, position, NameList::_signal, input ); duke@435: ++position; duke@435: } duke@435: // ++input; // TEMPORARY duke@435: return inst_seen; duke@435: } duke@435: } duke@435: // if no parens, then check for instruction name duke@435: // This instruction is the parent of a sub-tree duke@435: else if ((token = get_ident_dup()) != NULL) { duke@435: const Form *form = _AD._globalNames[token]; duke@435: if (form) { duke@435: InstructForm *inst = form->is_instruction(); duke@435: // Record the first instruction at this level duke@435: if( inst_seen == NULL ) { duke@435: inst_seen = inst; duke@435: } duke@435: if (inst) { duke@435: match.add_instruction( parent, position, token, input ); duke@435: parent = position; duke@435: ++position; duke@435: } else { duke@435: parse_err(SYNERR, "instruction name expected at identifier %s.\n", duke@435: token); duke@435: return inst_seen; duke@435: } duke@435: } duke@435: else { duke@435: parse_err(SYNERR, "missing identifier in peepmatch rule.\n"); duke@435: return NULL; duke@435: } duke@435: } duke@435: else { duke@435: parse_err(SYNERR, "missing identifier in peepmatch rule.\n"); duke@435: return NULL; duke@435: } duke@435: duke@435: } // end while duke@435: duke@435: assert( false, "ShouldNotReachHere();"); duke@435: return NULL; duke@435: } duke@435: duke@435: //------------------------------peep_match_parse------------------------------- duke@435: // Syntax for a peepmatch rule duke@435: // duke@435: // peepmatch ( root_instr_name [(instruction subtree)] [,(instruction subtree)]* ); duke@435: // duke@435: void ADLParser::peep_match_parse(Peephole &peep) { duke@435: duke@435: skipws(); duke@435: // Check the structure of the rule duke@435: // Check for open paren duke@435: if (_curchar != '(') { duke@435: parse_err(SYNERR, "missing '(' at start of peepmatch rule.\n"); duke@435: return; duke@435: } duke@435: next_char(); // skip '(' duke@435: duke@435: // Construct PeepMatch and parse the peepmatch rule. duke@435: PeepMatch *match = new PeepMatch(_ptr); duke@435: int parent = -1; // parent of root duke@435: int position = 0; // zero-based positions duke@435: int input = 0; // input position in parent's operands duke@435: InstructForm *root= peep_match_child_parse( *match, parent, position, input); duke@435: if( root == NULL ) { duke@435: parse_err(SYNERR, "missing instruction-name at start of peepmatch.\n"); duke@435: return; duke@435: } duke@435: duke@435: if( _curchar != ')' ) { duke@435: parse_err(SYNERR, "missing ')' at end of peepmatch.\n"); duke@435: return; duke@435: } duke@435: next_char(); // skip ')' duke@435: duke@435: // Check for closing semicolon duke@435: skipws(); duke@435: if( _curchar != ';' ) { duke@435: parse_err(SYNERR, "missing ';' at end of peepmatch.\n"); duke@435: return; duke@435: } duke@435: next_char(); // skip ';' duke@435: duke@435: // Store match into peep, and store peep into instruction duke@435: peep.add_match(match); duke@435: root->append_peephole(&peep); duke@435: } duke@435: duke@435: //------------------------------peep_constraint_parse-------------------------- duke@435: // Syntax for a peepconstraint rule duke@435: // A parenthesized list of relations between operands in peepmatch subtree duke@435: // duke@435: // peepconstraint %{ duke@435: // (instruction_number.operand_name duke@435: // relational_op duke@435: // instruction_number.operand_name OR register_name duke@435: // [, ...] ); duke@435: // duke@435: // // instruction numbers are zero-based using topological order in peepmatch duke@435: // duke@435: void ADLParser::peep_constraint_parse(Peephole &peep) { duke@435: duke@435: skipws(); duke@435: // Check the structure of the rule duke@435: // Check for open paren duke@435: if (_curchar != '(') { duke@435: parse_err(SYNERR, "missing '(' at start of peepconstraint rule.\n"); duke@435: return; duke@435: } duke@435: else { duke@435: next_char(); // Skip '(' duke@435: } duke@435: duke@435: // Check for a constraint duke@435: skipws(); duke@435: while( _curchar != ')' ) { duke@435: // Get information on the left instruction and its operand duke@435: // left-instructions's number twisti@1038: int left_inst = get_int(); duke@435: // Left-instruction's operand duke@435: skipws(); duke@435: if( _curchar != '.' ) { duke@435: parse_err(SYNERR, "missing '.' in peepconstraint after instruction number.\n"); duke@435: return; duke@435: } duke@435: next_char(); // Skip '.' duke@435: char *left_op = get_ident_dup(); duke@435: duke@435: skipws(); duke@435: // Collect relational operator duke@435: char *relation = get_relation_dup(); duke@435: duke@435: skipws(); duke@435: // Get information on the right instruction and its operand twisti@1038: int right_inst; // Right-instructions's number duke@435: if( isdigit(_curchar) ) { duke@435: right_inst = get_int(); duke@435: // Right-instruction's operand duke@435: skipws(); duke@435: if( _curchar != '.' ) { duke@435: parse_err(SYNERR, "missing '.' in peepconstraint after instruction number.\n"); duke@435: return; duke@435: } duke@435: next_char(); // Skip '.' duke@435: } else { duke@435: right_inst = -1; // Flag as being a register constraint duke@435: } duke@435: duke@435: char *right_op = get_ident_dup(); duke@435: duke@435: // Construct the next PeepConstraint duke@435: PeepConstraint *constraint = new PeepConstraint( left_inst, left_op, duke@435: relation, duke@435: right_inst, right_op ); duke@435: // And append it to the list for this peephole rule duke@435: peep.append_constraint( constraint ); duke@435: duke@435: // Check for another constraint, or end of rule duke@435: skipws(); duke@435: if( _curchar == ',' ) { duke@435: next_char(); // Skip ',' duke@435: skipws(); duke@435: } duke@435: else if( _curchar != ')' ) { duke@435: parse_err(SYNERR, "expected ',' or ')' after peephole constraint.\n"); duke@435: return; duke@435: } duke@435: } // end while( processing constraints ) duke@435: next_char(); // Skip ')' duke@435: duke@435: // Check for terminating ';' duke@435: skipws(); duke@435: if (_curchar != ';') { duke@435: parse_err(SYNERR, "missing ';' at end of peepconstraint.\n"); duke@435: return; duke@435: } duke@435: next_char(); // Skip trailing ';' duke@435: } duke@435: duke@435: duke@435: //------------------------------peep_replace_parse----------------------------- duke@435: // Syntax for a peepreplace rule duke@435: // root instruction name followed by a duke@435: // parenthesized list of whitespace separated instruction.operand specifiers duke@435: // duke@435: // peepreplace ( instr_name ( [instruction_number.operand_name]* ) ); duke@435: // duke@435: // duke@435: void ADLParser::peep_replace_parse(Peephole &peep) { duke@435: int lparen = 0; // keep track of parenthesis nesting depth duke@435: int rparen = 0; // keep track of parenthesis nesting depth duke@435: int icount = 0; // count of instructions in rule for naming duke@435: char *str = NULL; duke@435: char *token = NULL; duke@435: duke@435: skipws(); duke@435: // Check for open paren duke@435: if (_curchar != '(') { duke@435: parse_err(SYNERR, "missing '(' at start of peepreplace rule.\n"); duke@435: return; duke@435: } duke@435: else { duke@435: lparen++; duke@435: next_char(); duke@435: } duke@435: duke@435: // Check for root instruction duke@435: char *inst = get_ident_dup(); duke@435: const Form *form = _AD._globalNames[inst]; duke@435: if( form == NULL || form->is_instruction() == NULL ) { duke@435: parse_err(SYNERR, "Instruction name expected at start of peepreplace.\n"); duke@435: return; duke@435: } duke@435: duke@435: // Store string representation of rule into replace duke@435: PeepReplace *replace = new PeepReplace(str); duke@435: replace->add_instruction( inst ); duke@435: duke@435: skipws(); duke@435: // Start of root's operand-list duke@435: if (_curchar != '(') { duke@435: parse_err(SYNERR, "missing '(' at peepreplace root's operand-list.\n"); duke@435: return; duke@435: } duke@435: else { duke@435: lparen++; duke@435: next_char(); duke@435: } duke@435: duke@435: skipws(); duke@435: // Get the list of operands duke@435: while( _curchar != ')' ) { duke@435: // Get information on an instruction and its operand duke@435: // instructions's number duke@435: int inst_num = get_int(); duke@435: // Left-instruction's operand duke@435: skipws(); duke@435: if( _curchar != '.' ) { duke@435: parse_err(SYNERR, "missing '.' in peepreplace after instruction number.\n"); duke@435: return; duke@435: } duke@435: next_char(); // Skip '.' duke@435: char *inst_op = get_ident_dup(); duke@435: if( inst_op == NULL ) { duke@435: parse_err(SYNERR, "missing operand identifier in peepreplace.\n"); duke@435: return; duke@435: } duke@435: duke@435: // Record this operand's position in peepmatch duke@435: replace->add_operand( inst_num, inst_op ); duke@435: skipws(); duke@435: } duke@435: duke@435: // Check for the end of operands list duke@435: skipws(); duke@435: assert( _curchar == ')', "While loop should have advanced to ')'."); duke@435: next_char(); // Skip ')' duke@435: duke@435: skipws(); duke@435: // Check for end of peepreplace duke@435: if( _curchar != ')' ) { duke@435: parse_err(SYNERR, "missing ')' at end of peepmatch.\n"); duke@435: parse_err(SYNERR, "Support one replacement instruction.\n"); duke@435: return; duke@435: } duke@435: next_char(); // Skip ')' duke@435: duke@435: // Check for closing semicolon duke@435: skipws(); duke@435: if( _curchar != ';' ) { duke@435: parse_err(SYNERR, "missing ';' at end of peepreplace.\n"); duke@435: return; duke@435: } duke@435: next_char(); // skip ';' duke@435: duke@435: // Store replace into peep duke@435: peep.add_replace( replace ); duke@435: } duke@435: duke@435: //------------------------------pred_parse------------------------------------- duke@435: Predicate *ADLParser::pred_parse(void) { duke@435: Predicate *predicate; // Predicate class for operand duke@435: char *rule = NULL; // String representation of predicate duke@435: duke@435: skipws(); // Skip leading whitespace jrose@910: int line = linenum(); jrose@910: if ( (rule = get_paren_expr("pred expression", true)) == NULL ) { duke@435: parse_err(SYNERR, "incorrect or missing expression for 'predicate'\n"); duke@435: return NULL; duke@435: } duke@435: // Debug Stuff duke@435: if (_AD._adl_debug > 1) fprintf(stderr,"Predicate: %s\n", rule); duke@435: if (_curchar != ';') { duke@435: parse_err(SYNERR, "missing ';' in predicate definition\n"); duke@435: return NULL; duke@435: } duke@435: next_char(); // Point after the terminator duke@435: duke@435: predicate = new Predicate(rule); // Build new predicate object duke@435: skipws(); duke@435: return predicate; duke@435: } duke@435: duke@435: duke@435: //------------------------------ins_encode_parse_block------------------------- duke@435: // Parse the block form of ins_encode. See ins_encode_parse for more details duke@435: InsEncode *ADLParser::ins_encode_parse_block(InstructForm &inst) { duke@435: // Create a new encoding name based on the name of the instruction duke@435: // definition, which should be unique. duke@435: const char * prefix = "__enc_"; duke@435: char* ec_name = (char*)malloc(strlen(inst._ident) + strlen(prefix) + 1); duke@435: sprintf(ec_name, "%s%s", prefix, inst._ident); duke@435: duke@435: assert(_AD._encode->encClass(ec_name) == NULL, "shouldn't already exist"); duke@435: EncClass *encoding = _AD._encode->add_EncClass(ec_name); never@850: encoding->_linenum = linenum(); duke@435: duke@435: // synthesize the arguments list for the enc_class from the duke@435: // arguments to the instruct definition. duke@435: const char * param = NULL; duke@435: inst._parameters.reset(); duke@435: while ((param = inst._parameters.iter()) != NULL) { duke@435: OperandForm *opForm = (OperandForm*)inst._localNames[param]; duke@435: encoding->add_parameter(opForm->_ident, param); duke@435: } duke@435: duke@435: // Add the prologue to create the MacroAssembler duke@435: encoding->add_code("\n" duke@435: " // Define a MacroAssembler instance for use by the encoding. The\n" duke@435: " // name is chosen to match the __ idiom used for assembly in other\n" duke@435: " // parts of hotspot and assumes the existence of the standard\n" duke@435: " // #define __ _masm.\n" duke@435: " MacroAssembler _masm(&cbuf);\n"); duke@435: duke@435: // Parse the following %{ }% block duke@435: enc_class_parse_block(encoding, ec_name); duke@435: duke@435: // Build an encoding rule which invokes the encoding rule we just duke@435: // created, passing all arguments that we received. duke@435: InsEncode *encrule = new InsEncode(); // Encode class for instruction duke@435: NameAndList *params = encrule->add_encode(ec_name); duke@435: inst._parameters.reset(); duke@435: while ((param = inst._parameters.iter()) != NULL) { duke@435: params->add_entry(param); duke@435: } duke@435: duke@435: return encrule; duke@435: } duke@435: duke@435: duke@435: //------------------------------ins_encode_parse------------------------------- duke@435: // Encode rules have the form duke@435: // ins_encode( encode_class_name(parameter_list), ... ); duke@435: // duke@435: // The "encode_class_name" must be defined in the encode section duke@435: // The parameter list contains $names that are locals. duke@435: // duke@435: // Alternatively it can be written like this: duke@435: // duke@435: // ins_encode %{ duke@435: // ... // body duke@435: // %} duke@435: // duke@435: // which synthesizes a new encoding class taking the same arguments as duke@435: // the InstructForm, and automatically prefixes the definition with: duke@435: // duke@435: // MacroAssembler masm(&cbuf);\n"); duke@435: // duke@435: // making it more compact to take advantage of the MacroAssembler and duke@435: // placing the assembly closer to it's use by instructions. duke@435: InsEncode *ADLParser::ins_encode_parse(InstructForm &inst) { duke@435: duke@435: // Parse encode class name duke@435: skipws(); // Skip whitespace duke@435: if (_curchar != '(') { duke@435: // Check for ins_encode %{ form duke@435: if ((_curchar == '%') && (*(_ptr+1) == '{')) { duke@435: next_char(); // Skip '%' duke@435: next_char(); // Skip '{' duke@435: duke@435: // Parse the block form of ins_encode duke@435: return ins_encode_parse_block(inst); duke@435: } duke@435: duke@435: parse_err(SYNERR, "missing '%%{' or '(' in ins_encode definition\n"); duke@435: return NULL; duke@435: } duke@435: next_char(); // move past '(' duke@435: skipws(); duke@435: duke@435: InsEncode *encrule = new InsEncode(); // Encode class for instruction never@850: encrule->_linenum = linenum(); duke@435: char *ec_name = NULL; // String representation of encode rule duke@435: // identifier is optional. duke@435: while (_curchar != ')') { duke@435: ec_name = get_ident(); duke@435: if (ec_name == NULL) { duke@435: parse_err(SYNERR, "Invalid encode class name after 'ins_encode('.\n"); duke@435: return NULL; duke@435: } duke@435: // Check that encoding is defined in the encode section duke@435: EncClass *encode_class = _AD._encode->encClass(ec_name); duke@435: if (encode_class == NULL) { duke@435: // Like to defer checking these till later... duke@435: // parse_err(WARN, "Using an undefined encode class '%s' in 'ins_encode'.\n", ec_name); duke@435: } duke@435: duke@435: // Get list for encode method's parameters duke@435: NameAndList *params = encrule->add_encode(ec_name); duke@435: duke@435: // Parse the parameters to this encode method. duke@435: skipws(); duke@435: if ( _curchar == '(' ) { duke@435: next_char(); // move past '(' for parameters duke@435: duke@435: // Parse the encode method's parameters duke@435: while (_curchar != ')') { duke@435: char *param = get_ident_or_literal_constant("encoding operand"); duke@435: if ( param != NULL ) { duke@435: // Found a parameter: duke@435: // Check it is a local name, add it to the list, then check for more duke@435: // New: allow hex constants as parameters to an encode method. duke@435: // New: allow parenthesized expressions as parameters. duke@435: // New: allow "primary", "secondary", "tertiary" as parameters. duke@435: // New: allow user-defined register name as parameter duke@435: if ( (inst._localNames[param] == NULL) && duke@435: !ADLParser::is_literal_constant(param) && duke@435: (Opcode::as_opcode_type(param) == Opcode::NOT_AN_OPCODE) && duke@435: ((_AD._register == NULL ) || (_AD._register->getRegDef(param) == NULL)) ) { duke@435: parse_err(SYNERR, "Using non-locally defined parameter %s for encoding %s.\n", param, ec_name); duke@435: return NULL; duke@435: } duke@435: params->add_entry(param); duke@435: duke@435: skipws(); duke@435: if (_curchar == ',' ) { duke@435: // More parameters to come duke@435: next_char(); // move past ',' between parameters duke@435: skipws(); // Skip to next parameter duke@435: } duke@435: else if (_curchar == ')') { duke@435: // Done with parameter list duke@435: } duke@435: else { duke@435: // Only ',' or ')' are valid after a parameter name duke@435: parse_err(SYNERR, "expected ',' or ')' after parameter %s.\n", duke@435: ec_name); duke@435: return NULL; duke@435: } duke@435: duke@435: } else { duke@435: skipws(); duke@435: // Did not find a parameter duke@435: if (_curchar == ',') { duke@435: parse_err(SYNERR, "Expected encode parameter before ',' in encoding %s.\n", ec_name); duke@435: return NULL; duke@435: } duke@435: if (_curchar != ')') { duke@435: parse_err(SYNERR, "Expected ')' after encode parameters.\n"); duke@435: return NULL; duke@435: } duke@435: } duke@435: } // WHILE loop collecting parameters duke@435: next_char(); // move past ')' at end of parameters duke@435: } // done with parameter list for encoding duke@435: duke@435: // Check for ',' or ')' after encoding duke@435: skipws(); // move to character after parameters duke@435: if ( _curchar == ',' ) { duke@435: // Found a ',' duke@435: next_char(); // move past ',' between encode methods duke@435: skipws(); duke@435: } duke@435: else if ( _curchar != ')' ) { duke@435: // If not a ',' then only a ')' is allowed duke@435: parse_err(SYNERR, "Expected ')' after encoding %s.\n", ec_name); duke@435: return NULL; duke@435: } duke@435: duke@435: // Check for ',' separating parameters duke@435: // if ( _curchar != ',' && _curchar != ')' ) { duke@435: // parse_err(SYNERR, "expected ',' or ')' after encode method inside ins_encode.\n"); duke@435: // return NULL; duke@435: // } duke@435: duke@435: } // done parsing ins_encode methods and their parameters duke@435: if (_curchar != ')') { duke@435: parse_err(SYNERR, "Missing ')' at end of ins_encode description.\n"); duke@435: return NULL; duke@435: } duke@435: next_char(); // move past ')' duke@435: skipws(); // Skip leading whitespace duke@435: duke@435: if ( _curchar != ';' ) { duke@435: parse_err(SYNERR, "Missing ';' at end of ins_encode.\n"); duke@435: return NULL; duke@435: } duke@435: next_char(); // move past ';' duke@435: skipws(); // be friendly to oper_parse() duke@435: duke@435: // Debug Stuff duke@435: if (_AD._adl_debug > 1) fprintf(stderr,"Instruction Encode: %s\n", ec_name); duke@435: duke@435: return encrule; duke@435: } duke@435: duke@435: duke@435: //------------------------------size_parse----------------------------------- duke@435: char* ADLParser::size_parse(InstructForm *instr) { duke@435: char* sizeOfInstr = NULL; duke@435: duke@435: // Get value of the instruction's size duke@435: skipws(); duke@435: duke@435: // Parse size duke@435: sizeOfInstr = get_paren_expr("size expression"); duke@435: if (sizeOfInstr == NULL) { duke@435: parse_err(SYNERR, "size of opcode expected at %c\n", _curchar); duke@435: return NULL; duke@435: } duke@435: duke@435: skipws(); duke@435: duke@435: // Check for terminator duke@435: if (_curchar != ';') { duke@435: parse_err(SYNERR, "missing ';' in ins_attrib definition\n"); duke@435: return NULL; duke@435: } duke@435: next_char(); // Advance past the ';' duke@435: skipws(); // necessary for instr_parse() duke@435: duke@435: // Debug Stuff duke@435: if (_AD._adl_debug > 1) { duke@435: if (sizeOfInstr != NULL) { duke@435: fprintf(stderr,"size of opcode: %s\n", sizeOfInstr); duke@435: } duke@435: } duke@435: duke@435: return sizeOfInstr; duke@435: } duke@435: duke@435: duke@435: //------------------------------opcode_parse----------------------------------- duke@435: Opcode * ADLParser::opcode_parse(InstructForm *instr) { duke@435: char *primary = NULL; duke@435: char *secondary = NULL; duke@435: char *tertiary = NULL; duke@435: duke@435: char *val = NULL; duke@435: Opcode *opcode = NULL; duke@435: duke@435: // Get value of the instruction's opcode duke@435: skipws(); duke@435: if (_curchar != '(') { // Check for parenthesized operand list duke@435: parse_err(SYNERR, "missing '(' in expand instruction declaration\n"); duke@435: return NULL; duke@435: } duke@435: next_char(); // skip open paren duke@435: skipws(); duke@435: if (_curchar != ')') { duke@435: // Parse primary, secondary, and tertiary opcodes, if provided. duke@435: if ( ((primary = get_ident_or_literal_constant("primary opcode")) == NULL) ) { duke@435: parse_err(SYNERR, "primary hex opcode expected at %c\n", _curchar); duke@435: return NULL; duke@435: } duke@435: skipws(); duke@435: if (_curchar == ',') { duke@435: next_char(); duke@435: skipws(); duke@435: // Parse secondary opcode duke@435: if ( ((secondary = get_ident_or_literal_constant("secondary opcode")) == NULL) ) { duke@435: parse_err(SYNERR, "secondary hex opcode expected at %c\n", _curchar); duke@435: return NULL; duke@435: } duke@435: skipws(); duke@435: if (_curchar == ',') { duke@435: next_char(); duke@435: skipws(); duke@435: // Parse tertiary opcode duke@435: if ( ((tertiary = get_ident_or_literal_constant("tertiary opcode")) == NULL) ) { duke@435: parse_err(SYNERR,"tertiary hex opcode expected at %c\n", _curchar); duke@435: return NULL; duke@435: } duke@435: skipws(); duke@435: } duke@435: } duke@435: skipws(); duke@435: if (_curchar != ')') { duke@435: parse_err(SYNERR, "Missing ')' in opcode description\n"); duke@435: return NULL; duke@435: } duke@435: } duke@435: next_char(); // Skip ')' duke@435: skipws(); duke@435: // Check for terminator duke@435: if (_curchar != ';') { duke@435: parse_err(SYNERR, "missing ';' in ins_attrib definition\n"); duke@435: return NULL; duke@435: } duke@435: next_char(); // Advance past the ';' duke@435: skipws(); // necessary for instr_parse() duke@435: duke@435: // Debug Stuff duke@435: if (_AD._adl_debug > 1) { duke@435: if (primary != NULL) fprintf(stderr,"primary opcode: %s\n", primary); duke@435: if (secondary != NULL) fprintf(stderr,"secondary opcode: %s\n", secondary); duke@435: if (tertiary != NULL) fprintf(stderr,"tertiary opcode: %s\n", tertiary); duke@435: } duke@435: duke@435: // Generate new object and return duke@435: opcode = new Opcode(primary, secondary, tertiary); duke@435: return opcode; duke@435: } duke@435: duke@435: duke@435: //------------------------------interface_parse-------------------------------- duke@435: Interface *ADLParser::interface_parse(void) { duke@435: char *iface_name = NULL; // Name of interface class being used duke@435: char *iface_code = NULL; // Describe components of this class duke@435: duke@435: // Get interface class name duke@435: skipws(); // Skip whitespace duke@435: if (_curchar != '(') { duke@435: parse_err(SYNERR, "Missing '(' at start of interface description.\n"); duke@435: return NULL; duke@435: } duke@435: next_char(); // move past '(' duke@435: skipws(); duke@435: iface_name = get_ident(); duke@435: if (iface_name == NULL) { duke@435: parse_err(SYNERR, "missing interface name after 'interface'.\n"); duke@435: return NULL; duke@435: } duke@435: skipws(); duke@435: if (_curchar != ')') { duke@435: parse_err(SYNERR, "Missing ')' after name of interface.\n"); duke@435: return NULL; duke@435: } duke@435: next_char(); // move past ')' duke@435: duke@435: // Get details of the interface, duke@435: // for the type of interface indicated by iface_name. duke@435: Interface *inter = NULL; duke@435: skipws(); duke@435: if ( _curchar != ';' ) { duke@435: if ( strcmp(iface_name,"MEMORY_INTER") == 0 ) { duke@435: inter = mem_interface_parse(); duke@435: } duke@435: else if ( strcmp(iface_name,"COND_INTER") == 0 ) { duke@435: inter = cond_interface_parse(); duke@435: } duke@435: // The parse routines consume the "%}" duke@435: duke@435: // Check for probable extra ';' after defining block. duke@435: if ( _curchar == ';' ) { duke@435: parse_err(SYNERR, "Extra ';' after defining interface block.\n"); duke@435: next_char(); // Skip ';' duke@435: return NULL; duke@435: } duke@435: } else { duke@435: next_char(); // move past ';' duke@435: duke@435: // Create appropriate interface object duke@435: if ( strcmp(iface_name,"REG_INTER") == 0 ) { duke@435: inter = new RegInterface(); duke@435: } duke@435: else if ( strcmp(iface_name,"CONST_INTER") == 0 ) { duke@435: inter = new ConstInterface(); duke@435: } duke@435: } duke@435: skipws(); // be friendly to oper_parse() duke@435: // Debug Stuff duke@435: if (_AD._adl_debug > 1) fprintf(stderr,"Interface Form: %s\n", iface_name); duke@435: duke@435: // Create appropriate interface object and return. duke@435: return inter; duke@435: } duke@435: duke@435: duke@435: //------------------------------mem_interface_parse---------------------------- duke@435: Interface *ADLParser::mem_interface_parse(void) { duke@435: // Fields for MemInterface duke@435: char *base = NULL; duke@435: char *index = NULL; duke@435: char *scale = NULL; duke@435: char *disp = NULL; duke@435: duke@435: if (_curchar != '%') { duke@435: parse_err(SYNERR, "Missing '%{' for 'interface' block.\n"); duke@435: return NULL; duke@435: } duke@435: next_char(); // Skip '%' duke@435: if (_curchar != '{') { duke@435: parse_err(SYNERR, "Missing '%{' for 'interface' block.\n"); duke@435: return NULL; duke@435: } duke@435: next_char(); // Skip '{' duke@435: skipws(); duke@435: do { duke@435: char *field = get_ident(); duke@435: if (field == NULL) { duke@435: parse_err(SYNERR, "Expected keyword, base|index|scale|disp, or '%}' ending interface.\n"); duke@435: return NULL; duke@435: } duke@435: if ( strcmp(field,"base") == 0 ) { duke@435: base = interface_field_parse(); duke@435: } duke@435: else if ( strcmp(field,"index") == 0 ) { duke@435: index = interface_field_parse(); duke@435: } duke@435: else if ( strcmp(field,"scale") == 0 ) { duke@435: scale = interface_field_parse(); duke@435: } duke@435: else if ( strcmp(field,"disp") == 0 ) { duke@435: disp = interface_field_parse(); duke@435: } duke@435: else { duke@435: parse_err(SYNERR, "Expected keyword, base|index|scale|disp, or '%}' ending interface.\n"); duke@435: return NULL; duke@435: } duke@435: } while( _curchar != '%' ); duke@435: next_char(); // Skip '%' duke@435: if ( _curchar != '}' ) { duke@435: parse_err(SYNERR, "Missing '%}' for 'interface' block.\n"); duke@435: return NULL; duke@435: } duke@435: next_char(); // Skip '}' duke@435: duke@435: // Construct desired object and return duke@435: Interface *inter = new MemInterface(base, index, scale, disp); duke@435: return inter; duke@435: } duke@435: duke@435: duke@435: //------------------------------cond_interface_parse--------------------------- duke@435: Interface *ADLParser::cond_interface_parse(void) { duke@435: char *equal; duke@435: char *not_equal; duke@435: char *less; duke@435: char *greater_equal; duke@435: char *less_equal; duke@435: char *greater; never@850: const char *equal_format = "eq"; never@850: const char *not_equal_format = "ne"; never@850: const char *less_format = "lt"; never@850: const char *greater_equal_format = "ge"; never@850: const char *less_equal_format = "le"; never@850: const char *greater_format = "gt"; duke@435: duke@435: if (_curchar != '%') { duke@435: parse_err(SYNERR, "Missing '%{' for 'cond_interface' block.\n"); duke@435: return NULL; duke@435: } duke@435: next_char(); // Skip '%' duke@435: if (_curchar != '{') { duke@435: parse_err(SYNERR, "Missing '%{' for 'cond_interface' block.\n"); duke@435: return NULL; duke@435: } duke@435: next_char(); // Skip '{' duke@435: skipws(); duke@435: do { duke@435: char *field = get_ident(); duke@435: if (field == NULL) { duke@435: parse_err(SYNERR, "Expected keyword, base|index|scale|disp, or '%}' ending interface.\n"); duke@435: return NULL; duke@435: } duke@435: if ( strcmp(field,"equal") == 0 ) { never@850: equal = interface_field_parse(&equal_format); duke@435: } duke@435: else if ( strcmp(field,"not_equal") == 0 ) { never@850: not_equal = interface_field_parse(¬_equal_format); duke@435: } duke@435: else if ( strcmp(field,"less") == 0 ) { never@850: less = interface_field_parse(&less_format); duke@435: } duke@435: else if ( strcmp(field,"greater_equal") == 0 ) { never@850: greater_equal = interface_field_parse(&greater_equal_format); duke@435: } duke@435: else if ( strcmp(field,"less_equal") == 0 ) { never@850: less_equal = interface_field_parse(&less_equal_format); duke@435: } duke@435: else if ( strcmp(field,"greater") == 0 ) { never@850: greater = interface_field_parse(&greater_format); duke@435: } duke@435: else { duke@435: parse_err(SYNERR, "Expected keyword, base|index|scale|disp, or '%}' ending interface.\n"); duke@435: return NULL; duke@435: } duke@435: } while( _curchar != '%' ); duke@435: next_char(); // Skip '%' duke@435: if ( _curchar != '}' ) { duke@435: parse_err(SYNERR, "Missing '%}' for 'interface' block.\n"); duke@435: return NULL; duke@435: } duke@435: next_char(); // Skip '}' duke@435: duke@435: // Construct desired object and return never@850: Interface *inter = new CondInterface(equal, equal_format, never@850: not_equal, not_equal_format, never@850: less, less_format, never@850: greater_equal, greater_equal_format, never@850: less_equal, less_equal_format, never@850: greater, greater_format); duke@435: return inter; duke@435: } duke@435: duke@435: duke@435: //------------------------------interface_field_parse-------------------------- never@850: char *ADLParser::interface_field_parse(const char ** format) { duke@435: char *iface_field = NULL; duke@435: duke@435: // Get interface field duke@435: skipws(); // Skip whitespace duke@435: if (_curchar != '(') { duke@435: parse_err(SYNERR, "Missing '(' at start of interface field.\n"); duke@435: return NULL; duke@435: } duke@435: next_char(); // move past '(' duke@435: skipws(); duke@435: if ( _curchar != '0' && _curchar != '$' ) { duke@435: parse_err(SYNERR, "missing or invalid interface field contents.\n"); duke@435: return NULL; duke@435: } duke@435: iface_field = get_rep_var_ident(); duke@435: if (iface_field == NULL) { duke@435: parse_err(SYNERR, "missing or invalid interface field contents.\n"); duke@435: return NULL; duke@435: } duke@435: skipws(); never@850: if (format != NULL && _curchar == ',') { never@850: next_char(); never@850: skipws(); never@850: if (_curchar != '"') { never@850: parse_err(SYNERR, "Missing '\"' in field format .\n"); never@850: return NULL; never@850: } never@850: next_char(); never@850: char *start = _ptr; // Record start of the next string never@850: while ((_curchar != '"') && (_curchar != '%') && (_curchar != '\n')) { never@850: if (_curchar == '\\') next_char(); // superquote never@850: if (_curchar == '\n') parse_err(SYNERR, "newline in string"); // unimplemented! never@850: next_char(); never@850: } never@850: if (_curchar != '"') { never@850: parse_err(SYNERR, "Missing '\"' at end of field format .\n"); never@850: return NULL; never@850: } never@850: // If a string was found, terminate it and record in FormatRule never@850: if ( start != _ptr ) { never@850: *_ptr = '\0'; // Terminate the string never@850: *format = start; never@850: } never@850: next_char(); never@850: skipws(); never@850: } duke@435: if (_curchar != ')') { duke@435: parse_err(SYNERR, "Missing ')' after interface field.\n"); duke@435: return NULL; duke@435: } duke@435: next_char(); // move past ')' duke@435: skipws(); duke@435: if ( _curchar != ';' ) { duke@435: parse_err(SYNERR, "Missing ';' at end of interface field.\n"); duke@435: return NULL; duke@435: } duke@435: next_char(); // move past ';' duke@435: skipws(); // be friendly to interface_parse() duke@435: duke@435: return iface_field; duke@435: } duke@435: duke@435: duke@435: //------------------------------match_parse------------------------------------ duke@435: MatchRule *ADLParser::match_parse(FormDict &operands) { duke@435: MatchRule *match; // Match Rule class for instruction/operand duke@435: char *cnstr = NULL; // Code for constructor duke@435: int depth = 0; // Counter for matching parentheses duke@435: int numleaves = 0; // Counter for number of leaves in rule duke@435: duke@435: // Parse the match rule tree duke@435: MatchNode *mnode = matchNode_parse(operands, depth, numleaves, true); duke@435: duke@435: // Either there is a block with a constructor, or a ';' here duke@435: skipws(); // Skip whitespace duke@435: if ( _curchar == ';' ) { // Semicolon is valid terminator duke@435: cnstr = NULL; // no constructor for this form duke@435: next_char(); // Move past the ';', replaced with '\0' duke@435: } duke@435: else if ((cnstr = find_cpp_block("match constructor")) == NULL ) { duke@435: parse_err(SYNERR, "invalid construction of match rule\n" duke@435: "Missing ';' or invalid '%{' and '%}' constructor\n"); duke@435: return NULL; // No MatchRule to return duke@435: } duke@435: if (_AD._adl_debug > 1) duke@435: if (cnstr) fprintf(stderr,"Match Constructor: %s\n", cnstr); duke@435: // Build new MatchRule object duke@435: match = new MatchRule(_AD, mnode, depth, cnstr, numleaves); duke@435: skipws(); // Skip any trailing whitespace duke@435: return match; // Return MatchRule object duke@435: } duke@435: duke@435: //------------------------------format_parse----------------------------------- duke@435: FormatRule* ADLParser::format_parse(void) { duke@435: char *desc = NULL; duke@435: FormatRule *format = (new FormatRule(desc)); duke@435: duke@435: // Without expression form, MUST have a code block; duke@435: skipws(); // Skip whitespace duke@435: if ( _curchar == ';' ) { // Semicolon is valid terminator duke@435: desc = NULL; // no constructor for this form duke@435: next_char(); // Move past the ';', replaced with '\0' duke@435: } duke@435: else if ( _curchar == '%' && *(_ptr+1) == '{') { duke@435: next_char(); // Move past the '%' duke@435: next_char(); // Move past the '{' duke@435: duke@435: skipws(); never@850: if (_curchar == '$') { never@850: char* ident = get_rep_var_ident(); never@850: if (strcmp(ident, "$$template") == 0) return template_parse(); never@850: parse_err(SYNERR, "Unknown \"%s\" directive in format", ident); never@850: return NULL; never@850: } duke@435: // Check for the opening '"' inside the format description duke@435: if ( _curchar == '"' ) { duke@435: next_char(); // Move past the initial '"' duke@435: if( _curchar == '"' ) { // Handle empty format string case duke@435: *_ptr = '\0'; // Terminate empty string duke@435: format->_strings.addName(_ptr); duke@435: } duke@435: duke@435: // Collect the parts of the format description duke@435: // (1) strings that are passed through to tty->print duke@435: // (2) replacement/substitution variable, preceeded by a '$' duke@435: // (3) multi-token ANSIY C style strings duke@435: while ( true ) { duke@435: if ( _curchar == '%' || _curchar == '\n' ) { duke@435: if ( _curchar != '"' ) { duke@435: parse_err(SYNERR, "missing '\"' at end of format block"); duke@435: return NULL; duke@435: } duke@435: } duke@435: duke@435: // (1) duke@435: // Check if there is a string to pass through to output duke@435: char *start = _ptr; // Record start of the next string duke@435: while ((_curchar != '$') && (_curchar != '"') && (_curchar != '%') && (_curchar != '\n')) { jrose@910: if (_curchar == '\\') { jrose@910: next_char(); // superquote jrose@910: if ((_curchar == '$') || (_curchar == '%')) jrose@910: // hack to avoid % escapes and warnings about undefined \ escapes jrose@910: *(_ptr-1) = _curchar; jrose@910: } duke@435: if (_curchar == '\n') parse_err(SYNERR, "newline in string"); // unimplemented! duke@435: next_char(); duke@435: } duke@435: // If a string was found, terminate it and record in FormatRule duke@435: if ( start != _ptr ) { duke@435: *_ptr = '\0'; // Terminate the string duke@435: format->_strings.addName(start); duke@435: } duke@435: duke@435: // (2) duke@435: // If we are at a replacement variable, duke@435: // copy it and record in FormatRule duke@435: if ( _curchar == '$' ) { duke@435: next_char(); // Move past the '$' duke@435: char* rep_var = get_ident(); // Nil terminate the variable name duke@435: rep_var = strdup(rep_var);// Copy the string duke@435: *_ptr = _curchar; // and replace Nil with original character duke@435: format->_rep_vars.addName(rep_var); duke@435: // Add flag to _strings list indicating we should check _rep_vars duke@435: format->_strings.addName(NameList::_signal); duke@435: } duke@435: duke@435: // (3) duke@435: // Allow very long strings to be broken up, duke@435: // using the ANSI C syntax "foo\n" "bar" duke@435: if ( _curchar == '"') { duke@435: next_char(); // Move past the '"' duke@435: skipws(); // Skip white space before next string token duke@435: if ( _curchar != '"') { duke@435: break; duke@435: } else { duke@435: // Found one. Skip both " and the whitespace in between. duke@435: next_char(); duke@435: } duke@435: } duke@435: } // end while part of format description duke@435: duke@435: // Check for closing '"' and '%}' in format description duke@435: skipws(); // Move to closing '%}' duke@435: if ( _curchar != '%' ) { duke@435: parse_err(SYNERR, "non-blank characters between closing '\"' and '%' in format"); duke@435: return NULL; duke@435: } duke@435: } // Done with format description inside duke@435: duke@435: skipws(); duke@435: // Past format description, at '%' duke@435: if ( _curchar != '%' || *(_ptr+1) != '}' ) { duke@435: parse_err(SYNERR, "missing '%}' at end of format block"); duke@435: return NULL; duke@435: } duke@435: next_char(); // Move past the '%' duke@435: next_char(); // Move past the '}' duke@435: } duke@435: else { // parameter list alone must terminate with a ';' duke@435: parse_err(SYNERR, "missing ';' after Format expression"); duke@435: return NULL; duke@435: } duke@435: // Debug Stuff duke@435: if (_AD._adl_debug > 1) fprintf(stderr,"Format Rule: %s\n", desc); duke@435: duke@435: skipws(); duke@435: return format; duke@435: } duke@435: duke@435: never@850: //------------------------------template_parse----------------------------------- never@850: FormatRule* ADLParser::template_parse(void) { never@850: char *desc = NULL; never@850: FormatRule *format = (new FormatRule(desc)); never@850: never@850: skipws(); never@850: while ( (_curchar != '%') && (*(_ptr+1) != '}') ) { never@850: never@850: // (1) never@850: // Check if there is a string to pass through to output twisti@1038: { twisti@1038: char *start = _ptr; // Record start of the next string twisti@1038: while ((_curchar != '$') && ((_curchar != '%') || (*(_ptr+1) != '}')) ) { twisti@1038: // If at the start of a comment, skip past it twisti@1038: if( (_curchar == '/') && ((*(_ptr+1) == '/') || (*(_ptr+1) == '*')) ) { twisti@1038: skipws_no_preproc(); twisti@1038: } else { twisti@1038: // ELSE advance to the next character, or start of the next line twisti@1038: next_char_or_line(); twisti@1038: } never@850: } twisti@1038: // If a string was found, terminate it and record in EncClass twisti@1038: if ( start != _ptr ) { twisti@1038: *_ptr = '\0'; // Terminate the string twisti@1038: // Add flag to _strings list indicating we should check _rep_vars twisti@1038: format->_strings.addName(NameList::_signal2); twisti@1038: format->_strings.addName(start); twisti@1038: } never@850: } never@850: never@850: // (2) never@850: // If we are at a replacement variable, never@850: // copy it and record in EncClass never@850: if ( _curchar == '$' ) { never@850: // Found replacement Variable never@850: char *rep_var = get_rep_var_ident_dup(); never@850: if (strcmp(rep_var, "$emit") == 0) { never@850: // switch to normal format parsing never@850: next_char(); never@850: next_char(); never@850: skipws(); never@850: // Check for the opening '"' inside the format description never@850: if ( _curchar == '"' ) { never@850: next_char(); // Move past the initial '"' never@850: if( _curchar == '"' ) { // Handle empty format string case never@850: *_ptr = '\0'; // Terminate empty string never@850: format->_strings.addName(_ptr); never@850: } never@850: never@850: // Collect the parts of the format description never@850: // (1) strings that are passed through to tty->print never@850: // (2) replacement/substitution variable, preceeded by a '$' never@850: // (3) multi-token ANSIY C style strings never@850: while ( true ) { never@850: if ( _curchar == '%' || _curchar == '\n' ) { never@850: parse_err(SYNERR, "missing '\"' at end of format block"); never@850: return NULL; never@850: } never@850: never@850: // (1) never@850: // Check if there is a string to pass through to output never@850: char *start = _ptr; // Record start of the next string never@850: while ((_curchar != '$') && (_curchar != '"') && (_curchar != '%') && (_curchar != '\n')) { never@850: if (_curchar == '\\') next_char(); // superquote never@850: if (_curchar == '\n') parse_err(SYNERR, "newline in string"); // unimplemented! never@850: next_char(); never@850: } never@850: // If a string was found, terminate it and record in FormatRule never@850: if ( start != _ptr ) { never@850: *_ptr = '\0'; // Terminate the string never@850: format->_strings.addName(start); never@850: } never@850: never@850: // (2) never@850: // If we are at a replacement variable, never@850: // copy it and record in FormatRule never@850: if ( _curchar == '$' ) { never@850: next_char(); // Move past the '$' twisti@1038: char* next_rep_var = get_ident(); // Nil terminate the variable name twisti@1038: next_rep_var = strdup(next_rep_var);// Copy the string never@850: *_ptr = _curchar; // and replace Nil with original character twisti@1038: format->_rep_vars.addName(next_rep_var); never@850: // Add flag to _strings list indicating we should check _rep_vars never@850: format->_strings.addName(NameList::_signal); never@850: } never@850: never@850: // (3) never@850: // Allow very long strings to be broken up, never@850: // using the ANSI C syntax "foo\n" "bar" never@850: if ( _curchar == '"') { never@850: next_char(); // Move past the '"' never@850: skipws(); // Skip white space before next string token never@850: if ( _curchar != '"') { never@850: break; never@850: } else { never@850: // Found one. Skip both " and the whitespace in between. never@850: next_char(); never@850: } never@850: } never@850: } // end while part of format description never@850: } never@850: } else { never@850: // Add flag to _strings list indicating we should check _rep_vars never@850: format->_rep_vars.addName(rep_var); never@850: // Add flag to _strings list indicating we should check _rep_vars never@850: format->_strings.addName(NameList::_signal3); never@850: } never@850: } // end while part of format description never@850: } never@850: never@850: skipws(); never@850: // Past format description, at '%' never@850: if ( _curchar != '%' || *(_ptr+1) != '}' ) { never@850: parse_err(SYNERR, "missing '%}' at end of format block"); never@850: return NULL; never@850: } never@850: next_char(); // Move past the '%' never@850: next_char(); // Move past the '}' never@850: never@850: // Debug Stuff never@850: if (_AD._adl_debug > 1) fprintf(stderr,"Format Rule: %s\n", desc); never@850: never@850: skipws(); never@850: return format; never@850: } never@850: never@850: duke@435: //------------------------------effect_parse----------------------------------- duke@435: void ADLParser::effect_parse(InstructForm *instr) { duke@435: char* desc = NULL; duke@435: duke@435: skipws(); // Skip whitespace duke@435: if (_curchar != '(') { duke@435: parse_err(SYNERR, "missing '(' in effect definition\n"); duke@435: return; duke@435: } duke@435: // Get list of effect-operand pairs and insert into dictionary duke@435: else get_effectlist(instr->_effects, instr->_localNames); duke@435: duke@435: // Debug Stuff duke@435: if (_AD._adl_debug > 1) fprintf(stderr,"Effect description: %s\n", desc); duke@435: if (_curchar != ';') { duke@435: parse_err(SYNERR, "missing ';' in Effect definition\n"); duke@435: } duke@435: next_char(); // Skip ';' duke@435: duke@435: } duke@435: duke@435: //------------------------------expand_parse----------------------------------- duke@435: ExpandRule* ADLParser::expand_parse(InstructForm *instr) { duke@435: char *ident, *ident2; duke@435: OperandForm *oper; duke@435: InstructForm *ins; duke@435: NameAndList *instr_and_operands = NULL; duke@435: ExpandRule *exp = new ExpandRule(); duke@435: duke@435: // Expand is a block containing an ordered list of instructions, each of duke@435: // which has an ordered list of operands. duke@435: // Check for block delimiter duke@435: skipws(); // Skip leading whitespace duke@435: if ((_curchar != '%') duke@435: || (next_char(), (_curchar != '{')) ) { // If not open block duke@435: parse_err(SYNERR, "missing '%{' in expand definition\n"); duke@435: return(NULL); duke@435: } duke@435: next_char(); // Maintain the invariant duke@435: do { duke@435: ident = get_ident(); // Grab next identifier duke@435: if (ident == NULL) { duke@435: parse_err(SYNERR, "identifier expected at %c\n", _curchar); duke@435: continue; duke@435: } // Check that you have a valid instruction duke@435: const Form *form = _globalNames[ident]; duke@435: ins = form ? form->is_instruction() : NULL; duke@435: if (ins == NULL) { duke@435: // This is a new operand duke@435: oper = form ? form->is_operand() : NULL; duke@435: if (oper == NULL) { duke@435: parse_err(SYNERR, "instruction/operand name expected at %s\n", ident); duke@435: continue; duke@435: } duke@435: // Throw the operand on the _newopers list duke@435: skipws(); duke@435: ident = get_unique_ident(instr->_localNames,"Operand"); duke@435: if (ident == NULL) { duke@435: parse_err(SYNERR, "identifier expected at %c\n", _curchar); duke@435: continue; duke@435: } duke@435: exp->_newopers.addName(ident); duke@435: // Add new operand to LocalNames duke@435: instr->_localNames.Insert(ident, oper); duke@435: // Grab any constructor code and save as a string duke@435: char *c = NULL; duke@435: skipws(); duke@435: if (_curchar == '%') { // Need a constructor for the operand duke@435: c = find_cpp_block("Operand Constructor"); duke@435: if (c == NULL) { duke@435: parse_err(SYNERR, "Invalid code block for operand constructor\n", _curchar); duke@435: continue; duke@435: } duke@435: // Add constructor to _newopconst Dict duke@435: exp->_newopconst.Insert(ident, c); duke@435: } duke@435: else if (_curchar != ';') { // If no constructor, need a ; duke@435: parse_err(SYNERR, "Missing ; in expand rule operand declaration\n"); duke@435: continue; duke@435: } duke@435: else next_char(); // Skip the ; duke@435: skipws(); duke@435: } duke@435: else { duke@435: // Add instruction to list duke@435: instr_and_operands = new NameAndList(ident); duke@435: // Grab operands, build nameList of them, and then put into dictionary duke@435: skipws(); duke@435: if (_curchar != '(') { // Check for parenthesized operand list duke@435: parse_err(SYNERR, "missing '(' in expand instruction declaration\n"); duke@435: continue; duke@435: } duke@435: do { duke@435: next_char(); // skip open paren & comma characters duke@435: skipws(); duke@435: if (_curchar == ')') break; duke@435: ident2 = get_ident(); duke@435: skipws(); duke@435: if (ident2 == NULL) { duke@435: parse_err(SYNERR, "identifier expected at %c\n", _curchar); duke@435: continue; duke@435: } // Check that you have a valid operand twisti@1038: const Form *form2 = instr->_localNames[ident2]; twisti@1038: if (!form2) { duke@435: parse_err(SYNERR, "operand name expected at %s\n", ident2); duke@435: continue; duke@435: } twisti@1038: oper = form2->is_operand(); twisti@1038: if (oper == NULL && !form2->is_opclass()) { duke@435: parse_err(SYNERR, "operand name expected at %s\n", ident2); duke@435: continue; duke@435: } // Add operand to list duke@435: instr_and_operands->add_entry(ident2); duke@435: } while(_curchar == ','); duke@435: if (_curchar != ')') { duke@435: parse_err(SYNERR, "missing ')'in expand instruction declaration\n"); duke@435: continue; duke@435: } duke@435: next_char(); duke@435: if (_curchar != ';') { duke@435: parse_err(SYNERR, "missing ';'in expand instruction declaration\n"); duke@435: continue; duke@435: } duke@435: next_char(); duke@435: duke@435: // Record both instruction name and its operand list duke@435: exp->add_instruction(instr_and_operands); duke@435: duke@435: skipws(); duke@435: } duke@435: duke@435: } while(_curchar != '%'); duke@435: next_char(); duke@435: if (_curchar != '}') { duke@435: parse_err(SYNERR, "missing '%}' in expand rule definition\n"); duke@435: return(NULL); duke@435: } duke@435: next_char(); duke@435: duke@435: // Debug Stuff duke@435: if (_AD._adl_debug > 1) fprintf(stderr,"Expand Rule:\n"); duke@435: duke@435: skipws(); duke@435: return (exp); duke@435: } duke@435: duke@435: //------------------------------rewrite_parse---------------------------------- duke@435: RewriteRule* ADLParser::rewrite_parse(void) { duke@435: char* params = NULL; duke@435: char* desc = NULL; duke@435: duke@435: duke@435: // This feature targeted for second generation description language. duke@435: duke@435: skipws(); // Skip whitespace duke@435: // Get parameters for rewrite duke@435: if ((params = get_paren_expr("rewrite parameters")) == NULL) { duke@435: parse_err(SYNERR, "missing '(' in rewrite rule\n"); duke@435: return NULL; duke@435: } duke@435: // Debug Stuff duke@435: if (_AD._adl_debug > 1) fprintf(stderr,"Rewrite parameters: %s\n", params); duke@435: duke@435: // For now, grab entire block; duke@435: skipws(); duke@435: if ( (desc = find_cpp_block("rewrite block")) == NULL ) { duke@435: parse_err(SYNERR, "incorrect or missing block for 'rewrite'.\n"); duke@435: return NULL; duke@435: } duke@435: // Debug Stuff duke@435: if (_AD._adl_debug > 1) fprintf(stderr,"Rewrite Rule: %s\n", desc); duke@435: duke@435: skipws(); duke@435: return (new RewriteRule(params,desc)); duke@435: } duke@435: duke@435: //------------------------------attr_parse------------------------------------- duke@435: Attribute *ADLParser::attr_parse(char* ident) { duke@435: Attribute *attrib; // Attribute class duke@435: char *cost = NULL; // String representation of cost attribute duke@435: duke@435: skipws(); // Skip leading whitespace duke@435: if ( (cost = get_paren_expr("attribute")) == NULL ) { duke@435: parse_err(SYNERR, "incorrect or missing expression for 'attribute'\n"); duke@435: return NULL; duke@435: } duke@435: // Debug Stuff duke@435: if (_AD._adl_debug > 1) fprintf(stderr,"Attribute: %s\n", cost); duke@435: if (_curchar != ';') { duke@435: parse_err(SYNERR, "missing ';' in attribute definition\n"); duke@435: return NULL; duke@435: } duke@435: next_char(); // Point after the terminator duke@435: duke@435: skipws(); duke@435: attrib = new Attribute(ident,cost,INS_ATTR); // Build new predicate object duke@435: return attrib; duke@435: } duke@435: duke@435: duke@435: //------------------------------matchNode_parse-------------------------------- duke@435: MatchNode *ADLParser::matchNode_parse(FormDict &operands, int &depth, int &numleaves, bool atroot) { duke@435: // Count depth of parenthesis nesting for both left and right children duke@435: int lParens = depth; duke@435: int rParens = depth; duke@435: duke@435: // MatchNode objects for left, right, and root of subtree. duke@435: MatchNode *lChild = NULL; duke@435: MatchNode *rChild = NULL; duke@435: char *token; // Identifier which may be opcode or operand duke@435: duke@435: // Match expression starts with a '(' duke@435: if (cur_char() != '(') duke@435: return NULL; duke@435: duke@435: next_char(); // advance past '(' duke@435: duke@435: // Parse the opcode duke@435: token = get_ident(); // Get identifier, opcode duke@435: if (token == NULL) { duke@435: parse_err(SYNERR, "missing opcode in match expression\n"); duke@435: return NULL; duke@435: } duke@435: duke@435: // Take note if we see one of a few special operations - those that are duke@435: // treated differently on different architectures in the sense that on duke@435: // one architecture there is a match rule and on another there isn't (so duke@435: // a call will eventually be generated). duke@435: duke@435: for (int i = _last_machine_leaf + 1; i < _last_opcode; i++) { duke@435: if (strcmp(token, NodeClassNames[i]) == 0) { duke@435: _AD.has_match_rule(i, true); duke@435: } duke@435: } duke@435: duke@435: // Lookup the root value in the operands dict to perform substitution duke@435: const char *result = NULL; // Result type will be filled in later duke@435: const char *name = token; // local name associated with this node duke@435: const char *operation = token; // remember valid operation for later duke@435: const Form *form = operands[token]; duke@435: OpClassForm *opcForm = form ? form->is_opclass() : NULL; duke@435: if (opcForm != NULL) { duke@435: // If this token is an entry in the local names table, record its type duke@435: if (!opcForm->ideal_only()) { duke@435: operation = opcForm->_ident; duke@435: result = operation; // Operands result in their own type duke@435: } duke@435: // Otherwise it is an ideal type, and so, has no local name duke@435: else name = NULL; duke@435: } duke@435: duke@435: // Parse the operands duke@435: skipws(); duke@435: if (cur_char() != ')') { duke@435: duke@435: // Parse the left child duke@435: if (strcmp(operation,"Set")) duke@435: lChild = matchChild_parse(operands, lParens, numleaves, false); duke@435: else duke@435: lChild = matchChild_parse(operands, lParens, numleaves, true); duke@435: duke@435: skipws(); duke@435: if (cur_char() != ')' ) { duke@435: if(strcmp(operation, "Set")) duke@435: rChild = matchChild_parse(operands,rParens,numleaves,false); duke@435: else duke@435: rChild = matchChild_parse(operands,rParens,numleaves,true); duke@435: } duke@435: } duke@435: duke@435: // Check for required ')' duke@435: skipws(); duke@435: if (cur_char() != ')') { duke@435: parse_err(SYNERR, "missing ')' in match expression\n"); duke@435: return NULL; duke@435: } duke@435: next_char(); // skip the ')' duke@435: duke@435: MatchNode* mroot = new MatchNode(_AD,result,name,operation,lChild,rChild); duke@435: duke@435: // If not the root, reduce this subtree to an internal operand duke@435: if (!atroot) { duke@435: mroot->build_internalop(); duke@435: } duke@435: // depth is greater of left and right paths. duke@435: depth = (lParens > rParens) ? lParens : rParens; duke@435: duke@435: return mroot; duke@435: } duke@435: duke@435: duke@435: //------------------------------matchChild_parse------------------------------- duke@435: MatchNode *ADLParser::matchChild_parse(FormDict &operands, int &parens, int &numleaves, bool atroot) { duke@435: MatchNode *child = NULL; duke@435: const char *result = NULL; duke@435: const char *token = NULL; duke@435: const char *opType = NULL; duke@435: duke@435: if (cur_char() == '(') { // child is an operation duke@435: ++parens; duke@435: child = matchNode_parse(operands, parens, numleaves, atroot); duke@435: } duke@435: else { // child is an operand duke@435: token = get_ident(); duke@435: const Form *form = operands[token]; duke@435: OpClassForm *opcForm = form ? form->is_opclass() : NULL; duke@435: if (opcForm != NULL) { duke@435: opType = opcForm->_ident; duke@435: result = opcForm->_ident; // an operand's result matches its type duke@435: } else { duke@435: parse_err(SYNERR, "undefined operand %s in match rule\n", token); duke@435: return NULL; duke@435: } duke@435: duke@435: if (opType == NULL) { duke@435: parse_err(SYNERR, "missing type for argument '%s'\n", token); duke@435: } duke@435: duke@435: child = new MatchNode(_AD, result, token, opType); duke@435: ++numleaves; duke@435: } duke@435: duke@435: return child; duke@435: } duke@435: duke@435: duke@435: duke@435: // ******************** Private Utility Functions ************************* duke@435: duke@435: duke@435: char* ADLParser::find_cpp_block(const char* description) { duke@435: char *next; // Pointer for finding block delimiters duke@435: char* cppBlock = NULL; // Beginning of C++ code block duke@435: duke@435: if (_curchar == '%') { // Encoding is a C++ expression duke@435: next_char(); duke@435: if (_curchar != '{') { duke@435: parse_err(SYNERR, "missing '{' in %s \n", description); duke@435: return NULL; duke@435: } duke@435: next_char(); // Skip block delimiter duke@435: skipws_no_preproc(); // Skip leading whitespace duke@435: cppBlock = _ptr; // Point to start of expression jrose@910: int line = linenum(); duke@435: next = _ptr + 1; duke@435: while(((_curchar != '%') || (*next != '}')) && (_curchar != '\0')) { duke@435: next_char_or_line(); duke@435: next = _ptr+1; // Maintain the next pointer duke@435: } // Grab string duke@435: if (_curchar == '\0') { duke@435: parse_err(SYNERR, "invalid termination of %s \n", description); duke@435: return NULL; duke@435: } duke@435: *_ptr = '\0'; // Terminate string duke@435: _ptr += 2; // Skip block delimiter duke@435: _curchar = *_ptr; // Maintain invariant duke@435: duke@435: // Prepend location descriptor, for debugging. jrose@910: if (_AD._adlocation_debug) { jrose@910: char* location = get_line_string(line); jrose@910: char* end_loc = end_line_marker(); jrose@910: char* result = (char *)malloc(strlen(location) + strlen(cppBlock) + strlen(end_loc) + 1); jrose@910: strcpy(result, location); jrose@910: strcat(result, cppBlock); jrose@910: strcat(result, end_loc); jrose@910: cppBlock = result; jrose@910: free(location); jrose@910: } duke@435: } duke@435: duke@435: return cppBlock; duke@435: } duke@435: duke@435: // Move to the closing token of the expression we are currently at, duke@435: // as defined by stop_chars. Match parens and quotes. duke@435: char* ADLParser::get_expr(const char *desc, const char *stop_chars) { duke@435: char* expr = NULL; duke@435: int paren = 0; duke@435: duke@435: expr = _ptr; duke@435: while (paren > 0 || !strchr(stop_chars, _curchar)) { duke@435: if (_curchar == '(') { // Down level of nesting duke@435: paren++; // Bump the parenthesis counter duke@435: next_char(); // maintain the invariant duke@435: } duke@435: else if (_curchar == ')') { // Up one level of nesting duke@435: if (paren == 0) { duke@435: // Paren underflow: We didn't encounter the required stop-char. duke@435: parse_err(SYNERR, "too many )'s, did not find %s after %s\n", duke@435: stop_chars, desc); duke@435: return NULL; duke@435: } duke@435: paren--; // Drop the parenthesis counter duke@435: next_char(); // Maintain the invariant duke@435: } duke@435: else if (_curchar == '"' || _curchar == '\'') { duke@435: int qchar = _curchar; duke@435: while (true) { duke@435: next_char(); duke@435: if (_curchar == qchar) { next_char(); break; } duke@435: if (_curchar == '\\') next_char(); // superquote duke@435: if (_curchar == '\n' || _curchar == '\0') { duke@435: parse_err(SYNERR, "newline in string in %s\n", desc); duke@435: return NULL; duke@435: } duke@435: } duke@435: } duke@435: else if (_curchar == '%' && (_ptr[1] == '{' || _ptr[1] == '}')) { duke@435: // Make sure we do not stray into the next ADLC-level form. duke@435: parse_err(SYNERR, "unexpected %%%c in %s\n", _ptr[1], desc); duke@435: return NULL; duke@435: } duke@435: else if (_curchar == '\0') { duke@435: parse_err(SYNERR, "unexpected EOF in %s\n", desc); duke@435: return NULL; duke@435: } duke@435: else { duke@435: // Always walk over whitespace, comments, preprocessor directives, etc. duke@435: char* pre_skip_ptr = _ptr; duke@435: skipws(); duke@435: // If the parser declined to make progress on whitespace, duke@435: // skip the next character, which is therefore NOT whitespace. duke@435: if (pre_skip_ptr == _ptr) { duke@435: next_char(); duke@435: } else if (pre_skip_ptr+strlen(pre_skip_ptr) != _ptr+strlen(_ptr)) { duke@435: parse_err(SYNERR, "unimplemented: preprocessor must not elide subexpression in %s", desc); duke@435: } duke@435: } duke@435: } duke@435: duke@435: assert(strchr(stop_chars, _curchar), "non-null return must be at stop-char"); duke@435: *_ptr = '\0'; // Replace ')' or other stop-char with '\0' duke@435: return expr; duke@435: } duke@435: duke@435: // Helper function around get_expr duke@435: // Sets _curchar to '(' so that get_paren_expr will search for a matching ')' jrose@910: char *ADLParser::get_paren_expr(const char *description, bool include_location) { jrose@910: int line = linenum(); duke@435: if (_curchar != '(') // Escape if not valid starting position duke@435: return NULL; duke@435: next_char(); // Skip the required initial paren. duke@435: char *token2 = get_expr(description, ")"); duke@435: if (_curchar == ')') duke@435: next_char(); // Skip required final paren. jrose@910: int junk = 0; jrose@910: if (include_location && _AD._adlocation_debug && !is_int_token(token2, junk)) { jrose@910: // Prepend location descriptor, for debugging. jrose@910: char* location = get_line_string(line); jrose@910: char* end_loc = end_line_marker(); jrose@910: char* result = (char *)malloc(strlen(location) + strlen(token2) + strlen(end_loc) + 1); jrose@910: strcpy(result, location); jrose@910: strcat(result, token2); jrose@910: strcat(result, end_loc); jrose@910: token2 = result; jrose@910: free(location); jrose@910: } duke@435: return token2; duke@435: } duke@435: duke@435: //------------------------------get_ident_common------------------------------- duke@435: // Looks for an identifier in the buffer, and turns it into a null terminated duke@435: // string(still inside the file buffer). Returns a pointer to the string or duke@435: // NULL if some other token is found instead. duke@435: char *ADLParser::get_ident_common(bool do_preproc) { duke@435: register char c; duke@435: char *start; // Pointer to start of token duke@435: char *end; // Pointer to end of token duke@435: duke@435: if( _curline == NULL ) // Return NULL at EOF. duke@435: return NULL; duke@435: duke@435: skipws_common(do_preproc); // Skip whitespace before identifier duke@435: start = end = _ptr; // Start points at first character duke@435: end--; // unwind end by one to prepare for loop duke@435: do { duke@435: end++; // Increment end pointer duke@435: c = *end; // Grab character to test duke@435: } while ( ((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z')) duke@435: || ((c >= '0') && (c <= '9')) duke@435: || ((c == '_')) || ((c == ':')) || ((c == '#')) ); duke@435: if (start == end) { // We popped out on the first try duke@435: parse_err(SYNERR, "identifier expected at %c\n", c); duke@435: start = NULL; duke@435: } duke@435: else { duke@435: _curchar = c; // Save the first character of next token duke@435: *end = '\0'; // NULL terminate the string in place duke@435: } duke@435: _ptr = end; // Reset _ptr to point to next char after token duke@435: duke@435: // Make sure we do not try to use #defined identifiers. If start is duke@435: // NULL an error was already reported. duke@435: if (do_preproc && start != NULL) { duke@435: const char* def = _AD.get_preproc_def(start); duke@435: if (def != NULL && strcmp(def, start)) { jrose@910: const char* def1 = def; jrose@910: const char* def2 = _AD.get_preproc_def(def1); jrose@910: // implement up to 2 levels of #define jrose@910: if (def2 != NULL && strcmp(def2, def1)) { jrose@910: def = def2; jrose@910: const char* def3 = _AD.get_preproc_def(def2); jrose@910: if (def3 != NULL && strcmp(def3, def2) && strcmp(def3, def1)) { jrose@910: parse_err(SYNERR, "unimplemented: using %s defined as %s => %s => %s", jrose@910: start, def1, def2, def3); jrose@910: } duke@435: } duke@435: start = strdup(def); duke@435: } duke@435: } duke@435: duke@435: return start; // Pointer to token in filebuf duke@435: } duke@435: duke@435: //------------------------------get_ident_dup---------------------------------- duke@435: // Looks for an identifier in the buffer, and returns a duplicate duke@435: // or NULL if some other token is found instead. duke@435: char *ADLParser::get_ident_dup(void) { duke@435: char *ident = get_ident(); duke@435: duke@435: // Duplicate an identifier before returning and restore string. duke@435: if( ident != NULL ) { duke@435: ident = strdup(ident); // Copy the string duke@435: *_ptr = _curchar; // and replace Nil with original character duke@435: } duke@435: duke@435: return ident; duke@435: } duke@435: duke@435: //----------------------get_ident_or_literal_constant-------------------------- duke@435: // Looks for an identifier in the buffer, or a parenthesized expression. duke@435: char *ADLParser::get_ident_or_literal_constant(const char* description) { duke@435: char* param = NULL; duke@435: skipws(); duke@435: if (_curchar == '(') { duke@435: // Grab a constant expression. duke@435: param = get_paren_expr(description); duke@435: if (param[0] != '(') { duke@435: char* buf = (char*) malloc(strlen(param) + 3); duke@435: sprintf(buf, "(%s)", param); duke@435: param = buf; duke@435: } duke@435: assert(is_literal_constant(param), duke@435: "expr must be recognizable as a constant"); duke@435: } else { duke@435: param = get_ident(); duke@435: } duke@435: return param; duke@435: } duke@435: duke@435: //------------------------------get_rep_var_ident----------------------------- duke@435: // Do NOT duplicate, duke@435: // Leave nil terminator in buffer duke@435: // Preserve initial '$'(s) in string duke@435: char *ADLParser::get_rep_var_ident(void) { duke@435: // Remember starting point duke@435: char *rep_var = _ptr; duke@435: duke@435: // Check for replacement variable indicator '$' and pass if present duke@435: if ( _curchar == '$' ) { duke@435: next_char(); duke@435: } duke@435: // Check for a subfield indicator, a second '$', and pass if present duke@435: if ( _curchar == '$' ) { duke@435: next_char(); duke@435: } duke@435: duke@435: // Check for a control indicator, a third '$': duke@435: if ( _curchar == '$' ) { duke@435: next_char(); duke@435: } duke@435: duke@435: // Check for more than three '$'s in sequence, SYNERR duke@435: if( _curchar == '$' ) { duke@435: parse_err(SYNERR, "Replacement variables and field specifiers can not start with '$$$$'"); duke@435: next_char(); duke@435: return NULL; duke@435: } duke@435: duke@435: // Nil terminate the variable name following the '$' duke@435: char *rep_var_name = get_ident(); duke@435: assert( rep_var_name != NULL, duke@435: "Missing identifier after replacement variable indicator '$'"); duke@435: duke@435: return rep_var; duke@435: } duke@435: duke@435: duke@435: duke@435: //------------------------------get_rep_var_ident_dup------------------------- duke@435: // Return the next replacement variable identifier, skipping first '$' duke@435: // given a pointer into a line of the buffer. duke@435: // Null terminates string, still inside the file buffer, duke@435: // Returns a pointer to a copy of the string, or NULL on failure duke@435: char *ADLParser::get_rep_var_ident_dup(void) { duke@435: if( _curchar != '$' ) return NULL; duke@435: duke@435: next_char(); // Move past the '$' duke@435: char *rep_var = _ptr; // Remember starting point duke@435: duke@435: // Check for a subfield indicator, a second '$': duke@435: if ( _curchar == '$' ) { duke@435: next_char(); duke@435: } duke@435: duke@435: // Check for a control indicator, a third '$': duke@435: if ( _curchar == '$' ) { duke@435: next_char(); duke@435: } duke@435: duke@435: // Check for more than three '$'s in sequence, SYNERR duke@435: if( _curchar == '$' ) { duke@435: parse_err(SYNERR, "Replacement variables and field specifiers can not start with '$$$$'"); duke@435: next_char(); duke@435: return NULL; duke@435: } duke@435: duke@435: // Nil terminate the variable name following the '$' duke@435: char *rep_var_name = get_ident(); duke@435: assert( rep_var_name != NULL, duke@435: "Missing identifier after replacement variable indicator '$'"); duke@435: rep_var = strdup(rep_var); // Copy the string duke@435: *_ptr = _curchar; // and replace Nil with original character duke@435: duke@435: return rep_var; duke@435: } duke@435: duke@435: duke@435: //------------------------------get_unique_ident------------------------------ duke@435: // Looks for an identifier in the buffer, terminates it with a NULL, duke@435: // and checks that it is unique duke@435: char *ADLParser::get_unique_ident(FormDict& dict, const char* nameDescription){ duke@435: char* ident = get_ident(); duke@435: duke@435: if (ident == NULL) { duke@435: parse_err(SYNERR, "missing %s identifier at %c\n", nameDescription, _curchar); duke@435: } duke@435: else { duke@435: if (dict[ident] != NULL) { duke@435: parse_err(SYNERR, "duplicate name %s for %s\n", ident, nameDescription); duke@435: ident = NULL; duke@435: } duke@435: } duke@435: duke@435: return ident; duke@435: } duke@435: duke@435: duke@435: //------------------------------get_int---------------------------------------- duke@435: // Looks for a character string integer in the buffer, and turns it into an int duke@435: // invokes a parse_err if the next token is not an integer. duke@435: // This routine does not leave the integer null-terminated. duke@435: int ADLParser::get_int(void) { duke@435: register char c; duke@435: char *start; // Pointer to start of token duke@435: char *end; // Pointer to end of token duke@435: int result; // Storage for integer result duke@435: duke@435: if( _curline == NULL ) // Return NULL at EOF. twisti@1038: return 0; duke@435: duke@435: skipws(); // Skip whitespace before identifier duke@435: start = end = _ptr; // Start points at first character duke@435: c = *end; // Grab character to test duke@435: while ((c >= '0') && (c <= '9') duke@435: || ((c == '-') && (end == start))) { duke@435: end++; // Increment end pointer duke@435: c = *end; // Grab character to test duke@435: } duke@435: if (start == end) { // We popped out on the first try duke@435: parse_err(SYNERR, "integer expected at %c\n", c); duke@435: result = 0; duke@435: } duke@435: else { duke@435: _curchar = c; // Save the first character of next token duke@435: *end = '\0'; // NULL terminate the string in place duke@435: result = atoi(start); // Convert the string to an integer duke@435: *end = _curchar; // Restore buffer to original condition duke@435: } duke@435: duke@435: // Reset _ptr to next char after token duke@435: _ptr = end; duke@435: duke@435: return result; // integer duke@435: } duke@435: duke@435: duke@435: //------------------------------get_relation_dup------------------------------ duke@435: // Looks for a relational operator in the buffer duke@435: // invokes a parse_err if the next token is not a relation duke@435: // This routine creates a duplicate of the string in the buffer. duke@435: char *ADLParser::get_relation_dup(void) { duke@435: char *result = NULL; // relational operator being returned duke@435: duke@435: if( _curline == NULL ) // Return NULL at EOF. duke@435: return NULL; duke@435: duke@435: skipws(); // Skip whitespace before relation duke@435: char *start = _ptr; // Store start of relational operator duke@435: char first = *_ptr; // the first character duke@435: if( (first == '=') || (first == '!') || (first == '<') || (first == '>') ) { duke@435: next_char(); duke@435: char second = *_ptr; // the second character duke@435: if( (second == '=') ) { duke@435: next_char(); duke@435: char tmp = *_ptr; duke@435: *_ptr = '\0'; // NULL terminate duke@435: result = strdup(start); // Duplicate the string duke@435: *_ptr = tmp; // restore buffer duke@435: } else { duke@435: parse_err(SYNERR, "relational operator expected at %s\n", _ptr); duke@435: } duke@435: } else { duke@435: parse_err(SYNERR, "relational operator expected at %s\n", _ptr); duke@435: } duke@435: duke@435: return result; duke@435: } duke@435: duke@435: duke@435: duke@435: //------------------------------get_oplist------------------------------------- duke@435: // Looks for identifier pairs where first must be the name of an operand, and duke@435: // second must be a name unique in the scope of this instruction. Stores the duke@435: // names with a pointer to the OpClassForm of their type in a local name table. duke@435: void ADLParser::get_oplist(NameList ¶meters, FormDict &operands) { duke@435: OpClassForm *opclass = NULL; duke@435: char *ident = NULL; duke@435: duke@435: do { duke@435: next_char(); // skip open paren & comma characters duke@435: skipws(); duke@435: if (_curchar == ')') break; duke@435: duke@435: // Get operand type, and check it against global name table duke@435: ident = get_ident(); duke@435: if (ident == NULL) { duke@435: parse_err(SYNERR, "optype identifier expected at %c\n", _curchar); duke@435: return; duke@435: } duke@435: else { duke@435: const Form *form = _globalNames[ident]; duke@435: if( form == NULL ) { duke@435: parse_err(SYNERR, "undefined operand type %s\n", ident); duke@435: return; duke@435: } duke@435: duke@435: // Check for valid operand type duke@435: OpClassForm *opc = form->is_opclass(); duke@435: OperandForm *oper = form->is_operand(); duke@435: if((oper == NULL) && (opc == NULL)) { duke@435: parse_err(SYNERR, "identifier %s not operand type\n", ident); duke@435: return; duke@435: } duke@435: opclass = opc; duke@435: } duke@435: // Debugging Stuff duke@435: if (_AD._adl_debug > 1) fprintf(stderr, "\tOperand Type: %s\t", ident); duke@435: duke@435: // Get name of operand and add it to local name table duke@435: if( (ident = get_unique_ident(operands, "operand")) == NULL) { duke@435: return; duke@435: } duke@435: // Parameter names must not be global names. duke@435: if( _globalNames[ident] != NULL ) { duke@435: parse_err(SYNERR, "Reuse of global name %s as operand.\n",ident); duke@435: return; duke@435: } duke@435: operands.Insert(ident, opclass); duke@435: parameters.addName(ident); duke@435: duke@435: // Debugging Stuff duke@435: if (_AD._adl_debug > 1) fprintf(stderr, "\tOperand Name: %s\n", ident); duke@435: skipws(); duke@435: } while(_curchar == ','); duke@435: duke@435: if (_curchar != ')') parse_err(SYNERR, "missing ')'\n"); duke@435: else { duke@435: next_char(); // set current character position past the close paren duke@435: } duke@435: } duke@435: duke@435: duke@435: //------------------------------get_effectlist--------------------------------- duke@435: // Looks for identifier pairs where first must be the name of a pre-defined, duke@435: // effect, and the second must be the name of an operand defined in the duke@435: // operand list of this instruction. Stores the names with a pointer to the duke@435: // effect form in a local effects table. duke@435: void ADLParser::get_effectlist(FormDict &effects, FormDict &operands) { duke@435: OperandForm *opForm; duke@435: Effect *eForm; duke@435: char *ident; duke@435: duke@435: do { duke@435: next_char(); // skip open paren & comma characters duke@435: skipws(); duke@435: if (_curchar == ')') break; duke@435: duke@435: // Get effect type, and check it against global name table duke@435: ident = get_ident(); duke@435: if (ident == NULL) { duke@435: parse_err(SYNERR, "effect type identifier expected at %c\n", _curchar); duke@435: return; duke@435: } duke@435: else { duke@435: // Check for valid effect type duke@435: const Form *form = _globalNames[ident]; duke@435: if( form == NULL ) { duke@435: parse_err(SYNERR, "undefined effect type %s\n", ident); duke@435: return; duke@435: } duke@435: else { duke@435: if( (eForm = form->is_effect()) == NULL) { duke@435: parse_err(SYNERR, "identifier %s not effect type\n", ident); duke@435: return; duke@435: } duke@435: } duke@435: } duke@435: // Debugging Stuff duke@435: if (_AD._adl_debug > 1) fprintf(stderr, "\tEffect Type: %s\t", ident); duke@435: skipws(); duke@435: // Get name of operand and check that it is in the local name table duke@435: if( (ident = get_unique_ident(effects, "effect")) == NULL) { duke@435: parse_err(SYNERR, "missing operand identifier in effect list\n"); duke@435: return; duke@435: } duke@435: const Form *form = operands[ident]; duke@435: opForm = form ? form->is_operand() : NULL; duke@435: if( opForm == NULL ) { duke@435: if( form && form->is_opclass() ) { duke@435: const char* cname = form->is_opclass()->_ident; duke@435: parse_err(SYNERR, "operand classes are illegal in effect lists (found %s %s)\n", cname, ident); duke@435: } else { duke@435: parse_err(SYNERR, "undefined operand %s in effect list\n", ident); duke@435: } duke@435: return; duke@435: } duke@435: // Add the pair to the effects table duke@435: effects.Insert(ident, eForm); duke@435: // Debugging Stuff duke@435: if (_AD._adl_debug > 1) fprintf(stderr, "\tOperand Name: %s\n", ident); duke@435: skipws(); duke@435: } while(_curchar == ','); duke@435: duke@435: if (_curchar != ')') parse_err(SYNERR, "missing ')'\n"); duke@435: else { duke@435: next_char(); // set current character position past the close paren duke@435: } duke@435: } duke@435: duke@435: jrose@910: //-------------------------------preproc_line---------------------------------- jrose@910: // A "#line" keyword has been seen, so parse the rest of the line. jrose@910: void ADLParser::preproc_line(void) { jrose@910: int line = get_int(); jrose@910: skipws_no_preproc(); jrose@910: const char* file = NULL; jrose@910: if (_curchar == '"') { jrose@910: next_char(); // Move past the initial '"' jrose@910: file = _ptr; jrose@910: while (true) { jrose@910: if (_curchar == '\n') { jrose@910: parse_err(SYNERR, "missing '\"' at end of #line directive"); jrose@910: return; jrose@910: } jrose@910: if (_curchar == '"') { jrose@910: *_ptr = '\0'; // Terminate the string jrose@910: next_char(); jrose@910: skipws_no_preproc(); jrose@910: break; jrose@910: } jrose@910: next_char(); jrose@910: } jrose@910: } jrose@910: ensure_end_of_line(); jrose@910: if (file != NULL) jrose@910: _AD._ADL_file._name = file; jrose@910: _buf.set_linenum(line); jrose@910: } jrose@910: duke@435: //------------------------------preproc_define--------------------------------- duke@435: // A "#define" keyword has been seen, so parse the rest of the line. duke@435: void ADLParser::preproc_define(void) { duke@435: char* flag = get_ident_no_preproc(); duke@435: skipws_no_preproc(); duke@435: // only #define x y is supported for now duke@435: char* def = get_ident_no_preproc(); duke@435: _AD.set_preproc_def(flag, def); duke@435: skipws_no_preproc(); duke@435: if (_curchar != '\n') { duke@435: parse_err(SYNERR, "non-identifier in preprocessor definition\n"); duke@435: } duke@435: } duke@435: duke@435: //------------------------------preproc_undef---------------------------------- duke@435: // An "#undef" keyword has been seen, so parse the rest of the line. duke@435: void ADLParser::preproc_undef(void) { duke@435: char* flag = get_ident_no_preproc(); duke@435: skipws_no_preproc(); duke@435: ensure_end_of_line(); duke@435: _AD.set_preproc_def(flag, NULL); duke@435: } duke@435: duke@435: duke@435: duke@435: //------------------------------parse_err-------------------------------------- duke@435: // Issue a parser error message, and skip to the end of the current line duke@435: void ADLParser::parse_err(int flag, const char *fmt, ...) { duke@435: va_list args; duke@435: duke@435: va_start(args, fmt); duke@435: if (flag == 1) never@850: _AD._syntax_errs += _AD.emit_msg(0, flag, linenum(), fmt, args); duke@435: else if (flag == 2) never@850: _AD._semantic_errs += _AD.emit_msg(0, flag, linenum(), fmt, args); duke@435: else never@850: _AD._warnings += _AD.emit_msg(0, flag, linenum(), fmt, args); duke@435: duke@435: int error_char = _curchar; duke@435: char* error_ptr = _ptr+1; duke@435: for(;*_ptr != '\n'; _ptr++) ; // Skip to the end of the current line duke@435: _curchar = '\n'; duke@435: va_end(args); duke@435: _AD._no_output = 1; duke@435: duke@435: if (flag == 1) { duke@435: char* error_tail = strchr(error_ptr, '\n'); duke@435: char tem = *error_ptr; duke@435: error_ptr[-1] = '\0'; duke@435: char* error_head = error_ptr-1; duke@435: while (error_head > _curline && *error_head) --error_head; duke@435: if (error_tail) *error_tail = '\0'; duke@435: fprintf(stderr, "Error Context: %s>>>%c<<<%s\n", duke@435: error_head, error_char, error_ptr); duke@435: if (error_tail) *error_tail = '\n'; duke@435: error_ptr[-1] = tem; duke@435: } duke@435: } duke@435: duke@435: //---------------------------ensure_start_of_line------------------------------ duke@435: // A preprocessor directive has been encountered. Be sure it has fallen at twisti@1040: // the beginning of a line, or else report an error. duke@435: void ADLParser::ensure_start_of_line(void) { jrose@910: if (_curchar == '\n') { next_line(); return; } duke@435: assert( _ptr >= _curline && _ptr < _curline+strlen(_curline), duke@435: "Must be able to find which line we are in" ); duke@435: duke@435: for (char *s = _curline; s < _ptr; s++) { duke@435: if (*s > ' ') { duke@435: parse_err(SYNERR, "'%c' must be at beginning of line\n", _curchar); duke@435: break; duke@435: } duke@435: } duke@435: } duke@435: duke@435: //---------------------------ensure_end_of_line-------------------------------- duke@435: // A preprocessor directive has been parsed. Be sure there is no trailing duke@435: // garbage at the end of this line. Set the scan point to the beginning of duke@435: // the next line. duke@435: void ADLParser::ensure_end_of_line(void) { duke@435: skipws_no_preproc(); duke@435: if (_curchar != '\n' && _curchar != '\0') { duke@435: parse_err(SYNERR, "garbage char '%c' at end of line\n", _curchar); duke@435: } else { duke@435: next_char_or_line(); duke@435: } duke@435: } duke@435: duke@435: //---------------------------handle_preproc------------------------------------ duke@435: // The '#' character introducing a preprocessor directive has been found. duke@435: // Parse the whole directive name (e.g., #define, #endif) and take appropriate duke@435: // action. If we are in an "untaken" span of text, simply keep track of duke@435: // #ifdef nesting structure, so we can find out when to start taking text duke@435: // again. (In this state, we "sort of support" C's #if directives, enough duke@435: // to disregard their associated #else and #endif lines.) If we are in a duke@435: // "taken" span of text, there are two cases: "#define" and "#undef" duke@435: // directives are preserved and passed up to the caller, which eventually duke@435: // passes control to the top-level parser loop, which handles #define and duke@435: // #undef directly. (This prevents these directives from occurring in duke@435: // arbitrary positions in the AD file--we require better structure than C.) duke@435: // In the other case, and #ifdef, #ifndef, #else, or #endif is silently duke@435: // processed as whitespace, with the "taken" state of the text correctly duke@435: // updated. This routine returns "false" exactly in the case of a "taken" duke@435: // #define or #undef, which tells the caller that a preprocessor token duke@435: // has appeared which must be handled explicitly by the parse loop. duke@435: bool ADLParser::handle_preproc_token() { duke@435: assert(*_ptr == '#', "must be at start of preproc"); duke@435: ensure_start_of_line(); duke@435: next_char(); duke@435: skipws_no_preproc(); duke@435: char* start_ident = _ptr; duke@435: char* ident = (_curchar == '\n') ? NULL : get_ident_no_preproc(); duke@435: if (ident == NULL) { duke@435: parse_err(SYNERR, "expected preprocessor command, got end of line\n"); duke@435: } else if (!strcmp(ident, "ifdef") || duke@435: !strcmp(ident, "ifndef")) { duke@435: char* flag = get_ident_no_preproc(); duke@435: ensure_end_of_line(); duke@435: // Test the identifier only if we are already in taken code: duke@435: bool flag_def = preproc_taken() && (_AD.get_preproc_def(flag) != NULL); duke@435: bool now_taken = !strcmp(ident, "ifdef") ? flag_def : !flag_def; duke@435: begin_if_def(now_taken); duke@435: } else if (!strcmp(ident, "if")) { duke@435: if (preproc_taken()) duke@435: parse_err(SYNERR, "unimplemented: #%s %s", ident, _ptr+1); duke@435: next_line(); duke@435: // Intelligently skip this nested C preprocessor directive: duke@435: begin_if_def(true); duke@435: } else if (!strcmp(ident, "else")) { duke@435: ensure_end_of_line(); duke@435: invert_if_def(); duke@435: } else if (!strcmp(ident, "endif")) { duke@435: ensure_end_of_line(); duke@435: end_if_def(); duke@435: } else if (preproc_taken()) { duke@435: // pass this token up to the main parser as "#define" or "#undef" duke@435: _ptr = start_ident; duke@435: _curchar = *--_ptr; duke@435: if( _curchar != '#' ) { duke@435: parse_err(SYNERR, "no space allowed after # in #define or #undef"); duke@435: assert(_curchar == '#', "no space allowed after # in #define or #undef"); duke@435: } duke@435: return false; duke@435: } duke@435: return true; duke@435: } duke@435: duke@435: //---------------------------skipws_common------------------------------------- duke@435: // Skip whitespace, including comments and newlines, while keeping an accurate duke@435: // line count. duke@435: // Maybe handle certain preprocessor constructs: #ifdef, #ifndef, #else, #endif duke@435: void ADLParser::skipws_common(bool do_preproc) { duke@435: char *start = _ptr; duke@435: char *next = _ptr + 1; duke@435: duke@435: if (*_ptr == '\0') { duke@435: // Check for string terminator duke@435: if (_curchar > ' ') return; duke@435: if (_curchar == '\n') { duke@435: if (!do_preproc) return; // let caller handle the newline duke@435: next_line(); duke@435: _ptr = _curline; next = _ptr + 1; duke@435: } duke@435: else if (_curchar == '#' || duke@435: (_curchar == '/' && (*next == '/' || *next == '*'))) { duke@435: parse_err(SYNERR, "unimplemented: comment token in a funny place"); duke@435: } duke@435: } duke@435: while(_curline != NULL) { // Check for end of file duke@435: if (*_ptr == '\n') { // keep proper track of new lines duke@435: if (!do_preproc) break; // let caller handle the newline duke@435: next_line(); duke@435: _ptr = _curline; next = _ptr + 1; duke@435: } duke@435: else if ((*_ptr == '/') && (*next == '/')) // C++ comment duke@435: do { _ptr++; next++; } while(*_ptr != '\n'); // So go to end of line duke@435: else if ((*_ptr == '/') && (*next == '*')) { // C comment duke@435: _ptr++; next++; duke@435: do { duke@435: _ptr++; next++; duke@435: if (*_ptr == '\n') { // keep proper track of new lines duke@435: next_line(); // skip newlines within comments duke@435: if (_curline == NULL) { // check for end of file duke@435: parse_err(SYNERR, "end-of-file detected inside comment\n"); duke@435: break; duke@435: } duke@435: _ptr = _curline; next = _ptr + 1; duke@435: } duke@435: } while(!((*_ptr == '*') && (*next == '/'))); // Go to end of comment duke@435: _ptr = ++next; next++; // increment _ptr past comment end duke@435: } duke@435: else if (do_preproc && *_ptr == '#') { duke@435: // Note that this calls skipws_common(false) recursively! duke@435: bool preproc_handled = handle_preproc_token(); duke@435: if (!preproc_handled) { duke@435: if (preproc_taken()) { duke@435: return; // short circuit duke@435: } duke@435: ++_ptr; // skip the preprocessor character duke@435: } duke@435: next = _ptr+1; duke@435: } else if(*_ptr > ' ' && !(do_preproc && !preproc_taken())) { duke@435: break; duke@435: } duke@435: else if (*_ptr == '"' || *_ptr == '\'') { duke@435: assert(do_preproc, "only skip strings if doing preproc"); duke@435: // skip untaken quoted string duke@435: int qchar = *_ptr; duke@435: while (true) { duke@435: ++_ptr; duke@435: if (*_ptr == qchar) { ++_ptr; break; } duke@435: if (*_ptr == '\\') ++_ptr; duke@435: if (*_ptr == '\n' || *_ptr == '\0') { duke@435: parse_err(SYNERR, "newline in string"); duke@435: break; duke@435: } duke@435: } duke@435: next = _ptr + 1; duke@435: } duke@435: else { ++_ptr; ++next; } duke@435: } duke@435: if( _curline != NULL ) // at end of file _curchar isn't valid duke@435: _curchar = *_ptr; // reset _curchar to maintain invariant duke@435: } duke@435: duke@435: //---------------------------cur_char----------------------------------------- duke@435: char ADLParser::cur_char() { duke@435: return (_curchar); duke@435: } duke@435: duke@435: //---------------------------next_char----------------------------------------- duke@435: void ADLParser::next_char() { jrose@910: if (_curchar == '\n') parse_err(WARN, "must call next_line!"); duke@435: _curchar = *++_ptr; duke@435: // if ( _curchar == '\n' ) { duke@435: // next_line(); duke@435: // } duke@435: } duke@435: duke@435: //---------------------------next_char_or_line--------------------------------- duke@435: void ADLParser::next_char_or_line() { duke@435: if ( _curchar != '\n' ) { duke@435: _curchar = *++_ptr; duke@435: } else { duke@435: next_line(); duke@435: _ptr = _curline; duke@435: _curchar = *_ptr; // maintain invariant duke@435: } duke@435: } duke@435: duke@435: //---------------------------next_line----------------------------------------- duke@435: void ADLParser::next_line() { never@850: _curline = _buf.get_line(); jrose@910: _curchar = ' '; jrose@910: } jrose@910: jrose@910: //------------------------get_line_string-------------------------------------- jrose@910: // Prepended location descriptor, for debugging. jrose@910: // Must return a malloced string (that can be freed if desired). jrose@910: char* ADLParser::get_line_string(int linenum) { jrose@910: const char* file = _AD._ADL_file._name; jrose@910: int line = linenum ? linenum : this->linenum(); jrose@910: char* location = (char *)malloc(strlen(file) + 100); jrose@910: sprintf(location, "\n#line %d \"%s\"\n", line, file); jrose@910: return location; duke@435: } duke@435: duke@435: //-------------------------is_literal_constant--------------------------------- duke@435: bool ADLParser::is_literal_constant(const char *param) { duke@435: if (param[0] == 0) return false; // null string duke@435: if (param[0] == '(') return true; // parenthesized expression duke@435: if (param[0] == '0' && (param[1] == 'x' || param[1] == 'X')) { duke@435: // Make sure it's a hex constant. duke@435: int i = 2; duke@435: do { duke@435: if( !ADLParser::is_hex_digit(*(param+i)) ) return false; duke@435: ++i; duke@435: } while( *(param+i) != 0 ); duke@435: return true; duke@435: } duke@435: return false; duke@435: } duke@435: duke@435: //---------------------------is_hex_digit-------------------------------------- duke@435: bool ADLParser::is_hex_digit(char digit) { duke@435: return ((digit >= '0') && (digit <= '9')) duke@435: ||((digit >= 'a') && (digit <= 'f')) duke@435: ||((digit >= 'A') && (digit <= 'F')); duke@435: } duke@435: duke@435: //---------------------------is_int_token-------------------------------------- duke@435: bool ADLParser::is_int_token(const char* token, int& intval) { duke@435: const char* cp = token; duke@435: while (*cp != '\0' && *cp <= ' ') cp++; duke@435: if (*cp == '-') cp++; duke@435: int ndigit = 0; duke@435: while (*cp >= '0' && *cp <= '9') { cp++; ndigit++; } duke@435: while (*cp != '\0' && *cp <= ' ') cp++; duke@435: if (ndigit == 0 || *cp != '\0') { duke@435: return false; duke@435: } duke@435: intval = atoi(token); duke@435: return true; duke@435: } duke@435: jrose@910: static const char* skip_expr_ws(const char* str) { jrose@910: const char * cp = str; jrose@910: while (cp[0]) { jrose@910: if (cp[0] <= ' ') { jrose@910: ++cp; jrose@910: } else if (cp[0] == '#') { jrose@910: ++cp; jrose@910: while (cp[0] == ' ') ++cp; jrose@910: assert(0 == strncmp(cp, "line", 4), "must be a #line directive"); jrose@910: const char* eol = strchr(cp, '\n'); jrose@910: assert(eol != NULL, "must find end of line"); jrose@910: if (eol == NULL) eol = cp + strlen(cp); jrose@910: cp = eol; jrose@910: } else { jrose@910: break; jrose@910: } jrose@910: } jrose@910: return cp; jrose@910: } jrose@910: jrose@910: //-----------------------equivalent_expressions-------------------------------- jrose@910: bool ADLParser::equivalent_expressions(const char* str1, const char* str2) { jrose@910: if (str1 == str2) jrose@910: return true; jrose@910: else if (str1 == NULL || str2 == NULL) jrose@910: return false; jrose@910: const char* cp1 = str1; jrose@910: const char* cp2 = str2; jrose@910: char in_quote = '\0'; jrose@910: while (cp1[0] && cp2[0]) { jrose@910: if (!in_quote) { jrose@910: // skip spaces and/or cpp directives jrose@910: const char* cp1a = skip_expr_ws(cp1); jrose@910: const char* cp2a = skip_expr_ws(cp2); jrose@910: if (cp1a > cp1 && cp2a > cp2) { jrose@910: cp1 = cp1a; cp2 = cp2a; jrose@910: continue; jrose@910: } jrose@910: if (cp1a > cp1 || cp2a > cp2) break; // fail jrose@910: } jrose@910: // match one non-space char jrose@910: if (cp1[0] != cp2[0]) break; // fail jrose@910: char ch = cp1[0]; jrose@910: cp1++; cp2++; jrose@910: // watch for quotes jrose@910: if (in_quote && ch == '\\') { jrose@910: if (cp1[0] != cp2[0]) break; // fail jrose@910: if (!cp1[0]) break; jrose@910: cp1++; cp2++; jrose@910: } jrose@910: if (in_quote && ch == in_quote) { jrose@910: in_quote = '\0'; jrose@910: } else if (!in_quote && (ch == '"' || ch == '\'')) { jrose@910: in_quote = ch; jrose@910: } jrose@910: } jrose@910: return (!cp1[0] && !cp2[0]); jrose@910: } jrose@910: jrose@910: duke@435: //-------------------------------trim------------------------------------------ duke@435: void ADLParser::trim(char* &token) { duke@435: while (*token <= ' ') token++; duke@435: char* end = token + strlen(token); duke@435: while (end > token && *(end-1) <= ' ') --end; duke@435: *end = '\0'; duke@435: }