Path: blob/master/src/hotspot/share/adlc/adlparse.cpp
41145 views
/*1* Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*22*/2324// ADLPARSE.CPP - Architecture Description Language Parser25// Authors: Chris Vick and Mike Paleczny26#include "adlc.hpp"2728//----------------------------ADLParser----------------------------------------29// Create a new ADL parser30ADLParser::ADLParser(FileBuff& buffer, ArchDesc& archDesc)31: _buf(buffer), _AD(archDesc),32_globalNames(archDesc.globalNames()) {33_AD._syntax_errs = _AD._semantic_errs = 0; // No errors so far this file34_AD._warnings = 0; // No warnings either35_curline = _ptr = NULL; // No pointers into buffer yet3637_preproc_depth = 0;38_preproc_not_taken = 0;3940// Delimit command-line definitions from in-file definitions:41_AD._preproc_list.add_signal();42}4344//------------------------------~ADLParser-------------------------------------45// Delete an ADL parser.46ADLParser::~ADLParser() {47if (!_AD._quiet_mode)48fprintf(stderr,"---------------------------- Errors and Warnings ----------------------------\n");49#ifndef ASSERT50if (!_AD._quiet_mode) {51fprintf(stderr, "**************************************************************\n");52fprintf(stderr, "***** WARNING: ASSERT is undefined, assertions disabled. *****\n");53fprintf(stderr, "**************************************************************\n");54}55#endif56if( _AD._syntax_errs + _AD._semantic_errs + _AD._warnings == 0 ) {57if (!_AD._quiet_mode)58fprintf(stderr,"No errors or warnings to report from phase-1 parse.\n" );59}60else {61if( _AD._syntax_errs ) { // Any syntax errors?62fprintf(stderr,"%s: Found %d syntax error", _buf._fp->_name, _AD._syntax_errs);63if( _AD._syntax_errs > 1 ) fprintf(stderr,"s.\n\n");64else fprintf(stderr,".\n\n");65}66if( _AD._semantic_errs ) { // Any semantic errors?67fprintf(stderr,"%s: Found %d semantic error", _buf._fp->_name, _AD._semantic_errs);68if( _AD._semantic_errs > 1 ) fprintf(stderr,"s.\n\n");69else fprintf(stderr,".\n\n");70}71if( _AD._warnings ) { // Any warnings?72fprintf(stderr,"%s: Found %d warning", _buf._fp->_name, _AD._warnings);73if( _AD._warnings > 1 ) fprintf(stderr,"s.\n\n");74else fprintf(stderr,".\n\n");75}76}77if (!_AD._quiet_mode)78fprintf(stderr,"-----------------------------------------------------------------------------\n");79_AD._TotalLines += linenum()-1; // -1 for overshoot in "nextline" routine8081// Write out information we have stored82// // UNIXism == fsync(stderr);83}8485//------------------------------parse------------------------------------------86// Each top-level keyword should appear as the first non-whitespace on a line.87//88void ADLParser::parse() {89char *ident;9091// Iterate over the lines in the file buffer parsing Level 1 objects92for( next_line(); _curline != NULL; next_line()) {93_ptr = _curline; // Reset ptr to start of new line94skipws(); // Skip any leading whitespace95ident = get_ident(); // Get first token96if (ident == NULL) { // Empty line97continue; // Get the next line98}99if (!strcmp(ident, "instruct")) instr_parse();100else if (!strcmp(ident, "operand")) oper_parse();101else if (!strcmp(ident, "opclass")) opclass_parse();102else if (!strcmp(ident, "ins_attrib")) ins_attr_parse();103else if (!strcmp(ident, "op_attrib")) op_attr_parse();104else if (!strcmp(ident, "source")) source_parse();105else if (!strcmp(ident, "source_hpp")) source_hpp_parse();106else if (!strcmp(ident, "register")) reg_parse();107else if (!strcmp(ident, "frame")) frame_parse();108else if (!strcmp(ident, "encode")) encode_parse();109else if (!strcmp(ident, "pipeline")) pipe_parse();110else if (!strcmp(ident, "definitions")) definitions_parse();111else if (!strcmp(ident, "peephole")) peep_parse();112else if (!strcmp(ident, "#line")) preproc_line();113else if (!strcmp(ident, "#define")) preproc_define();114else if (!strcmp(ident, "#undef")) preproc_undef();115else {116parse_err(SYNERR, "expected one of - instruct, operand, ins_attrib, op_attrib, source, register, pipeline, encode\n Found %s",ident);117}118}119// Add reg_class spill_regs after parsing.120RegisterForm *regBlock = _AD.get_registers();121if (regBlock == NULL) {122parse_err(SEMERR, "Did not declare 'register' definitions");123}124regBlock->addSpillRegClass();125regBlock->addDynamicRegClass();126127// Done with parsing, check consistency.128129if (_preproc_depth != 0) {130parse_err(SYNERR, "End of file inside #ifdef");131}132133// AttributeForms ins_cost and op_cost must be defined for default behaviour134if (_globalNames[AttributeForm::_ins_cost] == NULL) {135parse_err(SEMERR, "Did not declare 'ins_cost' attribute");136}137if (_globalNames[AttributeForm::_op_cost] == NULL) {138parse_err(SEMERR, "Did not declare 'op_cost' attribute");139}140}141142// ******************** Private Level 1 Parse Functions ********************143//------------------------------instr_parse------------------------------------144// Parse the contents of an instruction definition, build the InstructForm to145// represent that instruction, and add it to the InstructForm list.146void ADLParser::instr_parse(void) {147char *ident;148InstructForm *instr;149MatchRule *rule;150int match_rules_cnt = 0;151152// First get the name of the instruction153if( (ident = get_unique_ident(_globalNames,"instruction")) == NULL )154return;155instr = new InstructForm(ident); // Create new instruction form156instr->_linenum = linenum();157_globalNames.Insert(ident, instr); // Add name to the name table158// Debugging Stuff159if (_AD._adl_debug > 1)160fprintf(stderr,"Parsing Instruction Form %s\n", ident);161162// Then get the operands163skipws();164if (_curchar != '(') {165parse_err(SYNERR, "missing '(' in instruct definition\n");166}167// Parse the operand list168else get_oplist(instr->_parameters, instr->_localNames);169skipws(); // Skip leading whitespace170// Check for block delimiter171if ( (_curchar != '%')172|| ( next_char(), (_curchar != '{')) ) {173parse_err(SYNERR, "missing '%%{' in instruction definition\n");174return;175}176next_char(); // Maintain the invariant177do {178ident = get_ident(); // Grab next identifier179if (ident == NULL) {180parse_err(SYNERR, "keyword identifier expected at %c\n", _curchar);181continue;182}183if (!strcmp(ident, "predicate")) instr->_predicate = pred_parse();184else if (!strcmp(ident, "match")) {185// Allow one instruction have several match rules.186rule = instr->_matrule;187if (rule == NULL) {188// This is first match rule encountered189rule = match_parse(instr->_localNames);190if (rule) {191instr->_matrule = rule;192// Special case the treatment of Control instructions.193if( instr->is_ideal_control() ) {194// Control instructions return a special result, 'Universe'195rule->_result = "Universe";196}197// Check for commutative operations with tree operands.198matchrule_clone_and_swap(rule, instr->_ident, match_rules_cnt);199}200} else {201// Find the end of the match rule list202while (rule->_next != NULL)203rule = rule->_next;204// Add the new match rule to the list205rule->_next = match_parse(instr->_localNames);206if (rule->_next) {207rule = rule->_next;208if( instr->is_ideal_control() ) {209parse_err(SYNERR, "unique match rule expected for %s\n", rule->_name);210return;211}212assert(match_rules_cnt < 100," too many match rule clones");213char* buf = (char*) AllocateHeap(strlen(instr->_ident) + 4);214sprintf(buf, "%s_%d", instr->_ident, match_rules_cnt++);215rule->_result = buf;216// Check for commutative operations with tree operands.217matchrule_clone_and_swap(rule, instr->_ident, match_rules_cnt);218}219}220}221else if (!strcmp(ident, "encode")) {222parse_err(SYNERR, "Instructions specify ins_encode, not encode\n");223}224else if (!strcmp(ident, "ins_encode")) ins_encode_parse(*instr);225// Parse late expand keyword.226else if (!strcmp(ident, "postalloc_expand")) postalloc_expand_parse(*instr);227else if (!strcmp(ident, "opcode")) instr->_opcode = opcode_parse(instr);228else if (!strcmp(ident, "size")) instr->_size = size_parse(instr);229else if (!strcmp(ident, "effect")) effect_parse(instr);230else if (!strcmp(ident, "expand")) instr->_exprule = expand_parse(instr);231else if (!strcmp(ident, "rewrite")) instr->_rewrule = rewrite_parse();232else if (!strcmp(ident, "constraint")) {233parse_err(SYNERR, "Instructions do not specify a constraint\n");234}235else if (!strcmp(ident, "construct")) {236parse_err(SYNERR, "Instructions do not specify a construct\n");237}238else if (!strcmp(ident, "format")) instr->_format = format_parse();239else if (!strcmp(ident, "interface")) {240parse_err(SYNERR, "Instructions do not specify an interface\n");241}242else if (!strcmp(ident, "ins_pipe")) ins_pipe_parse(*instr);243else { // Done with staticly defined parts of instruction definition244// Check identifier to see if it is the name of an attribute245const Form *form = _globalNames[ident];246AttributeForm *attr = form ? form->is_attribute() : NULL;247if (attr && (attr->_atype == INS_ATTR)) {248// Insert the new attribute into the linked list.249Attribute *temp = attr_parse(ident);250temp->_next = instr->_attribs;251instr->_attribs = temp;252} else {253parse_err(SYNERR, "expected one of:\n predicate, match, encode, or the name of"254" an instruction attribute at %s\n", ident);255}256}257skipws();258} while(_curchar != '%');259next_char();260if (_curchar != '}') {261parse_err(SYNERR, "missing '%%}' in instruction definition\n");262return;263}264// Check for "Set" form of chain rule265adjust_set_rule(instr);266if (_AD._pipeline) {267// No pipe required for late expand.268if (instr->expands() || instr->postalloc_expands()) {269if (instr->_ins_pipe) {270parse_err(WARN, "ins_pipe and expand rule both specified for instruction \"%s\";"271" ins_pipe will be unused\n", instr->_ident);272}273} else {274if (!instr->_ins_pipe) {275parse_err(WARN, "No ins_pipe specified for instruction \"%s\"\n", instr->_ident);276}277}278}279// Add instruction to tail of instruction list280_AD.addForm(instr);281282// Create instruction form for each additional match rule283rule = instr->_matrule;284if (rule != NULL) {285rule = rule->_next;286while (rule != NULL) {287ident = (char*)rule->_result;288InstructForm *clone = new InstructForm(ident, instr, rule); // Create new instruction form289_globalNames.Insert(ident, clone); // Add name to the name table290// Debugging Stuff291if (_AD._adl_debug > 1)292fprintf(stderr,"Parsing Instruction Form %s\n", ident);293// Check for "Set" form of chain rule294adjust_set_rule(clone);295// Add instruction to tail of instruction list296_AD.addForm(clone);297rule = rule->_next;298clone->_matrule->_next = NULL; // One match rule per clone299}300}301}302303//------------------------------matchrule_clone_and_swap-----------------------304// Check for commutative operations with subtree operands,305// create clones and swap operands.306void ADLParser::matchrule_clone_and_swap(MatchRule* rule, const char* instr_ident, int& match_rules_cnt) {307// Check for commutative operations with tree operands.308int count = 0;309rule->count_commutative_op(count);310if (count > 0) {311// Clone match rule and swap commutative operation's operands.312rule->matchrule_swap_commutative_op(instr_ident, count, match_rules_cnt);313}314}315316//------------------------------adjust_set_rule--------------------------------317// Check for "Set" form of chain rule318void ADLParser::adjust_set_rule(InstructForm *instr) {319if (instr->_matrule == NULL || instr->_matrule->_rChild == NULL) return;320const char *rch = instr->_matrule->_rChild->_opType;321const Form *frm = _globalNames[rch];322if( (! strcmp(instr->_matrule->_opType,"Set")) &&323frm && frm->is_operand() && (! frm->ideal_only()) ) {324// Previous implementation, which missed leaP*, but worked for loadCon*325unsigned position = 0;326const char *result = NULL;327const char *name = NULL;328const char *optype = NULL;329MatchNode *right = instr->_matrule->_rChild;330if (right->base_operand(position, _globalNames, result, name, optype)) {331position = 1;332const char *result2 = NULL;333const char *name2 = NULL;334const char *optype2 = NULL;335// Can not have additional base operands in right side of match!336if ( ! right->base_operand( position, _globalNames, result2, name2, optype2) ) {337if (instr->_predicate != NULL)338parse_err(SYNERR, "ADLC does not support instruction chain rules with predicates");339// Chain from input _ideal_operand_type_,340// Needed for shared roots of match-trees341ChainList *lst = (ChainList *)_AD._chainRules[optype];342if (lst == NULL) {343lst = new ChainList();344_AD._chainRules.Insert(optype, lst);345}346if (!lst->search(instr->_matrule->_lChild->_opType)) {347const char *cost = instr->cost();348if (cost == NULL) {349cost = ((AttributeForm*)_globalNames[AttributeForm::_ins_cost])->_attrdef;350}351// The ADLC does not support chaining from the ideal operand type352// of a predicated user-defined operand353if( frm->is_operand() == NULL || frm->is_operand()->_predicate == NULL ) {354lst->insert(instr->_matrule->_lChild->_opType,cost,instr->_ident);355}356}357// Chain from input _user_defined_operand_type_,358lst = (ChainList *)_AD._chainRules[result];359if (lst == NULL) {360lst = new ChainList();361_AD._chainRules.Insert(result, lst);362}363if (!lst->search(instr->_matrule->_lChild->_opType)) {364const char *cost = instr->cost();365if (cost == NULL) {366cost = ((AttributeForm*)_globalNames[AttributeForm::_ins_cost])->_attrdef;367}368// It is safe to chain from the top-level user-defined operand even369// if it has a predicate, since the predicate is checked before370// the user-defined type is available.371lst->insert(instr->_matrule->_lChild->_opType,cost,instr->_ident);372}373} else {374// May have instruction chain rule if root of right-tree is an ideal375OperandForm *rightOp = _globalNames[right->_opType]->is_operand();376if( rightOp ) {377const Form *rightRoot = _globalNames[rightOp->_matrule->_opType];378if( rightRoot && rightRoot->ideal_only() ) {379const char *chain_op = NULL;380if( rightRoot->is_instruction() )381chain_op = rightOp->_ident;382if( chain_op ) {383// Look-up the operation in chain rule table384ChainList *lst = (ChainList *)_AD._chainRules[chain_op];385if (lst == NULL) {386lst = new ChainList();387_AD._chainRules.Insert(chain_op, lst);388}389// if (!lst->search(instr->_matrule->_lChild->_opType)) {390const char *cost = instr->cost();391if (cost == NULL) {392cost = ((AttributeForm*)_globalNames[AttributeForm::_ins_cost])->_attrdef;393}394// This chains from a top-level operand whose predicate, if any,395// has been checked.396lst->insert(instr->_matrule->_lChild->_opType,cost,instr->_ident);397// }398}399}400}401} // end chain rule from right-tree's ideal root402}403}404}405406407//------------------------------oper_parse-------------------------------------408void ADLParser::oper_parse(void) {409char *ident;410OperandForm *oper;411AttributeForm *attr;412MatchRule *rule;413414// First get the name of the operand415skipws();416if( (ident = get_unique_ident(_globalNames,"operand")) == NULL )417return;418oper = new OperandForm(ident); // Create new operand form419oper->_linenum = linenum();420_globalNames.Insert(ident, oper); // Add name to the name table421422// Debugging Stuff423if (_AD._adl_debug > 1) fprintf(stderr,"Parsing Operand Form %s\n", ident);424425// Get the component operands426skipws();427if (_curchar != '(') {428parse_err(SYNERR, "missing '(' in operand definition\n");429return;430}431else get_oplist(oper->_parameters, oper->_localNames); // Parse the component operand list432skipws();433// Check for block delimiter434if ((_curchar != '%') || (*(_ptr+1) != '{')) { // If not open block435parse_err(SYNERR, "missing '%%{' in operand definition\n");436return;437}438next_char(); next_char(); // Skip over "%{" symbol439do {440ident = get_ident(); // Grab next identifier441if (ident == NULL) {442parse_err(SYNERR, "keyword identifier expected at %c\n", _curchar);443continue;444}445if (!strcmp(ident, "predicate")) oper->_predicate = pred_parse();446else if (!strcmp(ident, "match")) {447// Find the end of the match rule list448rule = oper->_matrule;449if (rule) {450while (rule->_next) rule = rule->_next;451// Add the new match rule to the list452rule->_next = match_parse(oper->_localNames);453if (rule->_next) {454rule->_next->_result = oper->_ident;455}456}457else {458// This is first match rule encountered459oper->_matrule = match_parse(oper->_localNames);460if (oper->_matrule) {461oper->_matrule->_result = oper->_ident;462}463}464}465else if (!strcmp(ident, "encode")) oper->_interface = interface_parse();466else if (!strcmp(ident, "ins_encode")) {467parse_err(SYNERR, "Operands specify 'encode', not 'ins_encode'\n");468}469else if (!strcmp(ident, "opcode")) {470parse_err(SYNERR, "Operands do not specify an opcode\n");471}472else if (!strcmp(ident, "effect")) {473parse_err(SYNERR, "Operands do not specify an effect\n");474}475else if (!strcmp(ident, "expand")) {476parse_err(SYNERR, "Operands do not specify an expand\n");477}478else if (!strcmp(ident, "rewrite")) {479parse_err(SYNERR, "Operands do not specify a rewrite\n");480}481else if (!strcmp(ident, "constraint"))oper->_constraint= constraint_parse();482else if (!strcmp(ident, "construct")) oper->_construct = construct_parse();483else if (!strcmp(ident, "format")) oper->_format = format_parse();484else if (!strcmp(ident, "interface")) oper->_interface = interface_parse();485// Check identifier to see if it is the name of an attribute486else if (((attr = _globalNames[ident]->is_attribute()) != NULL) &&487(attr->_atype == OP_ATTR)) oper->_attribs = attr_parse(ident);488else {489parse_err(SYNERR, "expected one of - constraint, predicate, match, encode, format, construct, or the name of a defined operand attribute at %s\n", ident);490}491skipws();492} while(_curchar != '%');493next_char();494if (_curchar != '}') {495parse_err(SYNERR, "missing '%%}' in operand definition\n");496return;497}498// Add operand to tail of operand list499_AD.addForm(oper);500}501502//------------------------------opclass_parse----------------------------------503// Operand Classes are a block with a comma delimited list of operand names504void ADLParser::opclass_parse(void) {505char *ident;506OpClassForm *opc;507OperandForm *opForm;508509// First get the name of the operand class510skipws();511if( (ident = get_unique_ident(_globalNames,"opclass")) == NULL )512return;513opc = new OpClassForm(ident); // Create new operand class form514_globalNames.Insert(ident, opc); // Add name to the name table515516// Debugging Stuff517if (_AD._adl_debug > 1)518fprintf(stderr,"Parsing Operand Class Form %s\n", ident);519520// Get the list of operands521skipws();522if (_curchar != '(') {523parse_err(SYNERR, "missing '(' in operand definition\n");524return;525}526do {527next_char(); // Skip past open paren or comma528ident = get_ident(); // Grab next identifier529if (ident == NULL) {530parse_err(SYNERR, "keyword identifier expected at %c\n", _curchar);531continue;532}533// Check identifier to see if it is the name of an operand534const Form *form = _globalNames[ident];535opForm = form ? form->is_operand() : NULL;536if ( opForm ) {537opc->_oplst.addName(ident); // Add operand to opclass list538opForm->_classes.addName(opc->_ident);// Add opclass to operand list539}540else {541parse_err(SYNERR, "expected name of a defined operand at %s\n", ident);542}543skipws(); // skip trailing whitespace544} while (_curchar == ','); // Check for the comma545// Check for closing ')'546if (_curchar != ')') {547parse_err(SYNERR, "missing ')' or ',' in opclass definition\n");548return;549}550next_char(); // Consume the ')'551skipws();552// Check for closing ';'553if (_curchar != ';') {554parse_err(SYNERR, "missing ';' in opclass definition\n");555return;556}557next_char(); // Consume the ';'558// Add operand to tail of operand list559_AD.addForm(opc);560}561562//------------------------------ins_attr_parse---------------------------------563void ADLParser::ins_attr_parse(void) {564char *ident;565char *aexpr;566AttributeForm *attrib;567568// get name for the instruction attribute569skipws(); // Skip leading whitespace570if( (ident = get_unique_ident(_globalNames,"inst_attrib")) == NULL )571return;572// Debugging Stuff573if (_AD._adl_debug > 1) fprintf(stderr,"Parsing Ins_Attribute Form %s\n", ident);574575// Get default value of the instruction attribute576skipws(); // Skip whitespace577if ((aexpr = get_paren_expr("attribute default expression string")) == NULL) {578parse_err(SYNERR, "missing '(' in ins_attrib definition\n");579return;580}581// Debug Stuff582if (_AD._adl_debug > 1) fprintf(stderr,"Attribute Expression: %s\n", aexpr);583584// Check for terminator585if (_curchar != ';') {586parse_err(SYNERR, "missing ';' in ins_attrib definition\n");587return;588}589next_char(); // Advance past the ';'590591// Construct the attribute, record global name, and store in ArchDesc592attrib = new AttributeForm(ident, INS_ATTR, aexpr);593_globalNames.Insert(ident, attrib); // Add name to the name table594_AD.addForm(attrib);595}596597//------------------------------op_attr_parse----------------------------------598void ADLParser::op_attr_parse(void) {599char *ident;600char *aexpr;601AttributeForm *attrib;602603// get name for the operand attribute604skipws(); // Skip leading whitespace605if( (ident = get_unique_ident(_globalNames,"op_attrib")) == NULL )606return;607// Debugging Stuff608if (_AD._adl_debug > 1) fprintf(stderr,"Parsing Op_Attribute Form %s\n", ident);609610// Get default value of the instruction attribute611skipws(); // Skip whitespace612if ((aexpr = get_paren_expr("attribute default expression string")) == NULL) {613parse_err(SYNERR, "missing '(' in op_attrib definition\n");614return;615}616// Debug Stuff617if (_AD._adl_debug > 1) fprintf(stderr,"Attribute Expression: %s\n", aexpr);618619// Check for terminator620if (_curchar != ';') {621parse_err(SYNERR, "missing ';' in op_attrib definition\n");622return;623}624next_char(); // Advance past the ';'625626// Construct the attribute, record global name, and store in ArchDesc627attrib = new AttributeForm(ident, OP_ATTR, aexpr);628_globalNames.Insert(ident, attrib);629_AD.addForm(attrib);630}631632//------------------------------definitions_parse-----------------------------------633void ADLParser::definitions_parse(void) {634skipws(); // Skip leading whitespace635if (_curchar == '%' && *(_ptr+1) == '{') {636next_char(); next_char(); // Skip "%{"637skipws();638while (_curchar != '%' && *(_ptr+1) != '}') {639// Process each definition until finding closing string "%}"640char *token = get_ident();641if (token == NULL) {642parse_err(SYNERR, "missing identifier inside definitions block.\n");643return;644}645if (strcmp(token,"int_def")==0) { int_def_parse(); }646// if (strcmp(token,"str_def")==0) { str_def_parse(); }647skipws();648}649}650else {651parse_err(SYNERR, "Missing %%{ ... %%} block after definitions keyword.\n");652return;653}654}655656//------------------------------int_def_parse----------------------------------657// Parse Example:658// int_def MEMORY_REF_COST ( 200, DEFAULT_COST * 2);659// <keyword> <name> ( <int_value>, <description> );660//661void ADLParser::int_def_parse(void) {662char *name = NULL; // Name of definition663char *value = NULL; // its value,664int int_value = -1; // positive values only665char *description = NULL; // textual description666667// Get definition name668skipws(); // Skip whitespace669name = get_ident();670if (name == NULL) {671parse_err(SYNERR, "missing definition name after int_def\n");672return;673}674675// Check for value of int_def dname( integer_value [, string_expression ] )676skipws();677if (_curchar == '(') {678679// Parse the integer value.680next_char();681value = get_ident();682if (value == NULL) {683parse_err(SYNERR, "missing value in int_def\n");684return;685}686if( !is_int_token(value, int_value) ) {687parse_err(SYNERR, "value in int_def is not recognized as integer\n");688return;689}690skipws();691692// Check for description693if (_curchar == ',') {694next_char(); // skip ','695696description = get_expr("int_def description", ")");697if (description == NULL) {698parse_err(SYNERR, "invalid or missing description in int_def\n");699return;700}701trim(description);702}703704if (_curchar != ')') {705parse_err(SYNERR, "missing ')' in register definition statement\n");706return;707}708next_char();709}710711// Check for closing ';'712skipws();713if (_curchar != ';') {714parse_err(SYNERR, "missing ';' after int_def\n");715return;716}717next_char(); // move past ';'718719// Debug Stuff720if (_AD._adl_debug > 1) {721fprintf(stderr,"int_def: %s ( %s, %s )\n", name,722(value), (description ? description : ""));723}724725// Record new definition.726Expr *expr = new Expr(name, description, int_value, int_value);727const Expr *old_expr = _AD.globalDefs().define(name, expr);728if (old_expr != NULL) {729parse_err(SYNERR, "Duplicate definition\n");730return;731}732733return;734}735736737//------------------------------source_parse-----------------------------------738void ADLParser::source_parse(void) {739SourceForm *source; // Encode class for instruction/operand740char *rule = NULL; // String representation of encode rule741742skipws(); // Skip leading whitespace743if ( (rule = find_cpp_block("source block")) == NULL ) {744parse_err(SYNERR, "incorrect or missing block for 'source'.\n");745return;746}747// Debug Stuff748if (_AD._adl_debug > 1) fprintf(stderr,"Source Form: %s\n", rule);749750source = new SourceForm(rule); // Build new Source object751_AD.addForm(source);752// skipws();753}754755//------------------------------source_hpp_parse-------------------------------756// Parse a source_hpp %{ ... %} block.757// The code gets stuck into the ad_<arch>.hpp file.758// If the source_hpp block appears before the register block in the AD759// file, it goes up at the very top of the ad_<arch>.hpp file, so that760// it can be used by register encodings, etc. Otherwise, it goes towards761// the bottom, where it's useful as a global definition to *.cpp files.762void ADLParser::source_hpp_parse(void) {763char *rule = NULL; // String representation of encode rule764765skipws(); // Skip leading whitespace766if ( (rule = find_cpp_block("source_hpp block")) == NULL ) {767parse_err(SYNERR, "incorrect or missing block for 'source_hpp'.\n");768return;769}770// Debug Stuff771if (_AD._adl_debug > 1) fprintf(stderr,"Header Form: %s\n", rule);772773if (_AD.get_registers() == NULL) {774// Very early in the file, before reg_defs, we collect pre-headers.775PreHeaderForm* pre_header = new PreHeaderForm(rule);776_AD.addForm(pre_header);777} else {778// Normally, we collect header info, placed at the bottom of the hpp file.779HeaderForm* header = new HeaderForm(rule);780_AD.addForm(header);781}782}783784//------------------------------reg_parse--------------------------------------785void ADLParser::reg_parse(void) {786RegisterForm *regBlock = _AD.get_registers(); // Information about registers encoding787if (regBlock == NULL) {788// Create the RegisterForm for the architecture description.789regBlock = new RegisterForm(); // Build new Source object790_AD.addForm(regBlock);791}792793skipws(); // Skip leading whitespace794if (_curchar == '%' && *(_ptr+1) == '{') {795next_char(); next_char(); // Skip "%{"796skipws();797while (_curchar != '%' && *(_ptr+1) != '}') {798char *token = get_ident();799if (token == NULL) {800parse_err(SYNERR, "missing identifier inside register block.\n");801return;802}803if (strcmp(token,"reg_def")==0) { reg_def_parse(); }804else if (strcmp(token,"reg_class")==0) { reg_class_parse(); }805else if (strcmp(token, "reg_class_dynamic") == 0) { reg_class_dynamic_parse(); }806else if (strcmp(token,"alloc_class")==0) { alloc_class_parse(); }807else if (strcmp(token,"#define")==0) { preproc_define(); }808else { parse_err(SYNERR, "bad token %s inside register block.\n", token); break; }809skipws();810}811}812else {813parse_err(SYNERR, "Missing %c{ ... %c} block after register keyword.\n",'%','%');814return;815}816}817818//------------------------------encode_parse-----------------------------------819void ADLParser::encode_parse(void) {820EncodeForm *encBlock; // Information about instruction/operand encoding821822_AD.getForm(&encBlock);823if ( encBlock == NULL) {824// Create the EncodeForm for the architecture description.825encBlock = new EncodeForm(); // Build new Source object826_AD.addForm(encBlock);827}828829skipws(); // Skip leading whitespace830if (_curchar == '%' && *(_ptr+1) == '{') {831next_char(); next_char(); // Skip "%{"832skipws();833while (_curchar != '%' && *(_ptr+1) != '}') {834char *token = get_ident();835if (token == NULL) {836parse_err(SYNERR, "missing identifier inside encoding block.\n");837return;838}839if (strcmp(token,"enc_class")==0) { enc_class_parse(); }840skipws();841}842}843else {844parse_err(SYNERR, "Missing %c{ ... %c} block after encode keyword.\n",'%','%');845return;846}847}848849//------------------------------enc_class_parse--------------------------------850void ADLParser::enc_class_parse(void) {851char *ec_name; // Name of encoding class being defined852853// Get encoding class name854skipws(); // Skip whitespace855ec_name = get_ident();856if (ec_name == NULL) {857parse_err(SYNERR, "missing encoding class name after encode.\n");858return;859}860861EncClass *encoding = _AD._encode->add_EncClass(ec_name);862encoding->_linenum = linenum();863864skipws(); // Skip leading whitespace865// Check for optional parameter list866if (_curchar == '(') {867do {868char *pType = NULL; // parameter type869char *pName = NULL; // parameter name870871next_char(); // skip open paren & comma characters872skipws();873if (_curchar == ')') break;874875// Get parameter type876pType = get_ident();877if (pType == NULL) {878parse_err(SYNERR, "parameter type expected at %c\n", _curchar);879return;880}881882skipws();883// Get parameter name884pName = get_ident();885if (pName == NULL) {886parse_err(SYNERR, "parameter name expected at %c\n", _curchar);887return;888}889890// Record parameter type and name891encoding->add_parameter( pType, pName );892893skipws();894} while(_curchar == ',');895896if (_curchar != ')') parse_err(SYNERR, "missing ')'\n");897else {898next_char(); // Skip ')'899}900} // Done with parameter list901902skipws();903// Check for block starting delimiters904if ((_curchar != '%') || (*(_ptr+1) != '{')) { // If not open block905parse_err(SYNERR, "missing '%c{' in enc_class definition\n", '%');906return;907}908next_char(); // Skip '%'909next_char(); // Skip '{'910911enc_class_parse_block(encoding, ec_name);912}913914915void ADLParser::enc_class_parse_block(EncClass* encoding, char* ec_name) {916skipws_no_preproc(); // Skip leading whitespace917// Prepend location descriptor, for debugging; cf. ADLParser::find_cpp_block918if (_AD._adlocation_debug) {919encoding->add_code(get_line_string());920}921922// Collect the parts of the encode description923// (1) strings that are passed through to output924// (2) replacement/substitution variable, preceeded by a '$'925while ( (_curchar != '%') && (*(_ptr+1) != '}') ) {926927// (1)928// Check if there is a string to pass through to output929char *start = _ptr; // Record start of the next string930while ((_curchar != '$') && ((_curchar != '%') || (*(_ptr+1) != '}')) ) {931// If at the start of a comment, skip past it932if( (_curchar == '/') && ((*(_ptr+1) == '/') || (*(_ptr+1) == '*')) ) {933skipws_no_preproc();934} else {935// ELSE advance to the next character, or start of the next line936next_char_or_line();937}938}939// If a string was found, terminate it and record in EncClass940if ( start != _ptr ) {941*_ptr = '\0'; // Terminate the string942encoding->add_code(start);943}944945// (2)946// If we are at a replacement variable,947// copy it and record in EncClass948if (_curchar == '$') {949// Found replacement Variable950char* rep_var = get_rep_var_ident_dup();951// Add flag to _strings list indicating we should check _rep_vars952encoding->add_rep_var(rep_var);953}954} // end while part of format description955next_char(); // Skip '%'956next_char(); // Skip '}'957958skipws();959960if (_AD._adlocation_debug) {961encoding->add_code(end_line_marker());962}963964// Debug Stuff965if (_AD._adl_debug > 1) fprintf(stderr,"EncodingClass Form: %s\n", ec_name);966}967968//------------------------------frame_parse-----------------------------------969void ADLParser::frame_parse(void) {970FrameForm *frame; // Information about stack-frame layout971char *desc = NULL; // String representation of frame972973skipws(); // Skip leading whitespace974975frame = new FrameForm(); // Build new Frame object976// Check for open block sequence977skipws(); // Skip leading whitespace978if (_curchar == '%' && *(_ptr+1) == '{') {979next_char(); next_char(); // Skip "%{"980skipws();981while (_curchar != '%' && *(_ptr+1) != '}') {982char *token = get_ident();983if (token == NULL) {984parse_err(SYNERR, "missing identifier inside frame block.\n");985return;986}987if (strcmp(token,"sync_stack_slots")==0) {988sync_stack_slots_parse(frame);989}990if (strcmp(token,"frame_pointer")==0) {991frame_pointer_parse(frame, false);992}993if (strcmp(token,"interpreter_frame_pointer")==0) {994interpreter_frame_pointer_parse(frame, false);995}996if (strcmp(token,"inline_cache_reg")==0) {997inline_cache_parse(frame, false);998}999if (strcmp(token,"compiler_method_oop_reg")==0) {1000parse_err(WARN, "Using obsolete Token, compiler_method_oop_reg");1001skipws();1002}1003if (strcmp(token,"interpreter_method_oop_reg")==0) {1004parse_err(WARN, "Using obsolete Token, interpreter_method_oop_reg");1005skipws();1006}1007if (strcmp(token,"interpreter_method_reg")==0) {1008parse_err(WARN, "Using obsolete Token, interpreter_method_reg");1009skipws();1010}1011if (strcmp(token,"cisc_spilling_operand_name")==0) {1012cisc_spilling_operand_name_parse(frame, false);1013}1014if (strcmp(token,"stack_alignment")==0) {1015stack_alignment_parse(frame);1016}1017if (strcmp(token,"return_addr")==0) {1018return_addr_parse(frame, false);1019}1020if (strcmp(token,"in_preserve_stack_slots")==0) {1021parse_err(WARN, "Using obsolete token, in_preserve_stack_slots");1022skipws();1023}1024if (strcmp(token,"out_preserve_stack_slots")==0) {1025parse_err(WARN, "Using obsolete token, out_preserve_stack_slots");1026skipws();1027}1028if (strcmp(token,"varargs_C_out_slots_killed")==0) {1029frame->_varargs_C_out_slots_killed = parse_one_arg("varargs C out slots killed");1030}1031if (strcmp(token,"calling_convention")==0) {1032parse_err(WARN, "Using obsolete token, calling_convention");1033skipws();1034}1035if (strcmp(token,"return_value")==0) {1036frame->_return_value = return_value_parse();1037}1038if (strcmp(token,"c_frame_pointer")==0) {1039frame_pointer_parse(frame, true);1040}1041if (strcmp(token,"c_return_addr")==0) {1042return_addr_parse(frame, true);1043}1044if (strcmp(token,"c_calling_convention")==0) {1045parse_err(WARN, "Using obsolete token, c_calling_convention");1046skipws();1047}1048if (strcmp(token,"c_return_value")==0) {1049frame->_c_return_value = return_value_parse();1050}10511052skipws();1053}1054}1055else {1056parse_err(SYNERR, "Missing %c{ ... %c} block after encode keyword.\n",'%','%');1057return;1058}1059// All Java versions are required, native versions are optional1060if(frame->_frame_pointer == NULL) {1061parse_err(SYNERR, "missing frame pointer definition in frame section.\n");1062return;1063}1064// !!!!! !!!!!1065// if(frame->_interpreter_frame_ptr_reg == NULL) {1066// parse_err(SYNERR, "missing interpreter frame pointer definition in frame section.\n");1067// return;1068// }1069if(frame->_alignment == NULL) {1070parse_err(SYNERR, "missing alignment definition in frame section.\n");1071return;1072}1073if(frame->_return_addr == NULL) {1074parse_err(SYNERR, "missing return address location in frame section.\n");1075return;1076}1077if(frame->_varargs_C_out_slots_killed == NULL) {1078parse_err(SYNERR, "missing varargs C out slots killed definition in frame section.\n");1079return;1080}1081if(frame->_return_value == NULL) {1082parse_err(SYNERR, "missing return value definition in frame section.\n");1083return;1084}1085// Fill natives in identically with the Java versions if not present.1086if(frame->_c_frame_pointer == NULL) {1087frame->_c_frame_pointer = frame->_frame_pointer;1088}1089if(frame->_c_return_addr == NULL) {1090frame->_c_return_addr = frame->_return_addr;1091frame->_c_return_addr_loc = frame->_return_addr_loc;1092}1093if(frame->_c_return_value == NULL) {1094frame->_c_return_value = frame->_return_value;1095}10961097// Debug Stuff1098if (_AD._adl_debug > 1) fprintf(stderr,"Frame Form: %s\n", desc);10991100// Create the EncodeForm for the architecture description.1101_AD.addForm(frame);1102// skipws();1103}11041105//------------------------------sync_stack_slots_parse-------------------------1106void ADLParser::sync_stack_slots_parse(FrameForm *frame) {1107// Assign value into frame form1108frame->_sync_stack_slots = parse_one_arg("sync stack slots entry");1109}11101111//------------------------------frame_pointer_parse----------------------------1112void ADLParser::frame_pointer_parse(FrameForm *frame, bool native) {1113char *frame_pointer = parse_one_arg("frame pointer entry");1114// Assign value into frame form1115if (native) { frame->_c_frame_pointer = frame_pointer; }1116else { frame->_frame_pointer = frame_pointer; }1117}11181119//------------------------------interpreter_frame_pointer_parse----------------------------1120void ADLParser::interpreter_frame_pointer_parse(FrameForm *frame, bool native) {1121frame->_interpreter_frame_pointer_reg = parse_one_arg("interpreter frame pointer entry");1122}11231124//------------------------------inline_cache_parse-----------------------------1125void ADLParser::inline_cache_parse(FrameForm *frame, bool native) {1126frame->_inline_cache_reg = parse_one_arg("inline cache reg entry");1127}11281129//------------------------------cisc_spilling_operand_parse---------------------1130void ADLParser::cisc_spilling_operand_name_parse(FrameForm *frame, bool native) {1131frame->_cisc_spilling_operand_name = parse_one_arg("cisc spilling operand name");1132}11331134//------------------------------stack_alignment_parse--------------------------1135void ADLParser::stack_alignment_parse(FrameForm *frame) {1136char *alignment = parse_one_arg("stack alignment entry");1137// Assign value into frame1138frame->_alignment = alignment;1139}11401141//------------------------------parse_one_arg-------------------------------1142char *ADLParser::parse_one_arg(const char *description) {1143char *token = NULL;1144if(_curchar == '(') {1145next_char();1146skipws();1147token = get_expr(description, ")");1148if (token == NULL) {1149parse_err(SYNERR, "missing value inside %s.\n", description);1150return NULL;1151}1152next_char(); // skip the close paren1153if(_curchar != ';') { // check for semi-colon1154parse_err(SYNERR, "missing %c in.\n", ';', description);1155return NULL;1156}1157next_char(); // skip the semi-colon1158}1159else {1160parse_err(SYNERR, "Missing %c in.\n", '(', description);1161return NULL;1162}11631164trim(token);1165return token;1166}11671168//------------------------------return_addr_parse------------------------------1169void ADLParser::return_addr_parse(FrameForm *frame, bool native) {1170bool in_register = true;1171if(_curchar == '(') {1172next_char();1173skipws();1174char *token = get_ident();1175if (token == NULL) {1176parse_err(SYNERR, "missing value inside return address entry.\n");1177return;1178}1179// check for valid values for stack/register1180if (strcmp(token, "REG") == 0) {1181in_register = true;1182}1183else if (strcmp(token, "STACK") == 0) {1184in_register = false;1185}1186else {1187parse_err(SYNERR, "invalid value inside return_address entry.\n");1188return;1189}1190if (native) { frame->_c_return_addr_loc = in_register; }1191else { frame->_return_addr_loc = in_register; }11921193// Parse expression that specifies register or stack position1194skipws();1195char *token2 = get_expr("return address entry", ")");1196if (token2 == NULL) {1197parse_err(SYNERR, "missing value inside return address entry.\n");1198return;1199}1200next_char(); // skip the close paren1201if (native) { frame->_c_return_addr = token2; }1202else { frame->_return_addr = token2; }12031204if(_curchar != ';') { // check for semi-colon1205parse_err(SYNERR, "missing %c in return address entry.\n", ';');1206return;1207}1208next_char(); // skip the semi-colon1209}1210else {1211parse_err(SYNERR, "Missing %c in return_address entry.\n", '(');1212}1213}12141215//------------------------------return_value_parse-----------------------------1216char *ADLParser::return_value_parse() {1217char *desc = NULL; // String representation of return_value12181219skipws(); // Skip leading whitespace1220if ( (desc = find_cpp_block("return value block")) == NULL ) {1221parse_err(SYNERR, "incorrect or missing block for 'return_value'.\n");1222}1223return desc;1224}12251226//------------------------------ins_pipe_parse---------------------------------1227void ADLParser::ins_pipe_parse(InstructForm &instr) {1228char * ident;12291230skipws();1231if ( _curchar != '(' ) { // Check for delimiter1232parse_err(SYNERR, "missing \"(\" in ins_pipe definition\n");1233return;1234}12351236next_char();1237ident = get_ident(); // Grab next identifier12381239if (ident == NULL) {1240parse_err(SYNERR, "keyword identifier expected at %c\n", _curchar);1241return;1242}12431244skipws();1245if ( _curchar != ')' ) { // Check for delimiter1246parse_err(SYNERR, "missing \")\" in ins_pipe definition\n");1247return;1248}12491250next_char(); // skip the close paren1251if(_curchar != ';') { // check for semi-colon1252parse_err(SYNERR, "missing %c in return value entry.\n", ';');1253return;1254}1255next_char(); // skip the semi-colon12561257// Check ident for validity1258if (_AD._pipeline && !_AD._pipeline->_classlist.search(ident)) {1259parse_err(SYNERR, "\"%s\" is not a valid pipeline class\n", ident);1260return;1261}12621263// Add this instruction to the list in the pipeline class1264_AD._pipeline->_classdict[ident]->is_pipeclass()->_instructs.addName(instr._ident);12651266// Set the name of the pipeline class in the instruction1267instr._ins_pipe = ident;1268return;1269}12701271//------------------------------pipe_parse-------------------------------------1272void ADLParser::pipe_parse(void) {1273PipelineForm *pipeline; // Encode class for instruction/operand1274char * ident;12751276pipeline = new PipelineForm(); // Build new Source object1277_AD.addForm(pipeline);12781279skipws(); // Skip leading whitespace1280// Check for block delimiter1281if ( (_curchar != '%')1282|| ( next_char(), (_curchar != '{')) ) {1283parse_err(SYNERR, "missing '%%{' in pipeline definition\n");1284return;1285}1286next_char(); // Maintain the invariant1287do {1288ident = get_ident(); // Grab next identifier1289if (ident == NULL) {1290parse_err(SYNERR, "keyword identifier expected at %c\n", _curchar);1291continue;1292}1293if (!strcmp(ident, "resources" )) resource_parse(*pipeline);1294else if (!strcmp(ident, "pipe_desc" )) pipe_desc_parse(*pipeline);1295else if (!strcmp(ident, "pipe_class")) pipe_class_parse(*pipeline);1296else if (!strcmp(ident, "define")) {1297skipws();1298if ( (_curchar != '%')1299|| ( next_char(), (_curchar != '{')) ) {1300parse_err(SYNERR, "expected '%%{'\n");1301return;1302}1303next_char(); skipws();13041305char *node_class = get_ident();1306if (node_class == NULL) {1307parse_err(SYNERR, "expected identifier, found \"%c\"\n", _curchar);1308return;1309}13101311skipws();1312if (_curchar != ',' && _curchar != '=') {1313parse_err(SYNERR, "expected `=`, found '%c'\n", _curchar);1314break;1315}1316next_char(); skipws();13171318char *pipe_class = get_ident();1319if (pipe_class == NULL) {1320parse_err(SYNERR, "expected identifier, found \"%c\"\n", _curchar);1321return;1322}1323if (_curchar != ';' ) {1324parse_err(SYNERR, "expected `;`, found '%c'\n", _curchar);1325break;1326}1327next_char(); // Skip over semi-colon13281329skipws();1330if ( (_curchar != '%')1331|| ( next_char(), (_curchar != '}')) ) {1332parse_err(SYNERR, "expected '%%}', found \"%c\"\n", _curchar);1333}1334next_char();13351336// Check ident for validity1337if (_AD._pipeline && !_AD._pipeline->_classlist.search(pipe_class)) {1338parse_err(SYNERR, "\"%s\" is not a valid pipeline class\n", pipe_class);1339return;1340}13411342// Add this machine node to the list in the pipeline class1343_AD._pipeline->_classdict[pipe_class]->is_pipeclass()->_instructs.addName(node_class);13441345MachNodeForm *machnode = new MachNodeForm(node_class); // Create new machnode form1346machnode->_machnode_pipe = pipe_class;13471348_AD.addForm(machnode);1349}1350else if (!strcmp(ident, "attributes")) {1351bool vsi_seen = false;13521353skipws();1354if ( (_curchar != '%')1355|| ( next_char(), (_curchar != '{')) ) {1356parse_err(SYNERR, "expected '%%{'\n");1357return;1358}1359next_char(); skipws();13601361while (_curchar != '%') {1362ident = get_ident();1363if (ident == NULL)1364break;13651366if (!strcmp(ident, "variable_size_instructions")) {1367skipws();1368if (_curchar == ';') {1369next_char(); skipws();1370}13711372pipeline->_variableSizeInstrs = true;1373vsi_seen = true;1374continue;1375}13761377if (!strcmp(ident, "fixed_size_instructions")) {1378skipws();1379if (_curchar == ';') {1380next_char(); skipws();1381}13821383pipeline->_variableSizeInstrs = false;1384vsi_seen = true;1385continue;1386}13871388if (!strcmp(ident, "branch_has_delay_slot")) {1389skipws();1390if (_curchar == ';') {1391next_char(); skipws();1392}13931394pipeline->_branchHasDelaySlot = true;1395continue;1396}13971398if (!strcmp(ident, "max_instructions_per_bundle")) {1399skipws();1400if (_curchar != '=') {1401parse_err(SYNERR, "expected `=`\n");1402break;1403}14041405next_char(); skipws();1406pipeline->_maxInstrsPerBundle = get_int();1407skipws();14081409if (_curchar == ';') {1410next_char(); skipws();1411}14121413continue;1414}14151416if (!strcmp(ident, "max_bundles_per_cycle")) {1417skipws();1418if (_curchar != '=') {1419parse_err(SYNERR, "expected `=`\n");1420break;1421}14221423next_char(); skipws();1424pipeline->_maxBundlesPerCycle = get_int();1425skipws();14261427if (_curchar == ';') {1428next_char(); skipws();1429}14301431continue;1432}14331434if (!strcmp(ident, "instruction_unit_size")) {1435skipws();1436if (_curchar != '=') {1437parse_err(SYNERR, "expected `=`, found '%c'\n", _curchar);1438break;1439}14401441next_char(); skipws();1442pipeline->_instrUnitSize = get_int();1443skipws();14441445if (_curchar == ';') {1446next_char(); skipws();1447}14481449continue;1450}14511452if (!strcmp(ident, "bundle_unit_size")) {1453skipws();1454if (_curchar != '=') {1455parse_err(SYNERR, "expected `=`, found '%c'\n", _curchar);1456break;1457}14581459next_char(); skipws();1460pipeline->_bundleUnitSize = get_int();1461skipws();14621463if (_curchar == ';') {1464next_char(); skipws();1465}14661467continue;1468}14691470if (!strcmp(ident, "instruction_fetch_unit_size")) {1471skipws();1472if (_curchar != '=') {1473parse_err(SYNERR, "expected `=`, found '%c'\n", _curchar);1474break;1475}14761477next_char(); skipws();1478pipeline->_instrFetchUnitSize = get_int();1479skipws();14801481if (_curchar == ';') {1482next_char(); skipws();1483}14841485continue;1486}14871488if (!strcmp(ident, "instruction_fetch_units")) {1489skipws();1490if (_curchar != '=') {1491parse_err(SYNERR, "expected `=`, found '%c'\n", _curchar);1492break;1493}14941495next_char(); skipws();1496pipeline->_instrFetchUnits = get_int();1497skipws();14981499if (_curchar == ';') {1500next_char(); skipws();1501}15021503continue;1504}15051506if (!strcmp(ident, "nops")) {1507skipws();1508if (_curchar != '(') {1509parse_err(SYNERR, "expected `(`, found '%c'\n", _curchar);1510break;1511}15121513next_char(); skipws();15141515while (_curchar != ')') {1516ident = get_ident();1517if (ident == NULL) {1518parse_err(SYNERR, "expected identifier for nop instruction, found '%c'\n", _curchar);1519break;1520}15211522pipeline->_noplist.addName(ident);1523pipeline->_nopcnt++;1524skipws();15251526if (_curchar == ',') {1527next_char(); skipws();1528}1529}15301531next_char(); skipws();15321533if (_curchar == ';') {1534next_char(); skipws();1535}15361537continue;1538}15391540parse_err(SYNERR, "unknown specifier \"%s\"\n", ident);1541}15421543if ( (_curchar != '%')1544|| ( next_char(), (_curchar != '}')) ) {1545parse_err(SYNERR, "expected '%%}', found \"%c\"\n", _curchar);1546}1547next_char(); skipws();15481549if (pipeline->_maxInstrsPerBundle == 0)1550parse_err(SYNERR, "\"max_instructions_per_bundle\" unspecified\n");1551if (pipeline->_instrUnitSize == 0 && pipeline->_bundleUnitSize == 0)1552parse_err(SYNERR, "\"instruction_unit_size\" and \"bundle_unit_size\" unspecified\n");1553if (pipeline->_instrFetchUnitSize == 0)1554parse_err(SYNERR, "\"instruction_fetch_unit_size\" unspecified\n");1555if (pipeline->_instrFetchUnits == 0)1556parse_err(SYNERR, "\"instruction_fetch_units\" unspecified\n");1557if (!vsi_seen)1558parse_err(SYNERR, "\"variable_size_instruction\" or \"fixed_size_instruction\" unspecified\n");1559}1560else { // Done with staticly defined parts of instruction definition1561parse_err(SYNERR, "expected one of \"resources\", \"pipe_desc\", \"pipe_class\", found \"%s\"\n", ident);1562return;1563}1564skipws();1565if (_curchar == ';')1566skipws();1567} while(_curchar != '%');15681569next_char();1570if (_curchar != '}') {1571parse_err(SYNERR, "missing \"%%}\" in pipeline definition\n");1572return;1573}15741575next_char();1576}15771578//------------------------------resource_parse----------------------------1579void ADLParser::resource_parse(PipelineForm &pipeline) {1580ResourceForm *resource;1581char * ident;1582char * expr;1583unsigned mask;1584pipeline._rescount = 0;15851586skipws(); // Skip leading whitespace15871588if (_curchar != '(') {1589parse_err(SYNERR, "missing \"(\" in resource definition\n");1590return;1591}15921593do {1594next_char(); // Skip "(" or ","1595ident = get_ident(); // Grab next identifier15961597if (_AD._adl_debug > 1) {1598if (ident != NULL) {1599fprintf(stderr, "resource_parse: identifier: %s\n", ident);1600}1601}16021603if (ident == NULL) {1604parse_err(SYNERR, "keyword identifier expected at \"%c\"\n", _curchar);1605return;1606}1607skipws();16081609if (_curchar != '=') {1610mask = (1 << pipeline._rescount++);1611}1612else {1613next_char(); skipws();1614expr = get_ident(); // Grab next identifier1615if (expr == NULL) {1616parse_err(SYNERR, "keyword identifier expected at \"%c\"\n", _curchar);1617return;1618}1619resource = (ResourceForm *) pipeline._resdict[expr];1620if (resource == NULL) {1621parse_err(SYNERR, "resource \"%s\" is not defined\n", expr);1622return;1623}1624mask = resource->mask();16251626skipws();1627while (_curchar == '|') {1628next_char(); skipws();16291630expr = get_ident(); // Grab next identifier1631if (expr == NULL) {1632parse_err(SYNERR, "keyword identifier expected at \"%c\"\n", _curchar);1633return;1634}16351636resource = (ResourceForm *) pipeline._resdict[expr]; // Look up the value1637if (resource == NULL) {1638parse_err(SYNERR, "resource \"%s\" is not defined\n", expr);1639return;1640}16411642mask |= resource->mask();1643skipws();1644}1645}16461647resource = new ResourceForm(mask);16481649pipeline._resdict.Insert(ident, resource);1650pipeline._reslist.addName(ident);1651} while (_curchar == ',');16521653if (_curchar != ')') {1654parse_err(SYNERR, "\")\" expected at \"%c\"\n", _curchar);1655return;1656}16571658next_char(); // Skip ")"1659if (_curchar == ';')1660next_char(); // Skip ";"1661}16621663//------------------------------resource_parse----------------------------1664void ADLParser::pipe_desc_parse(PipelineForm &pipeline) {1665char * ident;16661667skipws(); // Skip leading whitespace16681669if (_curchar != '(') {1670parse_err(SYNERR, "missing \"(\" in pipe_desc definition\n");1671return;1672}16731674do {1675next_char(); // Skip "(" or ","1676ident = get_ident(); // Grab next identifier1677if (ident == NULL) {1678parse_err(SYNERR, "keyword identifier expected at \"%c\"\n", _curchar);1679return;1680}16811682// Add the name to the list1683pipeline._stages.addName(ident);1684pipeline._stagecnt++;16851686skipws();1687} while (_curchar == ',');16881689if (_curchar != ')') {1690parse_err(SYNERR, "\")\" expected at \"%c\"\n", _curchar);1691return;1692}16931694next_char(); // Skip ")"1695if (_curchar == ';')1696next_char(); // Skip ";"1697}16981699//------------------------------pipe_class_parse--------------------------1700void ADLParser::pipe_class_parse(PipelineForm &pipeline) {1701PipeClassForm *pipe_class;1702char * ident;1703char * stage;1704char * read_or_write;1705int is_write;1706int is_read;1707OperandForm *oper;17081709skipws(); // Skip leading whitespace17101711ident = get_ident(); // Grab next identifier17121713if (ident == NULL) {1714parse_err(SYNERR, "keyword identifier expected at \"%c\"\n", _curchar);1715return;1716}17171718// Create a record for the pipe_class1719pipe_class = new PipeClassForm(ident, ++pipeline._classcnt);1720pipeline._classdict.Insert(ident, pipe_class);1721pipeline._classlist.addName(ident);17221723// Then get the operands1724skipws();1725if (_curchar != '(') {1726parse_err(SYNERR, "missing \"(\" in pipe_class definition\n");1727}1728// Parse the operand list1729else get_oplist(pipe_class->_parameters, pipe_class->_localNames);1730skipws(); // Skip leading whitespace1731// Check for block delimiter1732if ( (_curchar != '%')1733|| ( next_char(), (_curchar != '{')) ) {1734parse_err(SYNERR, "missing \"%%{\" in pipe_class definition\n");1735return;1736}1737next_char();17381739do {1740ident = get_ident(); // Grab next identifier1741if (ident == NULL) {1742parse_err(SYNERR, "keyword identifier expected at \"%c\"\n", _curchar);1743continue;1744}1745skipws();17461747if (!strcmp(ident, "fixed_latency")) {1748skipws();1749if (_curchar != '(') {1750parse_err(SYNERR, "missing \"(\" in latency definition\n");1751return;1752}1753next_char(); skipws();1754if( !isdigit(_curchar) ) {1755parse_err(SYNERR, "number expected for \"%c\" in latency definition\n", _curchar);1756return;1757}1758int fixed_latency = get_int();1759skipws();1760if (_curchar != ')') {1761parse_err(SYNERR, "missing \")\" in latency definition\n");1762return;1763}1764next_char(); skipws();1765if (_curchar != ';') {1766parse_err(SYNERR, "missing \";\" in latency definition\n");1767return;1768}17691770pipe_class->setFixedLatency(fixed_latency);1771next_char(); skipws();1772continue;1773}17741775if (!strcmp(ident, "zero_instructions") ||1776!strcmp(ident, "no_instructions")) {1777skipws();1778if (_curchar != ';') {1779parse_err(SYNERR, "missing \";\" in latency definition\n");1780return;1781}17821783pipe_class->setInstructionCount(0);1784next_char(); skipws();1785continue;1786}17871788if (!strcmp(ident, "one_instruction_with_delay_slot") ||1789!strcmp(ident, "single_instruction_with_delay_slot")) {1790skipws();1791if (_curchar != ';') {1792parse_err(SYNERR, "missing \";\" in latency definition\n");1793return;1794}17951796pipe_class->setInstructionCount(1);1797pipe_class->setBranchDelay(true);1798next_char(); skipws();1799continue;1800}18011802if (!strcmp(ident, "one_instruction") ||1803!strcmp(ident, "single_instruction")) {1804skipws();1805if (_curchar != ';') {1806parse_err(SYNERR, "missing \";\" in latency definition\n");1807return;1808}18091810pipe_class->setInstructionCount(1);1811next_char(); skipws();1812continue;1813}18141815if (!strcmp(ident, "instructions_in_first_bundle") ||1816!strcmp(ident, "instruction_count")) {1817skipws();18181819int number_of_instructions = 1;18201821if (_curchar != '(') {1822parse_err(SYNERR, "\"(\" expected at \"%c\"\n", _curchar);1823continue;1824}18251826next_char(); skipws();1827number_of_instructions = get_int();18281829skipws();1830if (_curchar != ')') {1831parse_err(SYNERR, "\")\" expected at \"%c\"\n", _curchar);1832continue;1833}18341835next_char(); skipws();1836if (_curchar != ';') {1837parse_err(SYNERR, "missing \";\" in latency definition\n");1838return;1839}18401841pipe_class->setInstructionCount(number_of_instructions);1842next_char(); skipws();1843continue;1844}18451846if (!strcmp(ident, "multiple_bundles")) {1847skipws();1848if (_curchar != ';') {1849parse_err(SYNERR, "missing \";\" after multiple bundles\n");1850return;1851}18521853pipe_class->setMultipleBundles(true);1854next_char(); skipws();1855continue;1856}18571858if (!strcmp(ident, "has_delay_slot")) {1859skipws();1860if (_curchar != ';') {1861parse_err(SYNERR, "missing \";\" after \"has_delay_slot\"\n");1862return;1863}18641865pipe_class->setBranchDelay(true);1866next_char(); skipws();1867continue;1868}18691870if (!strcmp(ident, "force_serialization")) {1871skipws();1872if (_curchar != ';') {1873parse_err(SYNERR, "missing \";\" after \"force_serialization\"\n");1874return;1875}18761877pipe_class->setForceSerialization(true);1878next_char(); skipws();1879continue;1880}18811882if (!strcmp(ident, "may_have_no_code")) {1883skipws();1884if (_curchar != ';') {1885parse_err(SYNERR, "missing \";\" after \"may_have_no_code\"\n");1886return;1887}18881889pipe_class->setMayHaveNoCode(true);1890next_char(); skipws();1891continue;1892}18931894const Form *parm = pipe_class->_localNames[ident];1895if (parm != NULL) {1896oper = parm->is_operand();1897if (oper == NULL && !parm->is_opclass()) {1898parse_err(SYNERR, "operand name expected at %s\n", ident);1899continue;1900}19011902if (_curchar != ':') {1903parse_err(SYNERR, "\":\" expected at \"%c\"\n", _curchar);1904continue;1905}1906next_char(); skipws();1907stage = get_ident();1908if (stage == NULL) {1909parse_err(SYNERR, "pipeline stage identifier expected at \"%c\"\n", _curchar);1910continue;1911}19121913skipws();1914if (_curchar != '(') {1915parse_err(SYNERR, "\"(\" expected at \"%c\"\n", _curchar);1916continue;1917}19181919next_char();1920read_or_write = get_ident();1921if (read_or_write == NULL) {1922parse_err(SYNERR, "\"read\" or \"write\" expected at \"%c\"\n", _curchar);1923continue;1924}19251926is_read = strcmp(read_or_write, "read") == 0;1927is_write = strcmp(read_or_write, "write") == 0;1928if (!is_read && !is_write) {1929parse_err(SYNERR, "\"read\" or \"write\" expected at \"%c\"\n", _curchar);1930continue;1931}19321933skipws();1934if (_curchar != ')') {1935parse_err(SYNERR, "\")\" expected at \"%c\"\n", _curchar);1936continue;1937}19381939next_char(); skipws();1940int more_instrs = 0;1941if (_curchar == '+') {1942next_char(); skipws();1943if (_curchar < '0' || _curchar > '9') {1944parse_err(SYNERR, "<number> expected at \"%c\"\n", _curchar);1945continue;1946}1947while (_curchar >= '0' && _curchar <= '9') {1948more_instrs *= 10;1949more_instrs += _curchar - '0';1950next_char();1951}1952skipws();1953}19541955PipeClassOperandForm *pipe_operand = new PipeClassOperandForm(stage, is_write, more_instrs);1956pipe_class->_localUsage.Insert(ident, pipe_operand);19571958if (_curchar == '%')1959continue;19601961if (_curchar != ';') {1962parse_err(SYNERR, "\";\" expected at \"%c\"\n", _curchar);1963continue;1964}1965next_char(); skipws();1966continue;1967}19681969// Scan for Resource Specifier1970const Form *res = pipeline._resdict[ident];1971if (res != NULL) {1972int cyclecnt = 1;1973if (_curchar != ':') {1974parse_err(SYNERR, "\":\" expected at \"%c\"\n", _curchar);1975continue;1976}1977next_char(); skipws();1978stage = get_ident();1979if (stage == NULL) {1980parse_err(SYNERR, "pipeline stage identifier expected at \"%c\"\n", _curchar);1981continue;1982}19831984skipws();1985if (_curchar == '(') {1986next_char();1987cyclecnt = get_int();19881989skipws();1990if (_curchar != ')') {1991parse_err(SYNERR, "\")\" expected at \"%c\"\n", _curchar);1992continue;1993}19941995next_char(); skipws();1996}19971998PipeClassResourceForm *resource = new PipeClassResourceForm(ident, stage, cyclecnt);1999int stagenum = pipeline._stages.index(stage);2000if (pipeline._maxcycleused < (stagenum+cyclecnt))2001pipeline._maxcycleused = (stagenum+cyclecnt);2002pipe_class->_resUsage.addForm(resource);20032004if (_curchar == '%')2005continue;20062007if (_curchar != ';') {2008parse_err(SYNERR, "\";\" expected at \"%c\"\n", _curchar);2009continue;2010}2011next_char(); skipws();2012continue;2013}20142015parse_err(SYNERR, "resource expected at \"%s\"\n", ident);2016return;2017} while(_curchar != '%');20182019next_char();2020if (_curchar != '}') {2021parse_err(SYNERR, "missing \"%%}\" in pipe_class definition\n");2022return;2023}20242025next_char();2026}20272028//------------------------------peep_parse-------------------------------------2029void ADLParser::peep_parse(void) {2030Peephole *peep; // Pointer to current peephole rule form2031char *desc = NULL; // String representation of rule20322033skipws(); // Skip leading whitespace20342035peep = new Peephole(); // Build new Peephole object2036// Check for open block sequence2037skipws(); // Skip leading whitespace2038if (_curchar == '%' && *(_ptr+1) == '{') {2039next_char(); next_char(); // Skip "%{"2040skipws();2041while (_curchar != '%' && *(_ptr+1) != '}') {2042char *token = get_ident();2043if (token == NULL) {2044parse_err(SYNERR, "missing identifier inside peephole rule.\n");2045return;2046}2047// check for legal subsections of peephole rule2048if (strcmp(token,"peepmatch")==0) {2049peep_match_parse(*peep); }2050else if (strcmp(token,"peepconstraint")==0) {2051peep_constraint_parse(*peep); }2052else if (strcmp(token,"peepreplace")==0) {2053peep_replace_parse(*peep); }2054else {2055parse_err(SYNERR, "expected peepmatch, peepconstraint, or peepreplace for identifier %s.\n", token);2056}2057skipws();2058}2059}2060else {2061parse_err(SYNERR, "Missing %%{ ... %%} block after peephole keyword.\n");2062return;2063}2064next_char(); // Skip past '%'2065next_char(); // Skip past '}'2066}20672068// ******************** Private Level 2 Parse Functions ********************2069//------------------------------constraint_parse------------------------------2070Constraint *ADLParser::constraint_parse(void) {2071char *func;2072char *arg;20732074// Check for constraint expression2075skipws();2076if (_curchar != '(') {2077parse_err(SYNERR, "missing constraint expression, (...)\n");2078return NULL;2079}2080next_char(); // Skip past '('20812082// Get constraint function2083skipws();2084func = get_ident();2085if (func == NULL) {2086parse_err(SYNERR, "missing function in constraint expression.\n");2087return NULL;2088}2089if (strcmp(func,"ALLOC_IN_RC")==02090|| strcmp(func,"IS_R_CLASS")==0) {2091// Check for '(' before argument2092skipws();2093if (_curchar != '(') {2094parse_err(SYNERR, "missing '(' for constraint function's argument.\n");2095return NULL;2096}2097next_char();20982099// Get it's argument2100skipws();2101arg = get_ident();2102if (arg == NULL) {2103parse_err(SYNERR, "missing argument for constraint function %s\n",func);2104return NULL;2105}2106// Check for ')' after argument2107skipws();2108if (_curchar != ')') {2109parse_err(SYNERR, "missing ')' after constraint function argument %s\n",arg);2110return NULL;2111}2112next_char();2113} else {2114parse_err(SYNERR, "Invalid constraint function %s\n",func);2115return NULL;2116}21172118// Check for closing paren and ';'2119skipws();2120if (_curchar != ')') {2121parse_err(SYNERR, "Missing ')' for constraint function %s\n",func);2122return NULL;2123}2124next_char();2125skipws();2126if (_curchar != ';') {2127parse_err(SYNERR, "Missing ';' after constraint.\n");2128return NULL;2129}2130next_char();21312132// Create new "Constraint"2133Constraint *constraint = new Constraint(func,arg);2134return constraint;2135}21362137//------------------------------constr_parse-----------------------------------2138ConstructRule *ADLParser::construct_parse(void) {2139return NULL;2140}214121422143//------------------------------reg_def_parse----------------------------------2144void ADLParser::reg_def_parse(void) {2145char *rname; // Name of register being defined21462147// Get register name2148skipws(); // Skip whitespace2149rname = get_ident();2150if (rname == NULL) {2151parse_err(SYNERR, "missing register name after reg_def\n");2152return;2153}21542155// Check for definition of register calling convention (save on call, ...),2156// register save type, and register encoding value.2157skipws();2158char *callconv = NULL;2159char *c_conv = NULL;2160char *idealtype = NULL;2161char *encoding = NULL;2162char *concrete = NULL;2163if (_curchar == '(') {2164next_char();2165callconv = get_ident();2166// Parse the internal calling convention, must be NS, SOC, SOE, or AS.2167if (callconv == NULL) {2168parse_err(SYNERR, "missing register calling convention value\n");2169return;2170}2171if(strcmp(callconv, "SOC") && strcmp(callconv,"SOE") &&2172strcmp(callconv, "NS") && strcmp(callconv, "AS")) {2173parse_err(SYNERR, "invalid value for register calling convention\n");2174}2175skipws();2176if (_curchar != ',') {2177parse_err(SYNERR, "missing comma in register definition statement\n");2178return;2179}2180next_char();21812182// Parse the native calling convention, must be NS, SOC, SOE, AS2183c_conv = get_ident();2184if (c_conv == NULL) {2185parse_err(SYNERR, "missing register native calling convention value\n");2186return;2187}2188if(strcmp(c_conv, "SOC") && strcmp(c_conv,"SOE") &&2189strcmp(c_conv, "NS") && strcmp(c_conv, "AS")) {2190parse_err(SYNERR, "invalid value for register calling convention\n");2191}2192skipws();2193if (_curchar != ',') {2194parse_err(SYNERR, "missing comma in register definition statement\n");2195return;2196}2197next_char();2198skipws();21992200// Parse the ideal save type2201idealtype = get_ident();2202if (idealtype == NULL) {2203parse_err(SYNERR, "missing register save type value\n");2204return;2205}2206skipws();2207if (_curchar != ',') {2208parse_err(SYNERR, "missing comma in register definition statement\n");2209return;2210}2211next_char();2212skipws();22132214// Parse the encoding value2215encoding = get_expr("encoding", ",");2216if (encoding == NULL) {2217parse_err(SYNERR, "missing register encoding value\n");2218return;2219}2220trim(encoding);2221if (_curchar != ',') {2222parse_err(SYNERR, "missing comma in register definition statement\n");2223return;2224}2225next_char();2226skipws();2227// Parse the concrete name type2228// concrete = get_ident();2229concrete = get_expr("concrete", ")");2230if (concrete == NULL) {2231parse_err(SYNERR, "missing vm register name value\n");2232return;2233}22342235if (_curchar != ')') {2236parse_err(SYNERR, "missing ')' in register definition statement\n");2237return;2238}2239next_char();2240}22412242// Check for closing ';'2243skipws();2244if (_curchar != ';') {2245parse_err(SYNERR, "missing ';' after reg_def\n");2246return;2247}2248next_char(); // move past ';'22492250// Debug Stuff2251if (_AD._adl_debug > 1) {2252fprintf(stderr,"Register Definition: %s ( %s, %s %s )\n", rname,2253(callconv ? callconv : ""), (c_conv ? c_conv : ""), concrete);2254}22552256// Record new register definition.2257_AD._register->addRegDef(rname, callconv, c_conv, idealtype, encoding, concrete);2258return;2259}22602261//------------------------------reg_class_parse--------------------------------2262void ADLParser::reg_class_parse(void) {2263char *cname; // Name of register class being defined22642265// Get register class name2266skipws(); // Skip leading whitespace2267cname = get_ident();2268if (cname == NULL) {2269parse_err(SYNERR, "missing register class name after 'reg_class'\n");2270return;2271}2272// Debug Stuff2273if (_AD._adl_debug >1) fprintf(stderr,"Register Class: %s\n", cname);22742275skipws();2276if (_curchar == '(') {2277// A register list is defined for the register class.2278// Collect registers into a generic RegClass register class.2279RegClass* reg_class = _AD._register->addRegClass<RegClass>(cname);22802281next_char(); // Skip '('2282skipws();2283while (_curchar != ')') {2284char *rname = get_ident();2285if (rname==NULL) {2286parse_err(SYNERR, "missing identifier inside reg_class list.\n");2287return;2288}2289RegDef *regDef = _AD._register->getRegDef(rname);2290if (!regDef) {2291parse_err(SEMERR, "unknown identifier %s inside reg_class list.\n", rname);2292} else {2293reg_class->addReg(regDef); // add regDef to regClass2294}22952296// Check for ',' and position to next token.2297skipws();2298if (_curchar == ',') {2299next_char(); // Skip trailing ','2300skipws();2301}2302}2303next_char(); // Skip closing ')'2304} else if (_curchar == '%') {2305// A code snippet is defined for the register class.2306// Collect the code snippet into a CodeSnippetRegClass register class.2307CodeSnippetRegClass* reg_class = _AD._register->addRegClass<CodeSnippetRegClass>(cname);2308char *code = find_cpp_block("reg class");2309if (code == NULL) {2310parse_err(SYNERR, "missing code declaration for reg class.\n");2311return;2312}2313reg_class->set_code_snippet(code);2314return;2315}23162317// Check for terminating ';'2318skipws();2319if (_curchar != ';') {2320parse_err(SYNERR, "missing ';' at end of reg_class definition.\n");2321return;2322}2323next_char(); // Skip trailing ';'23242325// Check RegClass size, must be <= 32 registers in class.23262327return;2328}23292330//------------------------------reg_class_dynamic_parse------------------------2331void ADLParser::reg_class_dynamic_parse(void) {2332char *cname; // Name of dynamic register class being defined23332334// Get register class name2335skipws();2336cname = get_ident();2337if (cname == NULL) {2338parse_err(SYNERR, "missing dynamic register class name after 'reg_class_dynamic'\n");2339return;2340}23412342if (_AD._adl_debug > 1) {2343fprintf(stdout, "Dynamic Register Class: %s\n", cname);2344}23452346skipws();2347if (_curchar != '(') {2348parse_err(SYNERR, "missing '(' at the beginning of reg_class_dynamic definition\n");2349return;2350}2351next_char();2352skipws();23532354// Collect two register classes and the C++ code representing the condition code used to2355// select between the two classes into a ConditionalRegClass register class.2356ConditionalRegClass* reg_class = _AD._register->addRegClass<ConditionalRegClass>(cname);2357int i;2358for (i = 0; i < 2; i++) {2359char* name = get_ident();2360if (name == NULL) {2361parse_err(SYNERR, "missing class identifier inside reg_class_dynamic list.\n");2362return;2363}2364RegClass* rc = _AD._register->getRegClass(name);2365if (rc == NULL) {2366parse_err(SEMERR, "unknown identifier %s inside reg_class_dynamic list.\n", name);2367} else {2368reg_class->set_rclass_at_index(i, rc);2369}23702371skipws();2372if (_curchar == ',') {2373next_char();2374skipws();2375} else {2376parse_err(SYNERR, "missing separator ',' inside reg_class_dynamic list.\n");2377}2378}23792380// Collect the condition code.2381skipws();2382if (_curchar == '%') {2383char* code = find_cpp_block("reg class dynamic");2384if (code == NULL) {2385parse_err(SYNERR, "missing code declaration for reg_class_dynamic.\n");2386return;2387}2388reg_class->set_condition_code(code);2389} else {2390parse_err(SYNERR, "missing %% at the beginning of code block in reg_class_dynamic definition\n");2391return;2392}23932394skipws();2395if (_curchar != ')') {2396parse_err(SYNERR, "missing ')' at the end of reg_class_dynamic definition\n");2397return;2398}2399next_char();24002401skipws();2402if (_curchar != ';') {2403parse_err(SYNERR, "missing ';' at the end of reg_class_dynamic definition.\n");2404return;2405}2406next_char(); // Skip trailing ';'24072408return;2409}24102411//------------------------------alloc_class_parse------------------------------2412void ADLParser::alloc_class_parse(void) {2413char *name; // Name of allocation class being defined24142415// Get allocation class name2416skipws(); // Skip leading whitespace2417name = get_ident();2418if (name == NULL) {2419parse_err(SYNERR, "missing allocation class name after 'reg_class'\n");2420return;2421}2422// Debug Stuff2423if (_AD._adl_debug >1) fprintf(stderr,"Allocation Class: %s\n", name);24242425AllocClass *alloc_class = _AD._register->addAllocClass(name);24262427// Collect registers in class2428skipws();2429if (_curchar == '(') {2430next_char(); // Skip '('2431skipws();2432while (_curchar != ')') {2433char *rname = get_ident();2434if (rname==NULL) {2435parse_err(SYNERR, "missing identifier inside reg_class list.\n");2436return;2437}2438// Check if name is a RegDef2439RegDef *regDef = _AD._register->getRegDef(rname);2440if (regDef) {2441alloc_class->addReg(regDef); // add regDef to allocClass2442} else {24432444// name must be a RegDef or a RegClass2445parse_err(SYNERR, "name %s should be a previously defined reg_def.\n", rname);2446return;2447}24482449// Check for ',' and position to next token.2450skipws();2451if (_curchar == ',') {2452next_char(); // Skip trailing ','2453skipws();2454}2455}2456next_char(); // Skip closing ')'2457}24582459// Check for terminating ';'2460skipws();2461if (_curchar != ';') {2462parse_err(SYNERR, "missing ';' at end of reg_class definition.\n");2463return;2464}2465next_char(); // Skip trailing ';'24662467return;2468}24692470//------------------------------peep_match_child_parse-------------------------2471InstructForm *ADLParser::peep_match_child_parse(PeepMatch &match, int parent, int &position, int input){2472char *token = NULL;2473int lparen = 0; // keep track of parenthesis nesting depth2474int rparen = 0; // position of instruction at this depth2475InstructForm *inst_seen = NULL;24762477// Walk the match tree,2478// Record <parent, position, instruction name, input position>2479while ( lparen >= rparen ) {2480skipws();2481// Left paren signals start of an input, collect with recursive call2482if (_curchar == '(') {2483++lparen;2484next_char();2485( void ) peep_match_child_parse(match, parent, position, rparen);2486}2487// Right paren signals end of an input, may be more2488else if (_curchar == ')') {2489++rparen;2490if( rparen == lparen ) { // IF rparen matches an lparen I've seen2491next_char(); // move past ')'2492} else { // ELSE leave ')' for parent2493assert( rparen == lparen + 1, "Should only see one extra ')'");2494// if an instruction was not specified for this paren-pair2495if( ! inst_seen ) { // record signal entry2496match.add_instruction( parent, position, NameList::_signal, input );2497++position;2498}2499// ++input; // TEMPORARY2500return inst_seen;2501}2502}2503// if no parens, then check for instruction name2504// This instruction is the parent of a sub-tree2505else if ((token = get_ident_dup()) != NULL) {2506const Form *form = _AD._globalNames[token];2507if (form) {2508InstructForm *inst = form->is_instruction();2509// Record the first instruction at this level2510if( inst_seen == NULL ) {2511inst_seen = inst;2512}2513if (inst) {2514match.add_instruction( parent, position, token, input );2515parent = position;2516++position;2517} else {2518parse_err(SYNERR, "instruction name expected at identifier %s.\n",2519token);2520return inst_seen;2521}2522}2523else {2524parse_err(SYNERR, "missing identifier in peepmatch rule.\n");2525return NULL;2526}2527}2528else {2529parse_err(SYNERR, "missing identifier in peepmatch rule.\n");2530return NULL;2531}25322533} // end while25342535assert( false, "ShouldNotReachHere();");2536return NULL;2537}25382539//------------------------------peep_match_parse-------------------------------2540// Syntax for a peepmatch rule2541//2542// peepmatch ( root_instr_name [(instruction subtree)] [,(instruction subtree)]* );2543//2544void ADLParser::peep_match_parse(Peephole &peep) {25452546skipws();2547// Check the structure of the rule2548// Check for open paren2549if (_curchar != '(') {2550parse_err(SYNERR, "missing '(' at start of peepmatch rule.\n");2551return;2552}2553next_char(); // skip '('25542555// Construct PeepMatch and parse the peepmatch rule.2556PeepMatch *match = new PeepMatch(_ptr);2557int parent = -1; // parent of root2558int position = 0; // zero-based positions2559int input = 0; // input position in parent's operands2560InstructForm *root= peep_match_child_parse( *match, parent, position, input);2561if( root == NULL ) {2562parse_err(SYNERR, "missing instruction-name at start of peepmatch.\n");2563return;2564}25652566if( _curchar != ')' ) {2567parse_err(SYNERR, "missing ')' at end of peepmatch.\n");2568return;2569}2570next_char(); // skip ')'25712572// Check for closing semicolon2573skipws();2574if( _curchar != ';' ) {2575parse_err(SYNERR, "missing ';' at end of peepmatch.\n");2576return;2577}2578next_char(); // skip ';'25792580// Store match into peep, and store peep into instruction2581peep.add_match(match);2582root->append_peephole(&peep);2583}25842585//------------------------------peep_constraint_parse--------------------------2586// Syntax for a peepconstraint rule2587// A parenthesized list of relations between operands in peepmatch subtree2588//2589// peepconstraint %{2590// (instruction_number.operand_name2591// relational_op2592// instruction_number.operand_name OR register_name2593// [, ...] );2594//2595// // instruction numbers are zero-based using topological order in peepmatch2596//2597void ADLParser::peep_constraint_parse(Peephole &peep) {25982599skipws();2600// Check the structure of the rule2601// Check for open paren2602if (_curchar != '(') {2603parse_err(SYNERR, "missing '(' at start of peepconstraint rule.\n");2604return;2605}2606else {2607next_char(); // Skip '('2608}26092610// Check for a constraint2611skipws();2612while( _curchar != ')' ) {2613// Get information on the left instruction and its operand2614// left-instructions's number2615int left_inst = get_int();2616// Left-instruction's operand2617skipws();2618if( _curchar != '.' ) {2619parse_err(SYNERR, "missing '.' in peepconstraint after instruction number.\n");2620return;2621}2622next_char(); // Skip '.'2623char *left_op = get_ident_dup();26242625skipws();2626// Collect relational operator2627char *relation = get_relation_dup();26282629skipws();2630// Get information on the right instruction and its operand2631int right_inst; // Right-instructions's number2632if( isdigit(_curchar) ) {2633right_inst = get_int();2634// Right-instruction's operand2635skipws();2636if( _curchar != '.' ) {2637parse_err(SYNERR, "missing '.' in peepconstraint after instruction number.\n");2638return;2639}2640next_char(); // Skip '.'2641} else {2642right_inst = -1; // Flag as being a register constraint2643}26442645char *right_op = get_ident_dup();26462647// Construct the next PeepConstraint2648PeepConstraint *constraint = new PeepConstraint( left_inst, left_op,2649relation,2650right_inst, right_op );2651// And append it to the list for this peephole rule2652peep.append_constraint( constraint );26532654// Check for another constraint, or end of rule2655skipws();2656if( _curchar == ',' ) {2657next_char(); // Skip ','2658skipws();2659}2660else if( _curchar != ')' ) {2661parse_err(SYNERR, "expected ',' or ')' after peephole constraint.\n");2662return;2663}2664} // end while( processing constraints )2665next_char(); // Skip ')'26662667// Check for terminating ';'2668skipws();2669if (_curchar != ';') {2670parse_err(SYNERR, "missing ';' at end of peepconstraint.\n");2671return;2672}2673next_char(); // Skip trailing ';'2674}267526762677//------------------------------peep_replace_parse-----------------------------2678// Syntax for a peepreplace rule2679// root instruction name followed by a2680// parenthesized list of whitespace separated instruction.operand specifiers2681//2682// peepreplace ( instr_name ( [instruction_number.operand_name]* ) );2683//2684//2685void ADLParser::peep_replace_parse(Peephole &peep) {2686int lparen = 0; // keep track of parenthesis nesting depth2687int rparen = 0; // keep track of parenthesis nesting depth2688int icount = 0; // count of instructions in rule for naming2689char *str = NULL;2690char *token = NULL;26912692skipws();2693// Check for open paren2694if (_curchar != '(') {2695parse_err(SYNERR, "missing '(' at start of peepreplace rule.\n");2696return;2697}2698else {2699lparen++;2700next_char();2701}27022703// Check for root instruction2704char *inst = get_ident_dup();2705const Form *form = _AD._globalNames[inst];2706if( form == NULL || form->is_instruction() == NULL ) {2707parse_err(SYNERR, "Instruction name expected at start of peepreplace.\n");2708return;2709}27102711// Store string representation of rule into replace2712PeepReplace *replace = new PeepReplace(str);2713replace->add_instruction( inst );27142715skipws();2716// Start of root's operand-list2717if (_curchar != '(') {2718parse_err(SYNERR, "missing '(' at peepreplace root's operand-list.\n");2719return;2720}2721else {2722lparen++;2723next_char();2724}27252726skipws();2727// Get the list of operands2728while( _curchar != ')' ) {2729// Get information on an instruction and its operand2730// instructions's number2731int inst_num = get_int();2732// Left-instruction's operand2733skipws();2734if( _curchar != '.' ) {2735parse_err(SYNERR, "missing '.' in peepreplace after instruction number.\n");2736return;2737}2738next_char(); // Skip '.'2739char *inst_op = get_ident_dup();2740if( inst_op == NULL ) {2741parse_err(SYNERR, "missing operand identifier in peepreplace.\n");2742return;2743}27442745// Record this operand's position in peepmatch2746replace->add_operand( inst_num, inst_op );2747skipws();2748}27492750// Check for the end of operands list2751skipws();2752assert( _curchar == ')', "While loop should have advanced to ')'.");2753next_char(); // Skip ')'27542755skipws();2756// Check for end of peepreplace2757if( _curchar != ')' ) {2758parse_err(SYNERR, "missing ')' at end of peepmatch.\n");2759parse_err(SYNERR, "Support one replacement instruction.\n");2760return;2761}2762next_char(); // Skip ')'27632764// Check for closing semicolon2765skipws();2766if( _curchar != ';' ) {2767parse_err(SYNERR, "missing ';' at end of peepreplace.\n");2768return;2769}2770next_char(); // skip ';'27712772// Store replace into peep2773peep.add_replace( replace );2774}27752776//------------------------------pred_parse-------------------------------------2777Predicate *ADLParser::pred_parse(void) {2778Predicate *predicate; // Predicate class for operand2779char *rule = NULL; // String representation of predicate27802781skipws(); // Skip leading whitespace2782int line = linenum();2783if ( (rule = get_paren_expr("pred expression", true)) == NULL ) {2784parse_err(SYNERR, "incorrect or missing expression for 'predicate'\n");2785return NULL;2786}2787// Debug Stuff2788if (_AD._adl_debug > 1) fprintf(stderr,"Predicate: %s\n", rule);2789if (_curchar != ';') {2790parse_err(SYNERR, "missing ';' in predicate definition\n");2791return NULL;2792}2793next_char(); // Point after the terminator27942795predicate = new Predicate(rule); // Build new predicate object2796skipws();2797return predicate;2798}279928002801//------------------------------ins_encode_parse_block-------------------------2802// Parse the block form of ins_encode. See ins_encode_parse for more details2803void ADLParser::ins_encode_parse_block(InstructForm& inst) {2804// Create a new encoding name based on the name of the instruction2805// definition, which should be unique.2806const char* prefix = "__ins_encode_";2807char* ec_name = (char*) AllocateHeap(strlen(inst._ident) + strlen(prefix) + 1);2808sprintf(ec_name, "%s%s", prefix, inst._ident);28092810assert(_AD._encode->encClass(ec_name) == NULL, "shouldn't already exist");2811EncClass* encoding = _AD._encode->add_EncClass(ec_name);2812encoding->_linenum = linenum();28132814// synthesize the arguments list for the enc_class from the2815// arguments to the instruct definition.2816const char* param = NULL;2817inst._parameters.reset();2818while ((param = inst._parameters.iter()) != NULL) {2819OpClassForm* opForm = inst._localNames[param]->is_opclass();2820assert(opForm != NULL, "sanity");2821encoding->add_parameter(opForm->_ident, param);2822}28232824if (!inst._is_postalloc_expand) {2825// Define a MacroAssembler instance for use by the encoding. The2826// name is chosen to match the __ idiom used for assembly in other2827// parts of hotspot and assumes the existence of the standard2828// #define __ _masm.2829encoding->add_code(" C2_MacroAssembler _masm(&cbuf);\n");2830}28312832// Parse the following %{ }% block2833ins_encode_parse_block_impl(inst, encoding, ec_name);28342835// Build an encoding rule which invokes the encoding rule we just2836// created, passing all arguments that we received.2837InsEncode* encrule = new InsEncode(); // Encode class for instruction2838NameAndList* params = encrule->add_encode(ec_name);2839inst._parameters.reset();2840while ((param = inst._parameters.iter()) != NULL) {2841params->add_entry(param);2842}28432844// Check for duplicate ins_encode sections after parsing the block2845// so that parsing can continue and find any other errors.2846if (inst._insencode != NULL) {2847parse_err(SYNERR, "Multiple ins_encode sections defined\n");2848return;2849}28502851// Set encode class of this instruction.2852inst._insencode = encrule;2853}285428552856void ADLParser::ins_encode_parse_block_impl(InstructForm& inst, EncClass* encoding, char* ec_name) {2857skipws_no_preproc(); // Skip leading whitespace2858// Prepend location descriptor, for debugging; cf. ADLParser::find_cpp_block2859if (_AD._adlocation_debug) {2860encoding->add_code(get_line_string());2861}28622863// Collect the parts of the encode description2864// (1) strings that are passed through to output2865// (2) replacement/substitution variable, preceeded by a '$'2866while ((_curchar != '%') && (*(_ptr+1) != '}')) {28672868// (1)2869// Check if there is a string to pass through to output2870char *start = _ptr; // Record start of the next string2871while ((_curchar != '$') && ((_curchar != '%') || (*(_ptr+1) != '}')) ) {2872// If at the start of a comment, skip past it2873if( (_curchar == '/') && ((*(_ptr+1) == '/') || (*(_ptr+1) == '*')) ) {2874skipws_no_preproc();2875} else {2876// ELSE advance to the next character, or start of the next line2877next_char_or_line();2878}2879}2880// If a string was found, terminate it and record in EncClass2881if (start != _ptr) {2882*_ptr = '\0'; // Terminate the string2883encoding->add_code(start);2884}28852886// (2)2887// If we are at a replacement variable,2888// copy it and record in EncClass2889if (_curchar == '$') {2890// Found replacement Variable2891char* rep_var = get_rep_var_ident_dup();28922893// Add flag to _strings list indicating we should check _rep_vars2894encoding->add_rep_var(rep_var);28952896skipws();28972898// Check if this instruct is a MachConstantNode.2899if (strcmp(rep_var, "constanttablebase") == 0) {2900// This instruct is a MachConstantNode.2901inst.set_needs_constant_base(true);2902if (strncmp("MachCall", inst.mach_base_class(_globalNames), strlen("MachCall")) != 0 ) {2903inst.set_is_mach_constant(true);2904}29052906if (_curchar == '(') {2907parse_err(SYNERR, "constanttablebase in instruct %s cannot have an argument "2908"(only constantaddress and constantoffset)", ec_name);2909return;2910}2911}2912else if ((strcmp(rep_var, "constantaddress") == 0) ||2913(strcmp(rep_var, "constantoffset") == 0)) {2914// This instruct is a MachConstantNode.2915inst.set_is_mach_constant(true);29162917// If the constant keyword has an argument, parse it.2918if (_curchar == '(') constant_parse(inst);2919}2920}2921} // end while part of format description2922next_char(); // Skip '%'2923next_char(); // Skip '}'29242925skipws();29262927if (_AD._adlocation_debug) {2928encoding->add_code(end_line_marker());2929}29302931// Debug Stuff2932if (_AD._adl_debug > 1) fprintf(stderr, "EncodingClass Form: %s\n", ec_name);2933}293429352936//------------------------------ins_encode_parse-------------------------------2937// Encode rules have the form2938// ins_encode( encode_class_name(parameter_list), ... );2939//2940// The "encode_class_name" must be defined in the encode section2941// The parameter list contains $names that are locals.2942//2943// Alternatively it can be written like this:2944//2945// ins_encode %{2946// ... // body2947// %}2948//2949// which synthesizes a new encoding class taking the same arguments as2950// the InstructForm, and automatically prefixes the definition with:2951//2952// C2_MacroAssembler masm(&cbuf);\n");2953//2954// making it more compact to take advantage of the C2_MacroAssembler and2955// placing the assembly closer to it's use by instructions.2956void ADLParser::ins_encode_parse(InstructForm& inst) {29572958// Parse encode class name2959skipws(); // Skip whitespace2960if (_curchar != '(') {2961// Check for ins_encode %{ form2962if ((_curchar == '%') && (*(_ptr+1) == '{')) {2963next_char(); // Skip '%'2964next_char(); // Skip '{'29652966// Parse the block form of ins_encode2967ins_encode_parse_block(inst);2968return;2969}29702971parse_err(SYNERR, "missing '%%{' or '(' in ins_encode definition\n");2972return;2973}2974next_char(); // move past '('2975skipws();29762977InsEncode *encrule = new InsEncode(); // Encode class for instruction2978encrule->_linenum = linenum();2979char *ec_name = NULL; // String representation of encode rule2980// identifier is optional.2981while (_curchar != ')') {2982ec_name = get_ident();2983if (ec_name == NULL) {2984parse_err(SYNERR, "Invalid encode class name after 'ins_encode('.\n");2985return;2986}2987// Check that encoding is defined in the encode section2988EncClass *encode_class = _AD._encode->encClass(ec_name);2989if (encode_class == NULL) {2990// Like to defer checking these till later...2991// parse_err(WARN, "Using an undefined encode class '%s' in 'ins_encode'.\n", ec_name);2992}29932994// Get list for encode method's parameters2995NameAndList *params = encrule->add_encode(ec_name);29962997// Parse the parameters to this encode method.2998skipws();2999if ( _curchar == '(' ) {3000next_char(); // move past '(' for parameters30013002// Parse the encode method's parameters3003while (_curchar != ')') {3004char *param = get_ident_or_literal_constant("encoding operand");3005if ( param != NULL ) {30063007// Check if this instruct is a MachConstantNode.3008if (strcmp(param, "constanttablebase") == 0) {3009// This instruct is a MachConstantNode.3010inst.set_needs_constant_base(true);3011if (strncmp("MachCall", inst.mach_base_class(_globalNames), strlen("MachCall")) != 0 ) {3012inst.set_is_mach_constant(true);3013}30143015if (_curchar == '(') {3016parse_err(SYNERR, "constanttablebase in instruct %s cannot have an argument "3017"(only constantaddress and constantoffset)", ec_name);3018return;3019}3020} else {3021// Found a parameter:3022// Check it is a local name, add it to the list, then check for more3023// New: allow hex constants as parameters to an encode method.3024// New: allow parenthesized expressions as parameters.3025// New: allow "primary", "secondary", "tertiary" as parameters.3026// New: allow user-defined register name as parameter3027if ( (inst._localNames[param] == NULL) &&3028!ADLParser::is_literal_constant(param) &&3029(Opcode::as_opcode_type(param) == Opcode::NOT_AN_OPCODE) &&3030((_AD._register == NULL ) || (_AD._register->getRegDef(param) == NULL)) ) {3031parse_err(SYNERR, "Using non-locally defined parameter %s for encoding %s.\n", param, ec_name);3032return;3033}3034}3035params->add_entry(param);30363037skipws();3038if (_curchar == ',' ) {3039// More parameters to come3040next_char(); // move past ',' between parameters3041skipws(); // Skip to next parameter3042}3043else if (_curchar == ')') {3044// Done with parameter list3045}3046else {3047// Only ',' or ')' are valid after a parameter name3048parse_err(SYNERR, "expected ',' or ')' after parameter %s.\n",3049ec_name);3050return;3051}30523053} else {3054skipws();3055// Did not find a parameter3056if (_curchar == ',') {3057parse_err(SYNERR, "Expected encode parameter before ',' in encoding %s.\n", ec_name);3058return;3059}3060if (_curchar != ')') {3061parse_err(SYNERR, "Expected ')' after encode parameters.\n");3062return;3063}3064}3065} // WHILE loop collecting parameters3066next_char(); // move past ')' at end of parameters3067} // done with parameter list for encoding30683069// Check for ',' or ')' after encoding3070skipws(); // move to character after parameters3071if ( _curchar == ',' ) {3072// Found a ','3073next_char(); // move past ',' between encode methods3074skipws();3075}3076else if ( _curchar != ')' ) {3077// If not a ',' then only a ')' is allowed3078parse_err(SYNERR, "Expected ')' after encoding %s.\n", ec_name);3079return;3080}30813082// Check for ',' separating parameters3083// if ( _curchar != ',' && _curchar != ')' ) {3084// parse_err(SYNERR, "expected ',' or ')' after encode method inside ins_encode.\n");3085// return NULL;3086// }30873088} // done parsing ins_encode methods and their parameters3089if (_curchar != ')') {3090parse_err(SYNERR, "Missing ')' at end of ins_encode description.\n");3091return;3092}3093next_char(); // move past ')'3094skipws(); // Skip leading whitespace30953096if ( _curchar != ';' ) {3097parse_err(SYNERR, "Missing ';' at end of ins_encode.\n");3098return;3099}3100next_char(); // move past ';'3101skipws(); // be friendly to oper_parse()31023103// Check for duplicate ins_encode sections after parsing the block3104// so that parsing can continue and find any other errors.3105if (inst._insencode != NULL) {3106parse_err(SYNERR, "Multiple ins_encode sections defined\n");3107return;3108}31093110// Debug Stuff3111if (_AD._adl_debug > 1) fprintf(stderr,"Instruction Encode: %s\n", ec_name);31123113// Set encode class of this instruction.3114inst._insencode = encrule;3115}31163117//------------------------------postalloc_expand_parse---------------------------3118// Encode rules have the form3119// postalloc_expand( encode_class_name(parameter_list) );3120//3121// The "encode_class_name" must be defined in the encode section.3122// The parameter list contains $names that are locals.3123//3124// This is just a copy of ins_encode_parse without the loop.3125void ADLParser::postalloc_expand_parse(InstructForm& inst) {3126inst._is_postalloc_expand = true;31273128// Parse encode class name.3129skipws(); // Skip whitespace.3130if (_curchar != '(') {3131// Check for postalloc_expand %{ form3132if ((_curchar == '%') && (*(_ptr+1) == '{')) {3133next_char(); // Skip '%'3134next_char(); // Skip '{'31353136// Parse the block form of postalloc_expand3137ins_encode_parse_block(inst);3138return;3139}31403141parse_err(SYNERR, "missing '(' in postalloc_expand definition\n");3142return;3143}3144next_char(); // Move past '('.3145skipws();31463147InsEncode *encrule = new InsEncode(); // Encode class for instruction.3148encrule->_linenum = linenum();3149char *ec_name = NULL; // String representation of encode rule.3150// identifier is optional.3151if (_curchar != ')') {3152ec_name = get_ident();3153if (ec_name == NULL) {3154parse_err(SYNERR, "Invalid postalloc_expand class name after 'postalloc_expand('.\n");3155return;3156}3157// Check that encoding is defined in the encode section.3158EncClass *encode_class = _AD._encode->encClass(ec_name);31593160// Get list for encode method's parameters3161NameAndList *params = encrule->add_encode(ec_name);31623163// Parse the parameters to this encode method.3164skipws();3165if (_curchar == '(') {3166next_char(); // Move past '(' for parameters.31673168// Parse the encode method's parameters.3169while (_curchar != ')') {3170char *param = get_ident_or_literal_constant("encoding operand");3171if (param != NULL) {3172// Found a parameter:31733174// First check for constant table support.31753176// Check if this instruct is a MachConstantNode.3177if (strcmp(param, "constanttablebase") == 0) {3178// This instruct is a MachConstantNode.3179inst.set_needs_constant_base(true);3180if (strncmp("MachCall", inst.mach_base_class(_globalNames), strlen("MachCall")) != 0 ) {3181inst.set_is_mach_constant(true);3182}31833184if (_curchar == '(') {3185parse_err(SYNERR, "constanttablebase in instruct %s cannot have an argument "3186"(only constantaddress and constantoffset)", ec_name);3187return;3188}3189}3190else if ((strcmp(param, "constantaddress") == 0) ||3191(strcmp(param, "constantoffset") == 0)) {3192// This instruct is a MachConstantNode.3193inst.set_is_mach_constant(true);31943195// If the constant keyword has an argument, parse it.3196if (_curchar == '(') constant_parse(inst);3197}31983199// Else check it is a local name, add it to the list, then check for more.3200// New: allow hex constants as parameters to an encode method.3201// New: allow parenthesized expressions as parameters.3202// New: allow "primary", "secondary", "tertiary" as parameters.3203// New: allow user-defined register name as parameter.3204else if ((inst._localNames[param] == NULL) &&3205!ADLParser::is_literal_constant(param) &&3206(Opcode::as_opcode_type(param) == Opcode::NOT_AN_OPCODE) &&3207((_AD._register == NULL) || (_AD._register->getRegDef(param) == NULL))) {3208parse_err(SYNERR, "Using non-locally defined parameter %s for encoding %s.\n", param, ec_name);3209return;3210}3211params->add_entry(param);32123213skipws();3214if (_curchar == ',') {3215// More parameters to come.3216next_char(); // Move past ',' between parameters.3217skipws(); // Skip to next parameter.3218} else if (_curchar == ')') {3219// Done with parameter list3220} else {3221// Only ',' or ')' are valid after a parameter name.3222parse_err(SYNERR, "expected ',' or ')' after parameter %s.\n", ec_name);3223return;3224}32253226} else {3227skipws();3228// Did not find a parameter.3229if (_curchar == ',') {3230parse_err(SYNERR, "Expected encode parameter before ',' in postalloc_expand %s.\n", ec_name);3231return;3232}3233if (_curchar != ')') {3234parse_err(SYNERR, "Expected ')' after postalloc_expand parameters.\n");3235return;3236}3237}3238} // WHILE loop collecting parameters.3239next_char(); // Move past ')' at end of parameters.3240} // Done with parameter list for encoding.32413242// Check for ',' or ')' after encoding.3243skipws(); // Move to character after parameters.3244if (_curchar != ')') {3245// Only a ')' is allowed.3246parse_err(SYNERR, "Expected ')' after postalloc_expand %s.\n", ec_name);3247return;3248}3249} // Done parsing postalloc_expand method and their parameters.3250if (_curchar != ')') {3251parse_err(SYNERR, "Missing ')' at end of postalloc_expand description.\n");3252return;3253}3254next_char(); // Move past ')'.3255skipws(); // Skip leading whitespace.32563257if (_curchar != ';') {3258parse_err(SYNERR, "Missing ';' at end of postalloc_expand.\n");3259return;3260}3261next_char(); // Move past ';'.3262skipws(); // Be friendly to oper_parse().32633264// Debug Stuff.3265if (_AD._adl_debug > 1) fprintf(stderr, "Instruction postalloc_expand: %s\n", ec_name);32663267// Set encode class of this instruction.3268inst._insencode = encrule;3269}327032713272//------------------------------constant_parse---------------------------------3273// Parse a constant expression.3274void ADLParser::constant_parse(InstructForm& inst) {3275// Create a new encoding name based on the name of the instruction3276// definition, which should be unique.3277const char* prefix = "__constant_";3278char* ec_name = (char*) AllocateHeap(strlen(inst._ident) + strlen(prefix) + 1);3279sprintf(ec_name, "%s%s", prefix, inst._ident);32803281assert(_AD._encode->encClass(ec_name) == NULL, "shouldn't already exist");3282EncClass* encoding = _AD._encode->add_EncClass(ec_name);3283encoding->_linenum = linenum();32843285// synthesize the arguments list for the enc_class from the3286// arguments to the instruct definition.3287const char* param = NULL;3288inst._parameters.reset();3289while ((param = inst._parameters.iter()) != NULL) {3290OpClassForm* opForm = inst._localNames[param]->is_opclass();3291assert(opForm != NULL, "sanity");3292encoding->add_parameter(opForm->_ident, param);3293}32943295// Parse the following ( ) expression.3296constant_parse_expression(encoding, ec_name);32973298// Build an encoding rule which invokes the encoding rule we just3299// created, passing all arguments that we received.3300InsEncode* encrule = new InsEncode(); // Encode class for instruction3301NameAndList* params = encrule->add_encode(ec_name);3302inst._parameters.reset();3303while ((param = inst._parameters.iter()) != NULL) {3304params->add_entry(param);3305}33063307// Set encode class of this instruction.3308inst._constant = encrule;3309}331033113312//------------------------------constant_parse_expression----------------------3313void ADLParser::constant_parse_expression(EncClass* encoding, char* ec_name) {3314skipws();33153316// Prepend location descriptor, for debugging; cf. ADLParser::find_cpp_block3317if (_AD._adlocation_debug) {3318encoding->add_code(get_line_string());3319}33203321// Start code line.3322encoding->add_code(" _constant = C->output()->constant_table().add");33233324// Parse everything in ( ) expression.3325encoding->add_code("(this, ");3326next_char(); // Skip '('3327int parens_depth = 1;33283329// Collect the parts of the constant expression.3330// (1) strings that are passed through to output3331// (2) replacement/substitution variable, preceeded by a '$'3332while (parens_depth > 0) {3333if (_curchar == '(') {3334parens_depth++;3335encoding->add_code("(");3336next_char();3337}3338else if (_curchar == ')') {3339parens_depth--;3340if (parens_depth > 0)3341encoding->add_code(")");3342next_char();3343}3344else {3345// (1)3346// Check if there is a string to pass through to output3347char *start = _ptr; // Record start of the next string3348while ((_curchar != '$') && (_curchar != '(') && (_curchar != ')')) {3349next_char();3350}3351// If a string was found, terminate it and record in EncClass3352if (start != _ptr) {3353*_ptr = '\0'; // Terminate the string3354encoding->add_code(start);3355}33563357// (2)3358// If we are at a replacement variable, copy it and record in EncClass.3359if (_curchar == '$') {3360// Found replacement Variable3361char* rep_var = get_rep_var_ident_dup();3362encoding->add_rep_var(rep_var);3363}3364}3365}33663367// Finish code line.3368encoding->add_code(");");33693370if (_AD._adlocation_debug) {3371encoding->add_code(end_line_marker());3372}33733374// Debug Stuff3375if (_AD._adl_debug > 1) fprintf(stderr, "EncodingClass Form: %s\n", ec_name);3376}337733783379//------------------------------size_parse-----------------------------------3380// Parse a 'size(<expr>)' attribute which specifies the size of the3381// emitted instructions in bytes. <expr> can be a C++ expression,3382// e.g. a constant.3383char* ADLParser::size_parse(InstructForm *instr) {3384char* sizeOfInstr = NULL;33853386// Get value of the instruction's size3387skipws();33883389// Parse size3390sizeOfInstr = get_paren_expr("size expression");3391if (sizeOfInstr == NULL) {3392parse_err(SYNERR, "size of opcode expected at %c\n", _curchar);3393return NULL;3394}33953396skipws();33973398// Check for terminator3399if (_curchar != ';') {3400parse_err(SYNERR, "missing ';' in ins_attrib definition\n");3401return NULL;3402}3403next_char(); // Advance past the ';'3404skipws(); // necessary for instr_parse()34053406// Debug Stuff3407if (_AD._adl_debug > 1) {3408if (sizeOfInstr != NULL) {3409fprintf(stderr,"size of opcode: %s\n", sizeOfInstr);3410}3411}34123413return sizeOfInstr;3414}341534163417//------------------------------opcode_parse-----------------------------------3418Opcode * ADLParser::opcode_parse(InstructForm *instr) {3419char *primary = NULL;3420char *secondary = NULL;3421char *tertiary = NULL;34223423char *val = NULL;3424Opcode *opcode = NULL;34253426// Get value of the instruction's opcode3427skipws();3428if (_curchar != '(') { // Check for parenthesized operand list3429parse_err(SYNERR, "missing '(' in expand instruction declaration\n");3430return NULL;3431}3432next_char(); // skip open paren3433skipws();3434if (_curchar != ')') {3435// Parse primary, secondary, and tertiary opcodes, if provided.3436if ( (primary = get_ident_or_literal_constant("primary opcode")) == NULL ) {3437parse_err(SYNERR, "primary hex opcode expected at %c\n", _curchar);3438return NULL;3439}3440skipws();3441if (_curchar == ',') {3442next_char();3443skipws();3444// Parse secondary opcode3445if ( (secondary = get_ident_or_literal_constant("secondary opcode")) == NULL ) {3446parse_err(SYNERR, "secondary hex opcode expected at %c\n", _curchar);3447return NULL;3448}3449skipws();3450if (_curchar == ',') {3451next_char();3452skipws();3453// Parse tertiary opcode3454if ( (tertiary = get_ident_or_literal_constant("tertiary opcode")) == NULL ) {3455parse_err(SYNERR,"tertiary hex opcode expected at %c\n", _curchar);3456return NULL;3457}3458skipws();3459}3460}3461skipws();3462if (_curchar != ')') {3463parse_err(SYNERR, "Missing ')' in opcode description\n");3464return NULL;3465}3466}3467next_char(); // Skip ')'3468skipws();3469// Check for terminator3470if (_curchar != ';') {3471parse_err(SYNERR, "missing ';' in ins_attrib definition\n");3472return NULL;3473}3474next_char(); // Advance past the ';'3475skipws(); // necessary for instr_parse()34763477// Debug Stuff3478if (_AD._adl_debug > 1) {3479if (primary != NULL) fprintf(stderr,"primary opcode: %s\n", primary);3480if (secondary != NULL) fprintf(stderr,"secondary opcode: %s\n", secondary);3481if (tertiary != NULL) fprintf(stderr,"tertiary opcode: %s\n", tertiary);3482}34833484// Generate new object and return3485opcode = new Opcode(primary, secondary, tertiary);3486return opcode;3487}348834893490//------------------------------interface_parse--------------------------------3491Interface *ADLParser::interface_parse(void) {3492char *iface_name = NULL; // Name of interface class being used3493char *iface_code = NULL; // Describe components of this class34943495// Get interface class name3496skipws(); // Skip whitespace3497if (_curchar != '(') {3498parse_err(SYNERR, "Missing '(' at start of interface description.\n");3499return NULL;3500}3501next_char(); // move past '('3502skipws();3503iface_name = get_ident();3504if (iface_name == NULL) {3505parse_err(SYNERR, "missing interface name after 'interface'.\n");3506return NULL;3507}3508skipws();3509if (_curchar != ')') {3510parse_err(SYNERR, "Missing ')' after name of interface.\n");3511return NULL;3512}3513next_char(); // move past ')'35143515// Get details of the interface,3516// for the type of interface indicated by iface_name.3517Interface *inter = NULL;3518skipws();3519if ( _curchar != ';' ) {3520if ( strcmp(iface_name,"MEMORY_INTER") == 0 ) {3521inter = mem_interface_parse();3522}3523else if ( strcmp(iface_name,"COND_INTER") == 0 ) {3524inter = cond_interface_parse();3525}3526// The parse routines consume the "%}"35273528// Check for probable extra ';' after defining block.3529if ( _curchar == ';' ) {3530parse_err(SYNERR, "Extra ';' after defining interface block.\n");3531next_char(); // Skip ';'3532return NULL;3533}3534} else {3535next_char(); // move past ';'35363537// Create appropriate interface object3538if ( strcmp(iface_name,"REG_INTER") == 0 ) {3539inter = new RegInterface();3540}3541else if ( strcmp(iface_name,"CONST_INTER") == 0 ) {3542inter = new ConstInterface();3543}3544}3545skipws(); // be friendly to oper_parse()3546// Debug Stuff3547if (_AD._adl_debug > 1) fprintf(stderr,"Interface Form: %s\n", iface_name);35483549// Create appropriate interface object and return.3550return inter;3551}355235533554//------------------------------mem_interface_parse----------------------------3555Interface *ADLParser::mem_interface_parse(void) {3556// Fields for MemInterface3557char *base = NULL;3558char *index = NULL;3559char *scale = NULL;3560char *disp = NULL;35613562if (_curchar != '%') {3563parse_err(SYNERR, "Missing '%%{' for 'interface' block.\n");3564return NULL;3565}3566next_char(); // Skip '%'3567if (_curchar != '{') {3568parse_err(SYNERR, "Missing '%%{' for 'interface' block.\n");3569return NULL;3570}3571next_char(); // Skip '{'3572skipws();3573do {3574char *field = get_ident();3575if (field == NULL) {3576parse_err(SYNERR, "Expected keyword, base|index|scale|disp, or '%%}' ending interface.\n");3577return NULL;3578}3579if ( strcmp(field,"base") == 0 ) {3580base = interface_field_parse();3581}3582else if ( strcmp(field,"index") == 0 ) {3583index = interface_field_parse();3584}3585else if ( strcmp(field,"scale") == 0 ) {3586scale = interface_field_parse();3587}3588else if ( strcmp(field,"disp") == 0 ) {3589disp = interface_field_parse();3590}3591else {3592parse_err(SYNERR, "Expected keyword, base|index|scale|disp, or '%%}' ending interface.\n");3593return NULL;3594}3595} while( _curchar != '%' );3596next_char(); // Skip '%'3597if ( _curchar != '}' ) {3598parse_err(SYNERR, "Missing '%%}' for 'interface' block.\n");3599return NULL;3600}3601next_char(); // Skip '}'36023603// Construct desired object and return3604Interface *inter = new MemInterface(base, index, scale, disp);3605return inter;3606}360736083609//------------------------------cond_interface_parse---------------------------3610Interface *ADLParser::cond_interface_parse(void) {3611char *equal;3612char *not_equal;3613char *less;3614char *greater_equal;3615char *less_equal;3616char *greater;3617char *overflow;3618char *no_overflow;3619const char *equal_format = "eq";3620const char *not_equal_format = "ne";3621const char *less_format = "lt";3622const char *greater_equal_format = "ge";3623const char *less_equal_format = "le";3624const char *greater_format = "gt";3625const char *overflow_format = "o";3626const char *no_overflow_format = "no";36273628if (_curchar != '%') {3629parse_err(SYNERR, "Missing '%%{' for 'cond_interface' block.\n");3630return NULL;3631}3632next_char(); // Skip '%'3633if (_curchar != '{') {3634parse_err(SYNERR, "Missing '%%{' for 'cond_interface' block.\n");3635return NULL;3636}3637next_char(); // Skip '{'3638skipws();3639do {3640char *field = get_ident();3641if (field == NULL) {3642parse_err(SYNERR, "Expected keyword, base|index|scale|disp, or '%%}' ending interface.\n");3643return NULL;3644}3645if ( strcmp(field,"equal") == 0 ) {3646equal = interface_field_parse(&equal_format);3647}3648else if ( strcmp(field,"not_equal") == 0 ) {3649not_equal = interface_field_parse(¬_equal_format);3650}3651else if ( strcmp(field,"less") == 0 ) {3652less = interface_field_parse(&less_format);3653}3654else if ( strcmp(field,"greater_equal") == 0 ) {3655greater_equal = interface_field_parse(&greater_equal_format);3656}3657else if ( strcmp(field,"less_equal") == 0 ) {3658less_equal = interface_field_parse(&less_equal_format);3659}3660else if ( strcmp(field,"greater") == 0 ) {3661greater = interface_field_parse(&greater_format);3662}3663else if ( strcmp(field,"overflow") == 0 ) {3664overflow = interface_field_parse(&overflow_format);3665}3666else if ( strcmp(field,"no_overflow") == 0 ) {3667no_overflow = interface_field_parse(&no_overflow_format);3668}3669else {3670parse_err(SYNERR, "Expected keyword, base|index|scale|disp, or '%%}' ending interface.\n");3671return NULL;3672}3673} while( _curchar != '%' );3674next_char(); // Skip '%'3675if ( _curchar != '}' ) {3676parse_err(SYNERR, "Missing '%%}' for 'interface' block.\n");3677return NULL;3678}3679next_char(); // Skip '}'36803681// Construct desired object and return3682Interface *inter = new CondInterface(equal, equal_format,3683not_equal, not_equal_format,3684less, less_format,3685greater_equal, greater_equal_format,3686less_equal, less_equal_format,3687greater, greater_format,3688overflow, overflow_format,3689no_overflow, no_overflow_format);3690return inter;3691}369236933694//------------------------------interface_field_parse--------------------------3695char *ADLParser::interface_field_parse(const char ** format) {3696char *iface_field = NULL;36973698// Get interface field3699skipws(); // Skip whitespace3700if (_curchar != '(') {3701parse_err(SYNERR, "Missing '(' at start of interface field.\n");3702return NULL;3703}3704next_char(); // move past '('3705skipws();3706if ( _curchar != '0' && _curchar != '$' ) {3707parse_err(SYNERR, "missing or invalid interface field contents.\n");3708return NULL;3709}3710iface_field = get_rep_var_ident();3711if (iface_field == NULL) {3712parse_err(SYNERR, "missing or invalid interface field contents.\n");3713return NULL;3714}3715skipws();3716if (format != NULL && _curchar == ',') {3717next_char();3718skipws();3719if (_curchar != '"') {3720parse_err(SYNERR, "Missing '\"' in field format .\n");3721return NULL;3722}3723next_char();3724char *start = _ptr; // Record start of the next string3725while ((_curchar != '"') && (_curchar != '%') && (_curchar != '\n')) {3726if (_curchar == '\\') next_char(); // superquote3727if (_curchar == '\n') parse_err(SYNERR, "newline in string"); // unimplemented!3728next_char();3729}3730if (_curchar != '"') {3731parse_err(SYNERR, "Missing '\"' at end of field format .\n");3732return NULL;3733}3734// If a string was found, terminate it and record in FormatRule3735if ( start != _ptr ) {3736*_ptr = '\0'; // Terminate the string3737*format = start;3738}3739next_char();3740skipws();3741}3742if (_curchar != ')') {3743parse_err(SYNERR, "Missing ')' after interface field.\n");3744return NULL;3745}3746next_char(); // move past ')'3747skipws();3748if ( _curchar != ';' ) {3749parse_err(SYNERR, "Missing ';' at end of interface field.\n");3750return NULL;3751}3752next_char(); // move past ';'3753skipws(); // be friendly to interface_parse()37543755return iface_field;3756}375737583759//------------------------------match_parse------------------------------------3760MatchRule *ADLParser::match_parse(FormDict &operands) {3761MatchRule *match; // Match Rule class for instruction/operand3762char *cnstr = NULL; // Code for constructor3763int depth = 0; // Counter for matching parentheses3764int numleaves = 0; // Counter for number of leaves in rule37653766// Parse the match rule tree3767MatchNode *mnode = matchNode_parse(operands, depth, numleaves, true);37683769// Either there is a block with a constructor, or a ';' here3770skipws(); // Skip whitespace3771if ( _curchar == ';' ) { // Semicolon is valid terminator3772cnstr = NULL; // no constructor for this form3773next_char(); // Move past the ';', replaced with '\0'3774}3775else if ((cnstr = find_cpp_block("match constructor")) == NULL ) {3776parse_err(SYNERR, "invalid construction of match rule\n"3777"Missing ';' or invalid '%%{' and '%%}' constructor\n");3778return NULL; // No MatchRule to return3779}3780if (_AD._adl_debug > 1)3781if (cnstr) fprintf(stderr,"Match Constructor: %s\n", cnstr);3782// Build new MatchRule object3783match = new MatchRule(_AD, mnode, depth, cnstr, numleaves);3784skipws(); // Skip any trailing whitespace3785return match; // Return MatchRule object3786}37873788//------------------------------format_parse-----------------------------------3789FormatRule* ADLParser::format_parse(void) {3790char *desc = NULL;3791FormatRule *format = (new FormatRule(desc));37923793// Without expression form, MUST have a code block;3794skipws(); // Skip whitespace3795if ( _curchar == ';' ) { // Semicolon is valid terminator3796desc = NULL; // no constructor for this form3797next_char(); // Move past the ';', replaced with '\0'3798}3799else if ( _curchar == '%' && *(_ptr+1) == '{') {3800next_char(); // Move past the '%'3801next_char(); // Move past the '{'38023803skipws();3804if (_curchar == '$') {3805char* ident = get_rep_var_ident();3806if (strcmp(ident, "$$template") == 0) return template_parse();3807parse_err(SYNERR, "Unknown \"%s\" directive in format", ident);3808return NULL;3809}3810// Check for the opening '"' inside the format description3811if ( _curchar == '"' ) {3812next_char(); // Move past the initial '"'3813if( _curchar == '"' ) { // Handle empty format string case3814*_ptr = '\0'; // Terminate empty string3815format->_strings.addName(_ptr);3816}38173818// Collect the parts of the format description3819// (1) strings that are passed through to tty->print3820// (2) replacement/substitution variable, preceeded by a '$'3821// (3) multi-token ANSIY C style strings3822while ( true ) {3823if ( _curchar == '%' || _curchar == '\n' ) {3824if ( _curchar != '"' ) {3825parse_err(SYNERR, "missing '\"' at end of format block");3826return NULL;3827}3828}38293830// (1)3831// Check if there is a string to pass through to output3832char *start = _ptr; // Record start of the next string3833while ((_curchar != '$') && (_curchar != '"') && (_curchar != '%') && (_curchar != '\n')) {3834if (_curchar == '\\') {3835next_char(); // superquote3836if ((_curchar == '$') || (_curchar == '%'))3837// hack to avoid % escapes and warnings about undefined \ escapes3838*(_ptr-1) = _curchar;3839}3840if (_curchar == '\n') parse_err(SYNERR, "newline in string"); // unimplemented!3841next_char();3842}3843// If a string was found, terminate it and record in FormatRule3844if ( start != _ptr ) {3845*_ptr = '\0'; // Terminate the string3846format->_strings.addName(start);3847}38483849// (2)3850// If we are at a replacement variable,3851// copy it and record in FormatRule3852if ( _curchar == '$' ) {3853next_char(); // Move past the '$'3854char* rep_var = get_ident(); // Nil terminate the variable name3855rep_var = strdup(rep_var);// Copy the string3856*_ptr = _curchar; // and replace Nil with original character3857format->_rep_vars.addName(rep_var);3858// Add flag to _strings list indicating we should check _rep_vars3859format->_strings.addName(NameList::_signal);3860}38613862// (3)3863// Allow very long strings to be broken up,3864// using the ANSI C syntax "foo\n" <newline> "bar"3865if ( _curchar == '"') {3866next_char(); // Move past the '"'3867skipws(); // Skip white space before next string token3868if ( _curchar != '"') {3869break;3870} else {3871// Found one. Skip both " and the whitespace in between.3872next_char();3873}3874}3875} // end while part of format description38763877// Check for closing '"' and '%}' in format description3878skipws(); // Move to closing '%}'3879if ( _curchar != '%' ) {3880parse_err(SYNERR, "non-blank characters between closing '\"' and '%%' in format");3881return NULL;3882}3883} // Done with format description inside38843885skipws();3886// Past format description, at '%'3887if ( _curchar != '%' || *(_ptr+1) != '}' ) {3888parse_err(SYNERR, "missing '%%}' at end of format block");3889return NULL;3890}3891next_char(); // Move past the '%'3892next_char(); // Move past the '}'3893}3894else { // parameter list alone must terminate with a ';'3895parse_err(SYNERR, "missing ';' after Format expression");3896return NULL;3897}3898// Debug Stuff3899if (_AD._adl_debug > 1) fprintf(stderr,"Format Rule: %s\n", desc);39003901skipws();3902return format;3903}390439053906//------------------------------template_parse-----------------------------------3907FormatRule* ADLParser::template_parse(void) {3908char *desc = NULL;3909FormatRule *format = (new FormatRule(desc));39103911skipws();3912while ( (_curchar != '%') && (*(_ptr+1) != '}') ) {39133914// (1)3915// Check if there is a string to pass through to output3916{3917char *start = _ptr; // Record start of the next string3918while ((_curchar != '$') && ((_curchar != '%') || (*(_ptr+1) != '}')) ) {3919// If at the start of a comment, skip past it3920if( (_curchar == '/') && ((*(_ptr+1) == '/') || (*(_ptr+1) == '*')) ) {3921skipws_no_preproc();3922} else {3923// ELSE advance to the next character, or start of the next line3924next_char_or_line();3925}3926}3927// If a string was found, terminate it and record in EncClass3928if ( start != _ptr ) {3929*_ptr = '\0'; // Terminate the string3930// Add flag to _strings list indicating we should check _rep_vars3931format->_strings.addName(NameList::_signal2);3932format->_strings.addName(start);3933}3934}39353936// (2)3937// If we are at a replacement variable,3938// copy it and record in EncClass3939if ( _curchar == '$' ) {3940// Found replacement Variable3941char *rep_var = get_rep_var_ident_dup();3942if (strcmp(rep_var, "$emit") == 0) {3943// switch to normal format parsing3944next_char();3945next_char();3946skipws();3947// Check for the opening '"' inside the format description3948if ( _curchar == '"' ) {3949next_char(); // Move past the initial '"'3950if( _curchar == '"' ) { // Handle empty format string case3951*_ptr = '\0'; // Terminate empty string3952format->_strings.addName(_ptr);3953}39543955// Collect the parts of the format description3956// (1) strings that are passed through to tty->print3957// (2) replacement/substitution variable, preceeded by a '$'3958// (3) multi-token ANSIY C style strings3959while ( true ) {3960if ( _curchar == '%' || _curchar == '\n' ) {3961parse_err(SYNERR, "missing '\"' at end of format block");3962return NULL;3963}39643965// (1)3966// Check if there is a string to pass through to output3967char *start = _ptr; // Record start of the next string3968while ((_curchar != '$') && (_curchar != '"') && (_curchar != '%') && (_curchar != '\n')) {3969if (_curchar == '\\') next_char(); // superquote3970if (_curchar == '\n') parse_err(SYNERR, "newline in string"); // unimplemented!3971next_char();3972}3973// If a string was found, terminate it and record in FormatRule3974if ( start != _ptr ) {3975*_ptr = '\0'; // Terminate the string3976format->_strings.addName(start);3977}39783979// (2)3980// If we are at a replacement variable,3981// copy it and record in FormatRule3982if ( _curchar == '$' ) {3983next_char(); // Move past the '$'3984char* next_rep_var = get_ident(); // Nil terminate the variable name3985next_rep_var = strdup(next_rep_var);// Copy the string3986*_ptr = _curchar; // and replace Nil with original character3987format->_rep_vars.addName(next_rep_var);3988// Add flag to _strings list indicating we should check _rep_vars3989format->_strings.addName(NameList::_signal);3990}39913992// (3)3993// Allow very long strings to be broken up,3994// using the ANSI C syntax "foo\n" <newline> "bar"3995if ( _curchar == '"') {3996next_char(); // Move past the '"'3997skipws(); // Skip white space before next string token3998if ( _curchar != '"') {3999break;4000} else {4001// Found one. Skip both " and the whitespace in between.4002next_char();4003}4004}4005} // end while part of format description4006}4007} else {4008// Add flag to _strings list indicating we should check _rep_vars4009format->_rep_vars.addName(rep_var);4010// Add flag to _strings list indicating we should check _rep_vars4011format->_strings.addName(NameList::_signal3);4012}4013} // end while part of format description4014}40154016skipws();4017// Past format description, at '%'4018if ( _curchar != '%' || *(_ptr+1) != '}' ) {4019parse_err(SYNERR, "missing '%%}' at end of format block");4020return NULL;4021}4022next_char(); // Move past the '%'4023next_char(); // Move past the '}'40244025// Debug Stuff4026if (_AD._adl_debug > 1) fprintf(stderr,"Format Rule: %s\n", desc);40274028skipws();4029return format;4030}403140324033//------------------------------effect_parse-----------------------------------4034void ADLParser::effect_parse(InstructForm *instr) {4035char* desc = NULL;40364037skipws(); // Skip whitespace4038if (_curchar != '(') {4039parse_err(SYNERR, "missing '(' in effect definition\n");4040return;4041}4042// Get list of effect-operand pairs and insert into dictionary4043else get_effectlist(instr->_effects, instr->_localNames, instr->_has_call);40444045// Debug Stuff4046if (_AD._adl_debug > 1) fprintf(stderr,"Effect description: %s\n", desc);4047if (_curchar != ';') {4048parse_err(SYNERR, "missing ';' in Effect definition\n");4049}4050next_char(); // Skip ';'40514052}40534054//------------------------------expand_parse-----------------------------------4055ExpandRule* ADLParser::expand_parse(InstructForm *instr) {4056char *ident, *ident2;4057NameAndList *instr_and_operands = NULL;4058ExpandRule *exp = new ExpandRule();40594060// Expand is a block containing an ordered list of operands with initializers,4061// or instructions, each of which has an ordered list of operands.4062// Check for block delimiter4063skipws(); // Skip leading whitespace4064if ((_curchar != '%')4065|| (next_char(), (_curchar != '{')) ) { // If not open block4066parse_err(SYNERR, "missing '%%{' in expand definition\n");4067return(NULL);4068}4069next_char(); // Maintain the invariant4070do {4071ident = get_ident(); // Grab next identifier4072if (ident == NULL) {4073parse_err(SYNERR, "identifier expected at %c\n", _curchar);4074continue;4075}40764077// Check whether we should parse an instruction or operand.4078const Form *form = _globalNames[ident];4079bool parse_oper = false;4080bool parse_ins = false;4081if (form == NULL) {4082skipws();4083// Check whether this looks like an instruction specification. If so,4084// just parse the instruction. The declaration of the instruction is4085// not needed here.4086if (_curchar == '(') parse_ins = true;4087} else if (form->is_instruction()) {4088parse_ins = true;4089} else if (form->is_operand()) {4090parse_oper = true;4091} else {4092parse_err(SYNERR, "instruction/operand name expected at %s\n", ident);4093continue;4094}40954096if (parse_oper) {4097// This is a new operand4098OperandForm *oper = form->is_operand();4099if (oper == NULL) {4100parse_err(SYNERR, "instruction/operand name expected at %s\n", ident);4101continue;4102}4103// Throw the operand on the _newopers list4104skipws();4105ident = get_unique_ident(instr->_localNames,"Operand");4106if (ident == NULL) {4107parse_err(SYNERR, "identifier expected at %c\n", _curchar);4108continue;4109}4110exp->_newopers.addName(ident);4111// Add new operand to LocalNames4112instr->_localNames.Insert(ident, oper);4113// Grab any constructor code and save as a string4114char *c = NULL;4115skipws();4116if (_curchar == '%') { // Need a constructor for the operand4117c = find_cpp_block("Operand Constructor");4118if (c == NULL) {4119parse_err(SYNERR, "Invalid code block for operand constructor\n", _curchar);4120continue;4121}4122// Add constructor to _newopconst Dict4123exp->_newopconst.Insert(ident, c);4124}4125else if (_curchar != ';') { // If no constructor, need a ;4126parse_err(SYNERR, "Missing ; in expand rule operand declaration\n");4127continue;4128}4129else next_char(); // Skip the ;4130skipws();4131}4132else {4133assert(parse_ins, "sanity");4134// Add instruction to list4135instr_and_operands = new NameAndList(ident);4136// Grab operands, build nameList of them, and then put into dictionary4137skipws();4138if (_curchar != '(') { // Check for parenthesized operand list4139parse_err(SYNERR, "missing '(' in expand instruction declaration\n");4140continue;4141}4142do {4143next_char(); // skip open paren & comma characters4144skipws();4145if (_curchar == ')') break;4146ident2 = get_ident();4147skipws();4148if (ident2 == NULL) {4149parse_err(SYNERR, "identifier expected at %c\n", _curchar);4150continue;4151} // Check that you have a valid operand4152const Form *form2 = instr->_localNames[ident2];4153if (!form2) {4154parse_err(SYNERR, "operand name expected at %s\n", ident2);4155continue;4156}4157OperandForm *oper = form2->is_operand();4158if (oper == NULL && !form2->is_opclass()) {4159parse_err(SYNERR, "operand name expected at %s\n", ident2);4160continue;4161} // Add operand to list4162instr_and_operands->add_entry(ident2);4163} while(_curchar == ',');4164if (_curchar != ')') {4165parse_err(SYNERR, "missing ')'in expand instruction declaration\n");4166continue;4167}4168next_char();4169if (_curchar != ';') {4170parse_err(SYNERR, "missing ';'in expand instruction declaration\n");4171continue;4172}4173next_char();41744175// Record both instruction name and its operand list4176exp->add_instruction(instr_and_operands);41774178skipws();4179}41804181} while(_curchar != '%');4182next_char();4183if (_curchar != '}') {4184parse_err(SYNERR, "missing '%%}' in expand rule definition\n");4185return(NULL);4186}4187next_char();41884189// Debug Stuff4190if (_AD._adl_debug > 1) fprintf(stderr,"Expand Rule:\n");41914192skipws();4193return (exp);4194}41954196//------------------------------rewrite_parse----------------------------------4197RewriteRule* ADLParser::rewrite_parse(void) {4198char* params = NULL;4199char* desc = NULL;420042014202// This feature targeted for second generation description language.42034204skipws(); // Skip whitespace4205// Get parameters for rewrite4206if ((params = get_paren_expr("rewrite parameters")) == NULL) {4207parse_err(SYNERR, "missing '(' in rewrite rule\n");4208return NULL;4209}4210// Debug Stuff4211if (_AD._adl_debug > 1) fprintf(stderr,"Rewrite parameters: %s\n", params);42124213// For now, grab entire block;4214skipws();4215if ( (desc = find_cpp_block("rewrite block")) == NULL ) {4216parse_err(SYNERR, "incorrect or missing block for 'rewrite'.\n");4217return NULL;4218}4219// Debug Stuff4220if (_AD._adl_debug > 1) fprintf(stderr,"Rewrite Rule: %s\n", desc);42214222skipws();4223return (new RewriteRule(params,desc));4224}42254226//------------------------------attr_parse-------------------------------------4227Attribute *ADLParser::attr_parse(char* ident) {4228Attribute *attrib; // Attribute class4229char *cost = NULL; // String representation of cost attribute42304231skipws(); // Skip leading whitespace4232if ( (cost = get_paren_expr("attribute")) == NULL ) {4233parse_err(SYNERR, "incorrect or missing expression for 'attribute'\n");4234return NULL;4235}4236// Debug Stuff4237if (_AD._adl_debug > 1) fprintf(stderr,"Attribute: %s\n", cost);4238if (_curchar != ';') {4239parse_err(SYNERR, "missing ';' in attribute definition\n");4240return NULL;4241}4242next_char(); // Point after the terminator42434244skipws();4245attrib = new Attribute(ident,cost,INS_ATTR); // Build new predicate object4246return attrib;4247}424842494250//------------------------------matchNode_parse--------------------------------4251MatchNode *ADLParser::matchNode_parse(FormDict &operands, int &depth, int &numleaves, bool atroot) {4252// Count depth of parenthesis nesting for both left and right children4253int lParens = depth;4254int rParens = depth;42554256// MatchNode objects for left, right, and root of subtree.4257MatchNode *lChild = NULL;4258MatchNode *rChild = NULL;4259char *token; // Identifier which may be opcode or operand42604261// Match expression starts with a '('4262if (cur_char() != '(')4263return NULL;42644265next_char(); // advance past '('42664267// Parse the opcode4268token = get_ident(); // Get identifier, opcode4269if (token == NULL) {4270parse_err(SYNERR, "missing opcode in match expression\n");4271return NULL;4272}42734274// Take note if we see one of a few special operations - those that are4275// treated differently on different architectures in the sense that on4276// one architecture there is a match rule and on another there isn't (so4277// a call will eventually be generated).42784279for (int i = _last_machine_leaf + 1; i < _last_opcode; i++) {4280if (strcmp(token, NodeClassNames[i]) == 0) {4281_AD.has_match_rule(i, true);4282}4283}42844285// Lookup the root value in the operands dict to perform substitution4286const char *result = NULL; // Result type will be filled in later4287const char *name = token; // local name associated with this node4288const char *operation = token; // remember valid operation for later4289const Form *form = operands[token];4290OpClassForm *opcForm = form ? form->is_opclass() : NULL;4291if (opcForm != NULL) {4292// If this token is an entry in the local names table, record its type4293if (!opcForm->ideal_only()) {4294operation = opcForm->_ident;4295result = operation; // Operands result in their own type4296}4297// Otherwise it is an ideal type, and so, has no local name4298else name = NULL;4299}43004301// Parse the operands4302skipws();4303if (cur_char() != ')') {43044305// Parse the left child4306if (strcmp(operation,"Set"))4307lChild = matchChild_parse(operands, lParens, numleaves, false);4308else4309lChild = matchChild_parse(operands, lParens, numleaves, true);43104311skipws();4312if (cur_char() != ')' ) {4313if(strcmp(operation, "Set"))4314rChild = matchChild_parse(operands,rParens,numleaves,false);4315else4316rChild = matchChild_parse(operands,rParens,numleaves,true);4317}4318}43194320// Check for required ')'4321skipws();4322if (cur_char() != ')') {4323parse_err(SYNERR, "missing ')' in match expression\n");4324return NULL;4325}4326next_char(); // skip the ')'43274328MatchNode* mroot = new MatchNode(_AD,result,name,operation,lChild,rChild);43294330// If not the root, reduce this subtree to an internal operand4331if (!atroot) {4332mroot->build_internalop();4333}4334// depth is greater of left and right paths.4335depth = (lParens > rParens) ? lParens : rParens;43364337return mroot;4338}433943404341//------------------------------matchChild_parse-------------------------------4342MatchNode *ADLParser::matchChild_parse(FormDict &operands, int &parens, int &numleaves, bool atroot) {4343MatchNode *child = NULL;4344const char *result = NULL;4345const char *token = NULL;4346const char *opType = NULL;43474348if (cur_char() == '(') { // child is an operation4349++parens;4350child = matchNode_parse(operands, parens, numleaves, atroot);4351}4352else { // child is an operand4353token = get_ident();4354const Form *form = operands[token];4355OpClassForm *opcForm = form ? form->is_opclass() : NULL;4356if (opcForm != NULL) {4357opType = opcForm->_ident;4358result = opcForm->_ident; // an operand's result matches its type4359} else {4360parse_err(SYNERR, "undefined operand %s in match rule\n", token);4361return NULL;4362}43634364if (opType == NULL) {4365parse_err(SYNERR, "missing type for argument '%s'\n", token);4366}43674368child = new MatchNode(_AD, result, token, opType);4369++numleaves;4370}43714372return child;4373}4374437543764377// ******************** Private Utility Functions *************************437843794380char* ADLParser::find_cpp_block(const char* description) {4381char *next; // Pointer for finding block delimiters4382char* cppBlock = NULL; // Beginning of C++ code block43834384if (_curchar == '%') { // Encoding is a C++ expression4385next_char();4386if (_curchar != '{') {4387parse_err(SYNERR, "missing '{' in %s \n", description);4388return NULL;4389}4390next_char(); // Skip block delimiter4391skipws_no_preproc(); // Skip leading whitespace4392cppBlock = _ptr; // Point to start of expression4393int line = linenum();4394next = _ptr + 1;4395while(((_curchar != '%') || (*next != '}')) && (_curchar != '\0')) {4396next_char_or_line();4397next = _ptr+1; // Maintain the next pointer4398} // Grab string4399if (_curchar == '\0') {4400parse_err(SYNERR, "invalid termination of %s \n", description);4401return NULL;4402}4403*_ptr = '\0'; // Terminate string4404_ptr += 2; // Skip block delimiter4405_curchar = *_ptr; // Maintain invariant44064407// Prepend location descriptor, for debugging.4408if (_AD._adlocation_debug) {4409char* location = get_line_string(line);4410char* end_loc = end_line_marker();4411char* result = (char *)AllocateHeap(strlen(location) + strlen(cppBlock) + strlen(end_loc) + 1);4412strcpy(result, location);4413strcat(result, cppBlock);4414strcat(result, end_loc);4415cppBlock = result;4416free(location);4417}4418}44194420return cppBlock;4421}44224423// Move to the closing token of the expression we are currently at,4424// as defined by stop_chars. Match parens and quotes.4425char* ADLParser::get_expr(const char *desc, const char *stop_chars) {4426char* expr = NULL;4427int paren = 0;44284429expr = _ptr;4430while (paren > 0 || !strchr(stop_chars, _curchar)) {4431if (_curchar == '(') { // Down level of nesting4432paren++; // Bump the parenthesis counter4433next_char(); // maintain the invariant4434}4435else if (_curchar == ')') { // Up one level of nesting4436if (paren == 0) {4437// Paren underflow: We didn't encounter the required stop-char.4438parse_err(SYNERR, "too many )'s, did not find %s after %s\n",4439stop_chars, desc);4440return NULL;4441}4442paren--; // Drop the parenthesis counter4443next_char(); // Maintain the invariant4444}4445else if (_curchar == '"' || _curchar == '\'') {4446int qchar = _curchar;4447while (true) {4448next_char();4449if (_curchar == qchar) { next_char(); break; }4450if (_curchar == '\\') next_char(); // superquote4451if (_curchar == '\n' || _curchar == '\0') {4452parse_err(SYNERR, "newline in string in %s\n", desc);4453return NULL;4454}4455}4456}4457else if (_curchar == '%' && (_ptr[1] == '{' || _ptr[1] == '}')) {4458// Make sure we do not stray into the next ADLC-level form.4459parse_err(SYNERR, "unexpected %%%c in %s\n", _ptr[1], desc);4460return NULL;4461}4462else if (_curchar == '\0') {4463parse_err(SYNERR, "unexpected EOF in %s\n", desc);4464return NULL;4465}4466else {4467// Always walk over whitespace, comments, preprocessor directives, etc.4468char* pre_skip_ptr = _ptr;4469skipws();4470// If the parser declined to make progress on whitespace,4471// skip the next character, which is therefore NOT whitespace.4472if (pre_skip_ptr == _ptr) {4473next_char();4474} else if (pre_skip_ptr+strlen(pre_skip_ptr) != _ptr+strlen(_ptr)) {4475parse_err(SYNERR, "unimplemented: preprocessor must not elide subexpression in %s", desc);4476}4477}4478}44794480assert(strchr(stop_chars, _curchar), "non-null return must be at stop-char");4481*_ptr = '\0'; // Replace ')' or other stop-char with '\0'4482return expr;4483}44844485// Helper function around get_expr4486// Sets _curchar to '(' so that get_paren_expr will search for a matching ')'4487char *ADLParser::get_paren_expr(const char *description, bool include_location) {4488int line = linenum();4489if (_curchar != '(') // Escape if not valid starting position4490return NULL;4491next_char(); // Skip the required initial paren.4492char *token2 = get_expr(description, ")");4493if (_curchar == ')')4494next_char(); // Skip required final paren.4495int junk = 0;4496if (include_location && _AD._adlocation_debug && !is_int_token(token2, junk)) {4497// Prepend location descriptor, for debugging.4498char* location = get_line_string(line);4499char* end_loc = end_line_marker();4500char* result = (char *)AllocateHeap(strlen(location) + strlen(token2) + strlen(end_loc) + 1);4501strcpy(result, location);4502strcat(result, token2);4503strcat(result, end_loc);4504token2 = result;4505free(location);4506}4507return token2;4508}45094510//------------------------------get_ident_common-------------------------------4511// Looks for an identifier in the buffer, and turns it into a null terminated4512// string(still inside the file buffer). Returns a pointer to the string or4513// NULL if some other token is found instead.4514char *ADLParser::get_ident_common(bool do_preproc) {4515char c;4516char *start; // Pointer to start of token4517char *end; // Pointer to end of token45184519if( _curline == NULL ) // Return NULL at EOF.4520return NULL;45214522skipws_common(do_preproc); // Skip whitespace before identifier4523start = end = _ptr; // Start points at first character4524end--; // unwind end by one to prepare for loop4525do {4526end++; // Increment end pointer4527c = *end; // Grab character to test4528} while ( ((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z'))4529|| ((c >= '0') && (c <= '9'))4530|| ((c == '_')) || ((c == ':')) || ((c == '#')) );4531if (start == end) { // We popped out on the first try4532// It can occur that `start' contains the rest of the input file.4533// In this case the output should be truncated.4534if (strlen(start) > 24) {4535char buf[32];4536strncpy(buf, start, 20);4537buf[20] = '\0';4538strcat(buf, "[...]");4539parse_err(SYNERR, "Identifier expected, but found '%s'.", buf);4540} else {4541parse_err(SYNERR, "Identifier expected, but found '%s'.", start);4542}4543start = NULL;4544}4545else {4546_curchar = c; // Save the first character of next token4547*end = '\0'; // NULL terminate the string in place4548}4549_ptr = end; // Reset _ptr to point to next char after token45504551// Make sure we do not try to use #defined identifiers. If start is4552// NULL an error was already reported.4553if (do_preproc && start != NULL) {4554const char* def = _AD.get_preproc_def(start);4555if (def != NULL && strcmp(def, start)) {4556const char* def1 = def;4557const char* def2 = _AD.get_preproc_def(def1);4558// implement up to 2 levels of #define4559if (def2 != NULL && strcmp(def2, def1)) {4560def = def2;4561const char* def3 = _AD.get_preproc_def(def2);4562if (def3 != NULL && strcmp(def3, def2) && strcmp(def3, def1)) {4563parse_err(SYNERR, "unimplemented: using %s defined as %s => %s => %s",4564start, def1, def2, def3);4565}4566}4567start = strdup(def);4568}4569}45704571return start; // Pointer to token in filebuf4572}45734574//------------------------------get_ident_dup----------------------------------4575// Looks for an identifier in the buffer, and returns a duplicate4576// or NULL if some other token is found instead.4577char *ADLParser::get_ident_dup(void) {4578char *ident = get_ident();45794580// Duplicate an identifier before returning and restore string.4581if( ident != NULL ) {4582ident = strdup(ident); // Copy the string4583*_ptr = _curchar; // and replace Nil with original character4584}45854586return ident;4587}45884589//----------------------get_ident_or_literal_constant--------------------------4590// Looks for an identifier in the buffer, or a parenthesized expression.4591char *ADLParser::get_ident_or_literal_constant(const char* description) {4592char* param = NULL;4593skipws();4594if (_curchar == '(') {4595// Grab a constant expression.4596param = get_paren_expr(description);4597if (param[0] != '(') {4598char* buf = (char*) AllocateHeap(strlen(param) + 3);4599sprintf(buf, "(%s)", param);4600param = buf;4601}4602assert(is_literal_constant(param),4603"expr must be recognizable as a constant");4604} else {4605param = get_ident();4606}4607return param;4608}46094610//------------------------------get_rep_var_ident-----------------------------4611// Do NOT duplicate,4612// Leave nil terminator in buffer4613// Preserve initial '$'(s) in string4614char *ADLParser::get_rep_var_ident(void) {4615// Remember starting point4616char *rep_var = _ptr;46174618// Check for replacement variable indicator '$' and pass if present4619if ( _curchar == '$' ) {4620next_char();4621}4622// Check for a subfield indicator, a second '$', and pass if present4623if ( _curchar == '$' ) {4624next_char();4625}46264627// Check for a control indicator, a third '$':4628if ( _curchar == '$' ) {4629next_char();4630}46314632// Check for more than three '$'s in sequence, SYNERR4633if( _curchar == '$' ) {4634parse_err(SYNERR, "Replacement variables and field specifiers can not start with '$$$$'");4635next_char();4636return NULL;4637}46384639// Nil terminate the variable name following the '$'4640char *rep_var_name = get_ident();4641assert( rep_var_name != NULL,4642"Missing identifier after replacement variable indicator '$'");46434644return rep_var;4645}4646464746484649//------------------------------get_rep_var_ident_dup-------------------------4650// Return the next replacement variable identifier, skipping first '$'4651// given a pointer into a line of the buffer.4652// Null terminates string, still inside the file buffer,4653// Returns a pointer to a copy of the string, or NULL on failure4654char *ADLParser::get_rep_var_ident_dup(void) {4655if( _curchar != '$' ) return NULL;46564657next_char(); // Move past the '$'4658char *rep_var = _ptr; // Remember starting point46594660// Check for a subfield indicator, a second '$':4661if ( _curchar == '$' ) {4662next_char();4663}46644665// Check for a control indicator, a third '$':4666if ( _curchar == '$' ) {4667next_char();4668}46694670// Check for more than three '$'s in sequence, SYNERR4671if( _curchar == '$' ) {4672parse_err(SYNERR, "Replacement variables and field specifiers can not start with '$$$$'");4673next_char();4674return NULL;4675}46764677// Nil terminate the variable name following the '$'4678char *rep_var_name = get_ident();4679assert( rep_var_name != NULL,4680"Missing identifier after replacement variable indicator '$'");4681rep_var = strdup(rep_var); // Copy the string4682*_ptr = _curchar; // and replace Nil with original character46834684return rep_var;4685}468646874688//------------------------------get_unique_ident------------------------------4689// Looks for an identifier in the buffer, terminates it with a NULL,4690// and checks that it is unique4691char *ADLParser::get_unique_ident(FormDict& dict, const char* nameDescription){4692char* ident = get_ident();46934694if (ident == NULL) {4695parse_err(SYNERR, "missing %s identifier at %c\n", nameDescription, _curchar);4696}4697else {4698if (dict[ident] != NULL) {4699parse_err(SYNERR, "duplicate name %s for %s\n", ident, nameDescription);4700ident = NULL;4701}4702}47034704return ident;4705}470647074708//------------------------------get_int----------------------------------------4709// Looks for a character string integer in the buffer, and turns it into an int4710// invokes a parse_err if the next token is not an integer.4711// This routine does not leave the integer null-terminated.4712int ADLParser::get_int(void) {4713char c;4714char *start; // Pointer to start of token4715char *end; // Pointer to end of token4716int result; // Storage for integer result47174718if( _curline == NULL ) // Return NULL at EOF.4719return 0;47204721skipws(); // Skip whitespace before identifier4722start = end = _ptr; // Start points at first character4723c = *end; // Grab character to test4724while ((c >= '0' && c <= '9') || (c == '-' && end == start)) {4725end++; // Increment end pointer4726c = *end; // Grab character to test4727}4728if (start == end) { // We popped out on the first try4729parse_err(SYNERR, "integer expected at %c\n", c);4730result = 0;4731}4732else {4733_curchar = c; // Save the first character of next token4734*end = '\0'; // NULL terminate the string in place4735result = atoi(start); // Convert the string to an integer4736*end = _curchar; // Restore buffer to original condition4737}47384739// Reset _ptr to next char after token4740_ptr = end;47414742return result; // integer4743}474447454746//------------------------------get_relation_dup------------------------------4747// Looks for a relational operator in the buffer4748// invokes a parse_err if the next token is not a relation4749// This routine creates a duplicate of the string in the buffer.4750char *ADLParser::get_relation_dup(void) {4751char *result = NULL; // relational operator being returned47524753if( _curline == NULL ) // Return NULL at EOF.4754return NULL;47554756skipws(); // Skip whitespace before relation4757char *start = _ptr; // Store start of relational operator4758char first = *_ptr; // the first character4759if( (first == '=') || (first == '!') || (first == '<') || (first == '>') ) {4760next_char();4761char second = *_ptr; // the second character4762if( second == '=' ) {4763next_char();4764char tmp = *_ptr;4765*_ptr = '\0'; // NULL terminate4766result = strdup(start); // Duplicate the string4767*_ptr = tmp; // restore buffer4768} else {4769parse_err(SYNERR, "relational operator expected at %s\n", _ptr);4770}4771} else {4772parse_err(SYNERR, "relational operator expected at %s\n", _ptr);4773}47744775return result;4776}4777477847794780//------------------------------get_oplist-------------------------------------4781// Looks for identifier pairs where first must be the name of an operand, and4782// second must be a name unique in the scope of this instruction. Stores the4783// names with a pointer to the OpClassForm of their type in a local name table.4784void ADLParser::get_oplist(NameList ¶meters, FormDict &operands) {4785OpClassForm *opclass = NULL;4786char *ident = NULL;47874788do {4789next_char(); // skip open paren & comma characters4790skipws();4791if (_curchar == ')') break;47924793// Get operand type, and check it against global name table4794ident = get_ident();4795if (ident == NULL) {4796parse_err(SYNERR, "optype identifier expected at %c\n", _curchar);4797return;4798}4799else {4800const Form *form = _globalNames[ident];4801if( form == NULL ) {4802parse_err(SYNERR, "undefined operand type %s\n", ident);4803return;4804}48054806// Check for valid operand type4807OpClassForm *opc = form->is_opclass();4808OperandForm *oper = form->is_operand();4809if((oper == NULL) && (opc == NULL)) {4810parse_err(SYNERR, "identifier %s not operand type\n", ident);4811return;4812}4813opclass = opc;4814}4815// Debugging Stuff4816if (_AD._adl_debug > 1) fprintf(stderr, "\tOperand Type: %s\t", ident);48174818// Get name of operand and add it to local name table4819if( (ident = get_unique_ident(operands, "operand")) == NULL) {4820return;4821}4822// Parameter names must not be global names.4823if( _globalNames[ident] != NULL ) {4824parse_err(SYNERR, "Reuse of global name %s as operand.\n",ident);4825return;4826}4827operands.Insert(ident, opclass);4828parameters.addName(ident);48294830// Debugging Stuff4831if (_AD._adl_debug > 1) fprintf(stderr, "\tOperand Name: %s\n", ident);4832skipws();4833} while(_curchar == ',');48344835if (_curchar != ')') parse_err(SYNERR, "missing ')'\n");4836else {4837next_char(); // set current character position past the close paren4838}4839}484048414842//------------------------------get_effectlist---------------------------------4843// Looks for identifier pairs where first must be the name of a pre-defined,4844// effect, and the second must be the name of an operand defined in the4845// operand list of this instruction. Stores the names with a pointer to the4846// effect form in a local effects table.4847void ADLParser::get_effectlist(FormDict &effects, FormDict &operands, bool& has_call) {4848OperandForm *opForm;4849Effect *eForm;4850char *ident;48514852do {4853next_char(); // skip open paren & comma characters4854skipws();4855if (_curchar == ')') break;48564857// Get effect type, and check it against global name table4858ident = get_ident();4859if (ident == NULL) {4860parse_err(SYNERR, "effect type identifier expected at %c\n", _curchar);4861return;4862}4863else {4864// Check for valid effect type4865const Form *form = _globalNames[ident];4866if( form == NULL ) {4867parse_err(SYNERR, "undefined effect type %s\n", ident);4868return;4869}4870else {4871if( (eForm = form->is_effect()) == NULL) {4872parse_err(SYNERR, "identifier %s not effect type\n", ident);4873return;4874}4875}4876}4877// Debugging Stuff4878if (_AD._adl_debug > 1) fprintf(stderr, "\tEffect Type: %s\t", ident);4879skipws();4880if (eForm->is(Component::CALL)) {4881if (_AD._adl_debug > 1) fprintf(stderr, "\n");4882has_call = true;4883} else {4884// Get name of operand and check that it is in the local name table4885if( (ident = get_unique_ident(effects, "effect")) == NULL) {4886parse_err(SYNERR, "missing operand identifier in effect list\n");4887return;4888}4889const Form *form = operands[ident];4890opForm = form ? form->is_operand() : NULL;4891if( opForm == NULL ) {4892if( form && form->is_opclass() ) {4893const char* cname = form->is_opclass()->_ident;4894parse_err(SYNERR, "operand classes are illegal in effect lists (found %s %s)\n", cname, ident);4895} else {4896parse_err(SYNERR, "undefined operand %s in effect list\n", ident);4897}4898return;4899}4900// Add the pair to the effects table4901effects.Insert(ident, eForm);4902// Debugging Stuff4903if (_AD._adl_debug > 1) fprintf(stderr, "\tOperand Name: %s\n", ident);4904}4905skipws();4906} while(_curchar == ',');49074908if (_curchar != ')') parse_err(SYNERR, "missing ')'\n");4909else {4910next_char(); // set current character position past the close paren4911}4912}491349144915//-------------------------------preproc_line----------------------------------4916// A "#line" keyword has been seen, so parse the rest of the line.4917void ADLParser::preproc_line(void) {4918int line = get_int();4919skipws_no_preproc();4920const char* file = NULL;4921if (_curchar == '"') {4922next_char(); // Move past the initial '"'4923file = _ptr;4924while (true) {4925if (_curchar == '\n') {4926parse_err(SYNERR, "missing '\"' at end of #line directive");4927return;4928}4929if (_curchar == '"') {4930*_ptr = '\0'; // Terminate the string4931next_char();4932skipws_no_preproc();4933break;4934}4935next_char();4936}4937}4938ensure_end_of_line();4939if (file != NULL)4940_AD._ADL_file._name = file;4941_buf.set_linenum(line);4942}49434944//------------------------------preproc_define---------------------------------4945// A "#define" keyword has been seen, so parse the rest of the line.4946void ADLParser::preproc_define(void) {4947char* flag = get_ident_no_preproc();4948skipws_no_preproc();4949// only #define x y is supported for now4950char* def = get_ident_no_preproc();4951_AD.set_preproc_def(flag, def);4952skipws_no_preproc();4953if (_curchar != '\n') {4954parse_err(SYNERR, "non-identifier in preprocessor definition\n");4955}4956}49574958//------------------------------preproc_undef----------------------------------4959// An "#undef" keyword has been seen, so parse the rest of the line.4960void ADLParser::preproc_undef(void) {4961char* flag = get_ident_no_preproc();4962skipws_no_preproc();4963ensure_end_of_line();4964_AD.set_preproc_def(flag, NULL);4965}4966496749684969//------------------------------parse_err--------------------------------------4970// Issue a parser error message, and skip to the end of the current line4971void ADLParser::parse_err(int flag, const char *fmt, ...) {4972va_list args;49734974va_start(args, fmt);4975if (flag == 1)4976_AD._syntax_errs += _AD.emit_msg(0, flag, linenum(), fmt, args);4977else if (flag == 2)4978_AD._semantic_errs += _AD.emit_msg(0, flag, linenum(), fmt, args);4979else4980_AD._warnings += _AD.emit_msg(0, flag, linenum(), fmt, args);49814982int error_char = _curchar;4983char* error_ptr = _ptr+1;4984for(;*_ptr != '\n'; _ptr++) ; // Skip to the end of the current line4985_curchar = '\n';4986va_end(args);4987_AD._no_output = 1;49884989if (flag == 1) {4990char* error_tail = strchr(error_ptr, '\n');4991char tem = *error_ptr;4992error_ptr[-1] = '\0';4993char* error_head = error_ptr-1;4994while (error_head > _curline && *error_head) --error_head;4995if (error_tail) *error_tail = '\0';4996fprintf(stderr, "Error Context: %s>>>%c<<<%s\n",4997error_head, error_char, error_ptr);4998if (error_tail) *error_tail = '\n';4999error_ptr[-1] = tem;5000}5001}50025003//---------------------------ensure_start_of_line------------------------------5004// A preprocessor directive has been encountered. Be sure it has fallen at5005// the beginning of a line, or else report an error.5006void ADLParser::ensure_start_of_line(void) {5007if (_curchar == '\n') { next_line(); return; }5008assert( _ptr >= _curline && _ptr < _curline+strlen(_curline),5009"Must be able to find which line we are in" );50105011for (char *s = _curline; s < _ptr; s++) {5012if (*s > ' ') {5013parse_err(SYNERR, "'%c' must be at beginning of line\n", _curchar);5014break;5015}5016}5017}50185019//---------------------------ensure_end_of_line--------------------------------5020// A preprocessor directive has been parsed. Be sure there is no trailing5021// garbage at the end of this line. Set the scan point to the beginning of5022// the next line.5023void ADLParser::ensure_end_of_line(void) {5024skipws_no_preproc();5025if (_curchar != '\n' && _curchar != '\0') {5026parse_err(SYNERR, "garbage char '%c' at end of line\n", _curchar);5027} else {5028next_char_or_line();5029}5030}50315032//---------------------------handle_preproc------------------------------------5033// The '#' character introducing a preprocessor directive has been found.5034// Parse the whole directive name (e.g., #define, #endif) and take appropriate5035// action. If we are in an "untaken" span of text, simply keep track of5036// #ifdef nesting structure, so we can find out when to start taking text5037// again. (In this state, we "sort of support" C's #if directives, enough5038// to disregard their associated #else and #endif lines.) If we are in a5039// "taken" span of text, there are two cases: "#define" and "#undef"5040// directives are preserved and passed up to the caller, which eventually5041// passes control to the top-level parser loop, which handles #define and5042// #undef directly. (This prevents these directives from occurring in5043// arbitrary positions in the AD file--we require better structure than C.)5044// In the other case, and #ifdef, #ifndef, #else, or #endif is silently5045// processed as whitespace, with the "taken" state of the text correctly5046// updated. This routine returns "false" exactly in the case of a "taken"5047// #define or #undef, which tells the caller that a preprocessor token5048// has appeared which must be handled explicitly by the parse loop.5049bool ADLParser::handle_preproc_token() {5050assert(*_ptr == '#', "must be at start of preproc");5051ensure_start_of_line();5052next_char();5053skipws_no_preproc();5054char* start_ident = _ptr;5055char* ident = (_curchar == '\n') ? NULL : get_ident_no_preproc();5056if (ident == NULL) {5057parse_err(SYNERR, "expected preprocessor command, got end of line\n");5058} else if (!strcmp(ident, "ifdef") ||5059!strcmp(ident, "ifndef")) {5060char* flag = get_ident_no_preproc();5061ensure_end_of_line();5062// Test the identifier only if we are already in taken code:5063bool flag_def = preproc_taken() && (_AD.get_preproc_def(flag) != NULL);5064bool now_taken = !strcmp(ident, "ifdef") ? flag_def : !flag_def;5065begin_if_def(now_taken);5066} else if (!strcmp(ident, "if")) {5067if (preproc_taken())5068parse_err(SYNERR, "unimplemented: #%s %s", ident, _ptr+1);5069next_line();5070// Intelligently skip this nested C preprocessor directive:5071begin_if_def(true);5072} else if (!strcmp(ident, "else")) {5073ensure_end_of_line();5074invert_if_def();5075} else if (!strcmp(ident, "endif")) {5076ensure_end_of_line();5077end_if_def();5078} else if (preproc_taken()) {5079// pass this token up to the main parser as "#define" or "#undef"5080_ptr = start_ident;5081_curchar = *--_ptr;5082if( _curchar != '#' ) {5083parse_err(SYNERR, "no space allowed after # in #define or #undef");5084assert(_curchar == '#', "no space allowed after # in #define or #undef");5085}5086return false;5087}5088return true;5089}50905091//---------------------------skipws_common-------------------------------------5092// Skip whitespace, including comments and newlines, while keeping an accurate5093// line count.5094// Maybe handle certain preprocessor constructs: #ifdef, #ifndef, #else, #endif5095void ADLParser::skipws_common(bool do_preproc) {5096char *start = _ptr;5097char *next = _ptr + 1;50985099if (*_ptr == '\0') {5100// Check for string terminator5101if (_curchar > ' ') return;5102if (_curchar == '\n') {5103if (!do_preproc) return; // let caller handle the newline5104next_line();5105_ptr = _curline; next = _ptr + 1;5106}5107else if (_curchar == '#' ||5108(_curchar == '/' && (*next == '/' || *next == '*'))) {5109parse_err(SYNERR, "unimplemented: comment token in a funny place");5110}5111}5112while(_curline != NULL) { // Check for end of file5113if (*_ptr == '\n') { // keep proper track of new lines5114if (!do_preproc) break; // let caller handle the newline5115next_line();5116_ptr = _curline; next = _ptr + 1;5117}5118else if ((*_ptr == '/') && (*next == '/')) // C++ comment5119do { _ptr++; next++; } while(*_ptr != '\n'); // So go to end of line5120else if ((*_ptr == '/') && (*next == '*')) { // C comment5121_ptr++; next++;5122do {5123_ptr++; next++;5124if (*_ptr == '\n') { // keep proper track of new lines5125next_line(); // skip newlines within comments5126if (_curline == NULL) { // check for end of file5127parse_err(SYNERR, "end-of-file detected inside comment\n");5128break;5129}5130_ptr = _curline; next = _ptr + 1;5131}5132} while(!((*_ptr == '*') && (*next == '/'))); // Go to end of comment5133_ptr = ++next; next++; // increment _ptr past comment end5134}5135else if (do_preproc && *_ptr == '#') {5136// Note that this calls skipws_common(false) recursively!5137bool preproc_handled = handle_preproc_token();5138if (!preproc_handled) {5139if (preproc_taken()) {5140return; // short circuit5141}5142++_ptr; // skip the preprocessor character5143}5144next = _ptr+1;5145} else if(*_ptr > ' ' && !(do_preproc && !preproc_taken())) {5146break;5147}5148else if (*_ptr == '"' || *_ptr == '\'') {5149assert(do_preproc, "only skip strings if doing preproc");5150// skip untaken quoted string5151int qchar = *_ptr;5152while (true) {5153++_ptr;5154if (*_ptr == qchar) { ++_ptr; break; }5155if (*_ptr == '\\') ++_ptr;5156if (*_ptr == '\n' || *_ptr == '\0') {5157parse_err(SYNERR, "newline in string");5158break;5159}5160}5161next = _ptr + 1;5162}5163else { ++_ptr; ++next; }5164}5165if( _curline != NULL ) // at end of file _curchar isn't valid5166_curchar = *_ptr; // reset _curchar to maintain invariant5167}51685169//---------------------------cur_char-----------------------------------------5170char ADLParser::cur_char() {5171return (_curchar);5172}51735174//---------------------------next_char-----------------------------------------5175void ADLParser::next_char() {5176if (_curchar == '\n') parse_err(WARN, "must call next_line!");5177_curchar = *++_ptr;5178// if ( _curchar == '\n' ) {5179// next_line();5180// }5181}51825183//---------------------------next_char_or_line---------------------------------5184void ADLParser::next_char_or_line() {5185if ( _curchar != '\n' ) {5186_curchar = *++_ptr;5187} else {5188next_line();5189_ptr = _curline;5190_curchar = *_ptr; // maintain invariant5191}5192}51935194//---------------------------next_line-----------------------------------------5195void ADLParser::next_line() {5196_curline = _buf.get_line();5197_curchar = ' ';5198}51995200//------------------------get_line_string--------------------------------------5201// Prepended location descriptor, for debugging.5202// Must return a malloced string (that can be freed if desired).5203char* ADLParser::get_line_string(int linenum) {5204const char* file = _AD._ADL_file._name;5205int line = linenum ? linenum : this->linenum();5206char* location = (char *)AllocateHeap(strlen(file) + 100);5207sprintf(location, "\n#line %d \"%s\"\n", line, file);5208return location;5209}52105211//-------------------------is_literal_constant---------------------------------5212bool ADLParser::is_literal_constant(const char *param) {5213if (param[0] == 0) return false; // null string5214if (param[0] == '(') return true; // parenthesized expression5215if (param[0] == '0' && (param[1] == 'x' || param[1] == 'X')) {5216// Make sure it's a hex constant.5217int i = 2;5218do {5219if( !ADLParser::is_hex_digit(*(param+i)) ) return false;5220++i;5221} while( *(param+i) != 0 );5222return true;5223}5224return false;5225}52265227//---------------------------is_hex_digit--------------------------------------5228bool ADLParser::is_hex_digit(char digit) {5229return ((digit >= '0') && (digit <= '9'))5230||((digit >= 'a') && (digit <= 'f'))5231||((digit >= 'A') && (digit <= 'F'));5232}52335234//---------------------------is_int_token--------------------------------------5235bool ADLParser::is_int_token(const char* token, int& intval) {5236const char* cp = token;5237while (*cp != '\0' && *cp <= ' ') cp++;5238if (*cp == '-') cp++;5239int ndigit = 0;5240while (*cp >= '0' && *cp <= '9') { cp++; ndigit++; }5241while (*cp != '\0' && *cp <= ' ') cp++;5242if (ndigit == 0 || *cp != '\0') {5243return false;5244}5245intval = atoi(token);5246return true;5247}52485249static const char* skip_expr_ws(const char* str) {5250const char * cp = str;5251while (cp[0]) {5252if (cp[0] <= ' ') {5253++cp;5254} else if (cp[0] == '#') {5255++cp;5256while (cp[0] == ' ') ++cp;5257assert(0 == strncmp(cp, "line", 4), "must be a #line directive");5258const char* eol = strchr(cp, '\n');5259assert(eol != NULL, "must find end of line");5260if (eol == NULL) eol = cp + strlen(cp);5261cp = eol;5262} else {5263break;5264}5265}5266return cp;5267}52685269//-----------------------equivalent_expressions--------------------------------5270bool ADLParser::equivalent_expressions(const char* str1, const char* str2) {5271if (str1 == str2)5272return true;5273else if (str1 == NULL || str2 == NULL)5274return false;5275const char* cp1 = str1;5276const char* cp2 = str2;5277char in_quote = '\0';5278while (cp1[0] && cp2[0]) {5279if (!in_quote) {5280// skip spaces and/or cpp directives5281const char* cp1a = skip_expr_ws(cp1);5282const char* cp2a = skip_expr_ws(cp2);5283if (cp1a > cp1 && cp2a > cp2) {5284cp1 = cp1a; cp2 = cp2a;5285continue;5286}5287if (cp1a > cp1 || cp2a > cp2) break; // fail5288}5289// match one non-space char5290if (cp1[0] != cp2[0]) break; // fail5291char ch = cp1[0];5292cp1++; cp2++;5293// watch for quotes5294if (in_quote && ch == '\\') {5295if (cp1[0] != cp2[0]) break; // fail5296if (!cp1[0]) break;5297cp1++; cp2++;5298}5299if (in_quote && ch == in_quote) {5300in_quote = '\0';5301} else if (!in_quote && (ch == '"' || ch == '\'')) {5302in_quote = ch;5303}5304}5305return (!cp1[0] && !cp2[0]);5306}530753085309//-------------------------------trim------------------------------------------5310void ADLParser::trim(char* &token) {5311while (*token <= ' ') token++;5312char* end = token + strlen(token);5313while (end > token && *(end-1) <= ' ') --end;5314*end = '\0';5315}531653175318