Path: blob/aarch64-shenandoah-jdk8u272-b10/hotspot/src/share/vm/adlc/adlparse.cpp
32285 views
/*1* Copyright (c) 1997, 2013, 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 ASSERT50fprintf(stderr, "**************************************************************\n");51fprintf(stderr, "***** WARNING: ASSERT is undefined, assertions disabled. *****\n");52fprintf(stderr, "**************************************************************\n");53#endif54if( _AD._syntax_errs + _AD._semantic_errs + _AD._warnings == 0 ) {55if (!_AD._quiet_mode)56fprintf(stderr,"No errors or warnings to report from phase-1 parse.\n" );57}58else {59if( _AD._syntax_errs ) { // Any syntax errors?60fprintf(stderr,"%s: Found %d syntax error", _buf._fp->_name, _AD._syntax_errs);61if( _AD._syntax_errs > 1 ) fprintf(stderr,"s.\n\n");62else fprintf(stderr,".\n\n");63}64if( _AD._semantic_errs ) { // Any semantic errors?65fprintf(stderr,"%s: Found %d semantic error", _buf._fp->_name, _AD._semantic_errs);66if( _AD._semantic_errs > 1 ) fprintf(stderr,"s.\n\n");67else fprintf(stderr,".\n\n");68}69if( _AD._warnings ) { // Any warnings?70fprintf(stderr,"%s: Found %d warning", _buf._fp->_name, _AD._warnings);71if( _AD._warnings > 1 ) fprintf(stderr,"s.\n\n");72else fprintf(stderr,".\n\n");73}74}75if (!_AD._quiet_mode)76fprintf(stderr,"-----------------------------------------------------------------------------\n");77_AD._TotalLines += linenum()-1; // -1 for overshoot in "nextline" routine7879// Write out information we have stored80// // UNIXism == fsync(stderr);81}8283//------------------------------parse------------------------------------------84// Each top-level keyword should appear as the first non-whitespace on a line.85//86void ADLParser::parse() {87char *ident;8889// Iterate over the lines in the file buffer parsing Level 1 objects90for( next_line(); _curline != NULL; next_line()) {91_ptr = _curline; // Reset ptr to start of new line92skipws(); // Skip any leading whitespace93ident = get_ident(); // Get first token94if (ident == NULL) { // Empty line95continue; // Get the next line96}97if (!strcmp(ident, "instruct")) instr_parse();98else if (!strcmp(ident, "operand")) oper_parse();99else if (!strcmp(ident, "opclass")) opclass_parse();100else if (!strcmp(ident, "ins_attrib")) ins_attr_parse();101else if (!strcmp(ident, "op_attrib")) op_attr_parse();102else if (!strcmp(ident, "source")) source_parse();103else if (!strcmp(ident, "source_hpp")) source_hpp_parse();104else if (!strcmp(ident, "register")) reg_parse();105else if (!strcmp(ident, "frame")) frame_parse();106else if (!strcmp(ident, "encode")) encode_parse();107else if (!strcmp(ident, "pipeline")) pipe_parse();108else if (!strcmp(ident, "definitions")) definitions_parse();109else if (!strcmp(ident, "peephole")) peep_parse();110else if (!strcmp(ident, "#line")) preproc_line();111else if (!strcmp(ident, "#define")) preproc_define();112else if (!strcmp(ident, "#undef")) preproc_undef();113else {114parse_err(SYNERR, "expected one of - instruct, operand, ins_attrib, op_attrib, source, register, pipeline, encode\n Found %s",ident);115}116}117// Add reg_class spill_regs after parsing.118RegisterForm *regBlock = _AD.get_registers();119if (regBlock == NULL) {120parse_err(SEMERR, "Did not declare 'register' definitions");121}122regBlock->addSpillRegClass();123124// Done with parsing, check consistency.125126if (_preproc_depth != 0) {127parse_err(SYNERR, "End of file inside #ifdef");128}129130// AttributeForms ins_cost and op_cost must be defined for default behaviour131if (_globalNames[AttributeForm::_ins_cost] == NULL) {132parse_err(SEMERR, "Did not declare 'ins_cost' attribute");133}134if (_globalNames[AttributeForm::_op_cost] == NULL) {135parse_err(SEMERR, "Did not declare 'op_cost' attribute");136}137}138139// ******************** Private Level 1 Parse Functions ********************140//------------------------------instr_parse------------------------------------141// Parse the contents of an instruction definition, build the InstructForm to142// represent that instruction, and add it to the InstructForm list.143void ADLParser::instr_parse(void) {144char *ident;145InstructForm *instr;146MatchRule *rule;147int match_rules_cnt = 0;148149// First get the name of the instruction150if( (ident = get_unique_ident(_globalNames,"instruction")) == NULL )151return;152instr = new InstructForm(ident); // Create new instruction form153instr->_linenum = linenum();154_globalNames.Insert(ident, instr); // Add name to the name table155// Debugging Stuff156if (_AD._adl_debug > 1)157fprintf(stderr,"Parsing Instruction Form %s\n", ident);158159// Then get the operands160skipws();161if (_curchar != '(') {162parse_err(SYNERR, "missing '(' in instruct definition\n");163}164// Parse the operand list165else get_oplist(instr->_parameters, instr->_localNames);166skipws(); // Skip leading whitespace167// Check for block delimiter168if ( (_curchar != '%')169|| ( next_char(), (_curchar != '{')) ) {170parse_err(SYNERR, "missing '%%{' in instruction definition\n");171return;172}173next_char(); // Maintain the invariant174do {175ident = get_ident(); // Grab next identifier176if (ident == NULL) {177parse_err(SYNERR, "keyword identifier expected at %c\n", _curchar);178continue;179}180if (!strcmp(ident, "predicate")) instr->_predicate = pred_parse();181else if (!strcmp(ident, "match")) {182// Allow one instruction have several match rules.183rule = instr->_matrule;184if (rule == NULL) {185// This is first match rule encountered186rule = match_parse(instr->_localNames);187if (rule) {188instr->_matrule = rule;189// Special case the treatment of Control instructions.190if( instr->is_ideal_control() ) {191// Control instructions return a special result, 'Universe'192rule->_result = "Universe";193}194// Check for commutative operations with tree operands.195matchrule_clone_and_swap(rule, instr->_ident, match_rules_cnt);196}197} else {198// Find the end of the match rule list199while (rule->_next != NULL)200rule = rule->_next;201// Add the new match rule to the list202rule->_next = match_parse(instr->_localNames);203if (rule->_next) {204rule = rule->_next;205if( instr->is_ideal_control() ) {206parse_err(SYNERR, "unique match rule expected for %s\n", rule->_name);207return;208}209assert(match_rules_cnt < 100," too many match rule clones");210char* buf = (char*) malloc(strlen(instr->_ident) + 4);211sprintf(buf, "%s_%d", instr->_ident, match_rules_cnt++);212rule->_result = buf;213// Check for commutative operations with tree operands.214matchrule_clone_and_swap(rule, instr->_ident, match_rules_cnt);215}216}217}218else if (!strcmp(ident, "encode")) {219parse_err(SYNERR, "Instructions specify ins_encode, not encode\n");220}221else if (!strcmp(ident, "ins_encode")) ins_encode_parse(*instr);222// Parse late expand keyword.223else if (!strcmp(ident, "postalloc_expand")) postalloc_expand_parse(*instr);224else if (!strcmp(ident, "opcode")) instr->_opcode = opcode_parse(instr);225else if (!strcmp(ident, "size")) instr->_size = size_parse(instr);226else if (!strcmp(ident, "effect")) effect_parse(instr);227else if (!strcmp(ident, "expand")) instr->_exprule = expand_parse(instr);228else if (!strcmp(ident, "rewrite")) instr->_rewrule = rewrite_parse();229else if (!strcmp(ident, "constraint")) {230parse_err(SYNERR, "Instructions do not specify a constraint\n");231}232else if (!strcmp(ident, "construct")) {233parse_err(SYNERR, "Instructions do not specify a construct\n");234}235else if (!strcmp(ident, "format")) instr->_format = format_parse();236else if (!strcmp(ident, "interface")) {237parse_err(SYNERR, "Instructions do not specify an interface\n");238}239else if (!strcmp(ident, "ins_pipe")) ins_pipe_parse(*instr);240else { // Done with staticly defined parts of instruction definition241// Check identifier to see if it is the name of an attribute242const Form *form = _globalNames[ident];243AttributeForm *attr = form ? form->is_attribute() : NULL;244if (attr && (attr->_atype == INS_ATTR)) {245// Insert the new attribute into the linked list.246Attribute *temp = attr_parse(ident);247temp->_next = instr->_attribs;248instr->_attribs = temp;249} else {250parse_err(SYNERR, "expected one of:\n predicate, match, encode, or the name of"251" an instruction attribute at %s\n", ident);252}253}254skipws();255} while(_curchar != '%');256next_char();257if (_curchar != '}') {258parse_err(SYNERR, "missing '%%}' in instruction definition\n");259return;260}261// Check for "Set" form of chain rule262adjust_set_rule(instr);263if (_AD._pipeline) {264// No pipe required for late expand.265if (instr->expands() || instr->postalloc_expands()) {266if (instr->_ins_pipe) {267parse_err(WARN, "ins_pipe and expand rule both specified for instruction \"%s\";"268" ins_pipe will be unused\n", instr->_ident);269}270} else {271if (!instr->_ins_pipe) {272parse_err(WARN, "No ins_pipe specified for instruction \"%s\"\n", instr->_ident);273}274}275}276// Add instruction to tail of instruction list277_AD.addForm(instr);278279// Create instruction form for each additional match rule280rule = instr->_matrule;281if (rule != NULL) {282rule = rule->_next;283while (rule != NULL) {284ident = (char*)rule->_result;285InstructForm *clone = new InstructForm(ident, instr, rule); // Create new instruction form286_globalNames.Insert(ident, clone); // Add name to the name table287// Debugging Stuff288if (_AD._adl_debug > 1)289fprintf(stderr,"Parsing Instruction Form %s\n", ident);290// Check for "Set" form of chain rule291adjust_set_rule(clone);292// Add instruction to tail of instruction list293_AD.addForm(clone);294rule = rule->_next;295clone->_matrule->_next = NULL; // One match rule per clone296}297}298}299300//------------------------------matchrule_clone_and_swap-----------------------301// Check for commutative operations with subtree operands,302// create clones and swap operands.303void ADLParser::matchrule_clone_and_swap(MatchRule* rule, const char* instr_ident, int& match_rules_cnt) {304// Check for commutative operations with tree operands.305int count = 0;306rule->count_commutative_op(count);307if (count > 0) {308// Clone match rule and swap commutative operation's operands.309rule->matchrule_swap_commutative_op(instr_ident, count, match_rules_cnt);310}311}312313//------------------------------adjust_set_rule--------------------------------314// Check for "Set" form of chain rule315void ADLParser::adjust_set_rule(InstructForm *instr) {316if (instr->_matrule == NULL || instr->_matrule->_rChild == NULL) return;317const char *rch = instr->_matrule->_rChild->_opType;318const Form *frm = _globalNames[rch];319if( (! strcmp(instr->_matrule->_opType,"Set")) &&320frm && frm->is_operand() && (! frm->ideal_only()) ) {321// Previous implementation, which missed leaP*, but worked for loadCon*322unsigned position = 0;323const char *result = NULL;324const char *name = NULL;325const char *optype = NULL;326MatchNode *right = instr->_matrule->_rChild;327if (right->base_operand(position, _globalNames, result, name, optype)) {328position = 1;329const char *result2 = NULL;330const char *name2 = NULL;331const char *optype2 = NULL;332// Can not have additional base operands in right side of match!333if ( ! right->base_operand( position, _globalNames, result2, name2, optype2) ) {334if (instr->_predicate != NULL)335parse_err(SYNERR, "ADLC does not support instruction chain rules with predicates");336// Chain from input _ideal_operand_type_,337// Needed for shared roots of match-trees338ChainList *lst = (ChainList *)_AD._chainRules[optype];339if (lst == NULL) {340lst = new ChainList();341_AD._chainRules.Insert(optype, lst);342}343if (!lst->search(instr->_matrule->_lChild->_opType)) {344const char *cost = instr->cost();345if (cost == NULL) {346cost = ((AttributeForm*)_globalNames[AttributeForm::_ins_cost])->_attrdef;347}348// The ADLC does not support chaining from the ideal operand type349// of a predicated user-defined operand350if( frm->is_operand() == NULL || frm->is_operand()->_predicate == NULL ) {351lst->insert(instr->_matrule->_lChild->_opType,cost,instr->_ident);352}353}354// Chain from input _user_defined_operand_type_,355lst = (ChainList *)_AD._chainRules[result];356if (lst == NULL) {357lst = new ChainList();358_AD._chainRules.Insert(result, lst);359}360if (!lst->search(instr->_matrule->_lChild->_opType)) {361const char *cost = instr->cost();362if (cost == NULL) {363cost = ((AttributeForm*)_globalNames[AttributeForm::_ins_cost])->_attrdef;364}365// It is safe to chain from the top-level user-defined operand even366// if it has a predicate, since the predicate is checked before367// the user-defined type is available.368lst->insert(instr->_matrule->_lChild->_opType,cost,instr->_ident);369}370} else {371// May have instruction chain rule if root of right-tree is an ideal372OperandForm *rightOp = _globalNames[right->_opType]->is_operand();373if( rightOp ) {374const Form *rightRoot = _globalNames[rightOp->_matrule->_opType];375if( rightRoot && rightRoot->ideal_only() ) {376const char *chain_op = NULL;377if( rightRoot->is_instruction() )378chain_op = rightOp->_ident;379if( chain_op ) {380// Look-up the operation in chain rule table381ChainList *lst = (ChainList *)_AD._chainRules[chain_op];382if (lst == NULL) {383lst = new ChainList();384_AD._chainRules.Insert(chain_op, lst);385}386// if (!lst->search(instr->_matrule->_lChild->_opType)) {387const char *cost = instr->cost();388if (cost == NULL) {389cost = ((AttributeForm*)_globalNames[AttributeForm::_ins_cost])->_attrdef;390}391// This chains from a top-level operand whose predicate, if any,392// has been checked.393lst->insert(instr->_matrule->_lChild->_opType,cost,instr->_ident);394// }395}396}397}398} // end chain rule from right-tree's ideal root399}400}401}402403404//------------------------------oper_parse-------------------------------------405void ADLParser::oper_parse(void) {406char *ident;407OperandForm *oper;408AttributeForm *attr;409MatchRule *rule;410411// First get the name of the operand412skipws();413if( (ident = get_unique_ident(_globalNames,"operand")) == NULL )414return;415oper = new OperandForm(ident); // Create new operand form416oper->_linenum = linenum();417_globalNames.Insert(ident, oper); // Add name to the name table418419// Debugging Stuff420if (_AD._adl_debug > 1) fprintf(stderr,"Parsing Operand Form %s\n", ident);421422// Get the component operands423skipws();424if (_curchar != '(') {425parse_err(SYNERR, "missing '(' in operand definition\n");426return;427}428else get_oplist(oper->_parameters, oper->_localNames); // Parse the component operand list429skipws();430// Check for block delimiter431if ((_curchar != '%') || (*(_ptr+1) != '{')) { // If not open block432parse_err(SYNERR, "missing '%%{' in operand definition\n");433return;434}435next_char(); next_char(); // Skip over "%{" symbol436do {437ident = get_ident(); // Grab next identifier438if (ident == NULL) {439parse_err(SYNERR, "keyword identifier expected at %c\n", _curchar);440continue;441}442if (!strcmp(ident, "predicate")) oper->_predicate = pred_parse();443else if (!strcmp(ident, "match")) {444// Find the end of the match rule list445rule = oper->_matrule;446if (rule) {447while (rule->_next) rule = rule->_next;448// Add the new match rule to the list449rule->_next = match_parse(oper->_localNames);450if (rule->_next) {451rule->_next->_result = oper->_ident;452}453}454else {455// This is first match rule encountered456oper->_matrule = match_parse(oper->_localNames);457if (oper->_matrule) {458oper->_matrule->_result = oper->_ident;459}460}461}462else if (!strcmp(ident, "encode")) oper->_interface = interface_parse();463else if (!strcmp(ident, "ins_encode")) {464parse_err(SYNERR, "Operands specify 'encode', not 'ins_encode'\n");465}466else if (!strcmp(ident, "opcode")) {467parse_err(SYNERR, "Operands do not specify an opcode\n");468}469else if (!strcmp(ident, "effect")) {470parse_err(SYNERR, "Operands do not specify an effect\n");471}472else if (!strcmp(ident, "expand")) {473parse_err(SYNERR, "Operands do not specify an expand\n");474}475else if (!strcmp(ident, "rewrite")) {476parse_err(SYNERR, "Operands do not specify a rewrite\n");477}478else if (!strcmp(ident, "constraint"))oper->_constraint= constraint_parse();479else if (!strcmp(ident, "construct")) oper->_construct = construct_parse();480else if (!strcmp(ident, "format")) oper->_format = format_parse();481else if (!strcmp(ident, "interface")) oper->_interface = interface_parse();482// Check identifier to see if it is the name of an attribute483else if (((attr = _globalNames[ident]->is_attribute()) != NULL) &&484(attr->_atype == OP_ATTR)) oper->_attribs = attr_parse(ident);485else {486parse_err(SYNERR, "expected one of - constraint, predicate, match, encode, format, construct, or the name of a defined operand attribute at %s\n", ident);487}488skipws();489} while(_curchar != '%');490next_char();491if (_curchar != '}') {492parse_err(SYNERR, "missing '%%}' in operand definition\n");493return;494}495// Add operand to tail of operand list496_AD.addForm(oper);497}498499//------------------------------opclass_parse----------------------------------500// Operand Classes are a block with a comma delimited list of operand names501void ADLParser::opclass_parse(void) {502char *ident;503OpClassForm *opc;504OperandForm *opForm;505506// First get the name of the operand class507skipws();508if( (ident = get_unique_ident(_globalNames,"opclass")) == NULL )509return;510opc = new OpClassForm(ident); // Create new operand class form511_globalNames.Insert(ident, opc); // Add name to the name table512513// Debugging Stuff514if (_AD._adl_debug > 1)515fprintf(stderr,"Parsing Operand Class Form %s\n", ident);516517// Get the list of operands518skipws();519if (_curchar != '(') {520parse_err(SYNERR, "missing '(' in operand definition\n");521return;522}523do {524next_char(); // Skip past open paren or comma525ident = get_ident(); // Grab next identifier526if (ident == NULL) {527parse_err(SYNERR, "keyword identifier expected at %c\n", _curchar);528continue;529}530// Check identifier to see if it is the name of an operand531const Form *form = _globalNames[ident];532opForm = form ? form->is_operand() : NULL;533if ( opForm ) {534opc->_oplst.addName(ident); // Add operand to opclass list535opForm->_classes.addName(opc->_ident);// Add opclass to operand list536}537else {538parse_err(SYNERR, "expected name of a defined operand at %s\n", ident);539}540skipws(); // skip trailing whitespace541} while (_curchar == ','); // Check for the comma542// Check for closing ')'543if (_curchar != ')') {544parse_err(SYNERR, "missing ')' or ',' in opclass definition\n");545return;546}547next_char(); // Consume the ')'548skipws();549// Check for closing ';'550if (_curchar != ';') {551parse_err(SYNERR, "missing ';' in opclass definition\n");552return;553}554next_char(); // Consume the ';'555// Add operand to tail of operand list556_AD.addForm(opc);557}558559//------------------------------ins_attr_parse---------------------------------560void ADLParser::ins_attr_parse(void) {561char *ident;562char *aexpr;563AttributeForm *attrib;564565// get name for the instruction attribute566skipws(); // Skip leading whitespace567if( (ident = get_unique_ident(_globalNames,"inst_attrib")) == NULL )568return;569// Debugging Stuff570if (_AD._adl_debug > 1) fprintf(stderr,"Parsing Ins_Attribute Form %s\n", ident);571572// Get default value of the instruction attribute573skipws(); // Skip whitespace574if ((aexpr = get_paren_expr("attribute default expression string")) == NULL) {575parse_err(SYNERR, "missing '(' in ins_attrib definition\n");576return;577}578// Debug Stuff579if (_AD._adl_debug > 1) fprintf(stderr,"Attribute Expression: %s\n", aexpr);580581// Check for terminator582if (_curchar != ';') {583parse_err(SYNERR, "missing ';' in ins_attrib definition\n");584return;585}586next_char(); // Advance past the ';'587588// Construct the attribute, record global name, and store in ArchDesc589attrib = new AttributeForm(ident, INS_ATTR, aexpr);590_globalNames.Insert(ident, attrib); // Add name to the name table591_AD.addForm(attrib);592}593594//------------------------------op_attr_parse----------------------------------595void ADLParser::op_attr_parse(void) {596char *ident;597char *aexpr;598AttributeForm *attrib;599600// get name for the operand attribute601skipws(); // Skip leading whitespace602if( (ident = get_unique_ident(_globalNames,"op_attrib")) == NULL )603return;604// Debugging Stuff605if (_AD._adl_debug > 1) fprintf(stderr,"Parsing Op_Attribute Form %s\n", ident);606607// Get default value of the instruction attribute608skipws(); // Skip whitespace609if ((aexpr = get_paren_expr("attribute default expression string")) == NULL) {610parse_err(SYNERR, "missing '(' in op_attrib definition\n");611return;612}613// Debug Stuff614if (_AD._adl_debug > 1) fprintf(stderr,"Attribute Expression: %s\n", aexpr);615616// Check for terminator617if (_curchar != ';') {618parse_err(SYNERR, "missing ';' in op_attrib definition\n");619return;620}621next_char(); // Advance past the ';'622623// Construct the attribute, record global name, and store in ArchDesc624attrib = new AttributeForm(ident, OP_ATTR, aexpr);625_globalNames.Insert(ident, attrib);626_AD.addForm(attrib);627}628629//------------------------------definitions_parse-----------------------------------630void ADLParser::definitions_parse(void) {631skipws(); // Skip leading whitespace632if (_curchar == '%' && *(_ptr+1) == '{') {633next_char(); next_char(); // Skip "%{"634skipws();635while (_curchar != '%' && *(_ptr+1) != '}') {636// Process each definition until finding closing string "%}"637char *token = get_ident();638if (token == NULL) {639parse_err(SYNERR, "missing identifier inside definitions block.\n");640return;641}642if (strcmp(token,"int_def")==0) { int_def_parse(); }643// if (strcmp(token,"str_def")==0) { str_def_parse(); }644skipws();645}646}647else {648parse_err(SYNERR, "Missing %%{ ... %%} block after definitions keyword.\n");649return;650}651}652653//------------------------------int_def_parse----------------------------------654// Parse Example:655// int_def MEMORY_REF_COST ( 200, DEFAULT_COST * 2);656// <keyword> <name> ( <int_value>, <description> );657//658void ADLParser::int_def_parse(void) {659char *name = NULL; // Name of definition660char *value = NULL; // its value,661int int_value = -1; // positive values only662char *description = NULL; // textual description663664// Get definition name665skipws(); // Skip whitespace666name = get_ident();667if (name == NULL) {668parse_err(SYNERR, "missing definition name after int_def\n");669return;670}671672// Check for value of int_def dname( integer_value [, string_expression ] )673skipws();674if (_curchar == '(') {675676// Parse the integer value.677next_char();678value = get_ident();679if (value == NULL) {680parse_err(SYNERR, "missing value in int_def\n");681return;682}683if( !is_int_token(value, int_value) ) {684parse_err(SYNERR, "value in int_def is not recognized as integer\n");685return;686}687skipws();688689// Check for description690if (_curchar == ',') {691next_char(); // skip ','692693description = get_expr("int_def description", ")");694if (description == NULL) {695parse_err(SYNERR, "invalid or missing description in int_def\n");696return;697}698trim(description);699}700701if (_curchar != ')') {702parse_err(SYNERR, "missing ')' in register definition statement\n");703return;704}705next_char();706}707708// Check for closing ';'709skipws();710if (_curchar != ';') {711parse_err(SYNERR, "missing ';' after int_def\n");712return;713}714next_char(); // move past ';'715716// Debug Stuff717if (_AD._adl_debug > 1) {718fprintf(stderr,"int_def: %s ( %s, %s )\n", name,719(value), (description ? description : ""));720}721722// Record new definition.723Expr *expr = new Expr(name, description, int_value, int_value);724const Expr *old_expr = _AD.globalDefs().define(name, expr);725if (old_expr != NULL) {726parse_err(SYNERR, "Duplicate definition\n");727return;728}729730return;731}732733734//------------------------------source_parse-----------------------------------735void ADLParser::source_parse(void) {736SourceForm *source; // Encode class for instruction/operand737char *rule = NULL; // String representation of encode rule738739skipws(); // Skip leading whitespace740if ( (rule = find_cpp_block("source block")) == NULL ) {741parse_err(SYNERR, "incorrect or missing block for 'source'.\n");742return;743}744// Debug Stuff745if (_AD._adl_debug > 1) fprintf(stderr,"Source Form: %s\n", rule);746747source = new SourceForm(rule); // Build new Source object748_AD.addForm(source);749// skipws();750}751752//------------------------------source_hpp_parse-------------------------------753// Parse a source_hpp %{ ... %} block.754// The code gets stuck into the ad_<arch>.hpp file.755// If the source_hpp block appears before the register block in the AD756// file, it goes up at the very top of the ad_<arch>.hpp file, so that757// it can be used by register encodings, etc. Otherwise, it goes towards758// the bottom, where it's useful as a global definition to *.cpp files.759void ADLParser::source_hpp_parse(void) {760char *rule = NULL; // String representation of encode rule761762skipws(); // Skip leading whitespace763if ( (rule = find_cpp_block("source_hpp block")) == NULL ) {764parse_err(SYNERR, "incorrect or missing block for 'source_hpp'.\n");765return;766}767// Debug Stuff768if (_AD._adl_debug > 1) fprintf(stderr,"Header Form: %s\n", rule);769770if (_AD.get_registers() == NULL) {771// Very early in the file, before reg_defs, we collect pre-headers.772PreHeaderForm* pre_header = new PreHeaderForm(rule);773_AD.addForm(pre_header);774} else {775// Normally, we collect header info, placed at the bottom of the hpp file.776HeaderForm* header = new HeaderForm(rule);777_AD.addForm(header);778}779}780781//------------------------------reg_parse--------------------------------------782void ADLParser::reg_parse(void) {783RegisterForm *regBlock = _AD.get_registers(); // Information about registers encoding784if (regBlock == NULL) {785// Create the RegisterForm for the architecture description.786regBlock = new RegisterForm(); // Build new Source object787_AD.addForm(regBlock);788}789790skipws(); // Skip leading whitespace791if (_curchar == '%' && *(_ptr+1) == '{') {792next_char(); next_char(); // Skip "%{"793skipws();794while (_curchar != '%' && *(_ptr+1) != '}') {795char *token = get_ident();796if (token == NULL) {797parse_err(SYNERR, "missing identifier inside register block.\n");798return;799}800if (strcmp(token,"reg_def")==0) { reg_def_parse(); }801else if (strcmp(token,"reg_class")==0) { reg_class_parse(); }802else if (strcmp(token, "reg_class_dynamic") == 0) { reg_class_dynamic_parse(); }803else if (strcmp(token,"alloc_class")==0) { alloc_class_parse(); }804else if (strcmp(token,"#define")==0) { preproc_define(); }805else { parse_err(SYNERR, "bad token %s inside register block.\n", token); break; }806skipws();807}808}809else {810parse_err(SYNERR, "Missing %c{ ... %c} block after register keyword.\n",'%','%');811return;812}813}814815//------------------------------encode_parse-----------------------------------816void ADLParser::encode_parse(void) {817EncodeForm *encBlock; // Information about instruction/operand encoding818819_AD.getForm(&encBlock);820if ( encBlock == NULL) {821// Create the EncodeForm for the architecture description.822encBlock = new EncodeForm(); // Build new Source object823_AD.addForm(encBlock);824}825826skipws(); // Skip leading whitespace827if (_curchar == '%' && *(_ptr+1) == '{') {828next_char(); next_char(); // Skip "%{"829skipws();830while (_curchar != '%' && *(_ptr+1) != '}') {831char *token = get_ident();832if (token == NULL) {833parse_err(SYNERR, "missing identifier inside encoding block.\n");834return;835}836if (strcmp(token,"enc_class")==0) { enc_class_parse(); }837skipws();838}839}840else {841parse_err(SYNERR, "Missing %c{ ... %c} block after encode keyword.\n",'%','%');842return;843}844}845846//------------------------------enc_class_parse--------------------------------847void ADLParser::enc_class_parse(void) {848char *ec_name; // Name of encoding class being defined849850// Get encoding class name851skipws(); // Skip whitespace852ec_name = get_ident();853if (ec_name == NULL) {854parse_err(SYNERR, "missing encoding class name after encode.\n");855return;856}857858EncClass *encoding = _AD._encode->add_EncClass(ec_name);859encoding->_linenum = linenum();860861skipws(); // Skip leading whitespace862// Check for optional parameter list863if (_curchar == '(') {864do {865char *pType = NULL; // parameter type866char *pName = NULL; // parameter name867868next_char(); // skip open paren & comma characters869skipws();870if (_curchar == ')') break;871872// Get parameter type873pType = get_ident();874if (pType == NULL) {875parse_err(SYNERR, "parameter type expected at %c\n", _curchar);876return;877}878879skipws();880// Get parameter name881pName = get_ident();882if (pName == NULL) {883parse_err(SYNERR, "parameter name expected at %c\n", _curchar);884return;885}886887// Record parameter type and name888encoding->add_parameter( pType, pName );889890skipws();891} while(_curchar == ',');892893if (_curchar != ')') parse_err(SYNERR, "missing ')'\n");894else {895next_char(); // Skip ')'896}897} // Done with parameter list898899skipws();900// Check for block starting delimiters901if ((_curchar != '%') || (*(_ptr+1) != '{')) { // If not open block902parse_err(SYNERR, "missing '%c{' in enc_class definition\n", '%');903return;904}905next_char(); // Skip '%'906next_char(); // Skip '{'907908enc_class_parse_block(encoding, ec_name);909}910911912void ADLParser::enc_class_parse_block(EncClass* encoding, char* ec_name) {913skipws_no_preproc(); // Skip leading whitespace914// Prepend location descriptor, for debugging; cf. ADLParser::find_cpp_block915if (_AD._adlocation_debug) {916encoding->add_code(get_line_string());917}918919// Collect the parts of the encode description920// (1) strings that are passed through to output921// (2) replacement/substitution variable, preceeded by a '$'922while ( (_curchar != '%') && (*(_ptr+1) != '}') ) {923924// (1)925// Check if there is a string to pass through to output926char *start = _ptr; // Record start of the next string927while ((_curchar != '$') && ((_curchar != '%') || (*(_ptr+1) != '}')) ) {928// If at the start of a comment, skip past it929if( (_curchar == '/') && ((*(_ptr+1) == '/') || (*(_ptr+1) == '*')) ) {930skipws_no_preproc();931} else {932// ELSE advance to the next character, or start of the next line933next_char_or_line();934}935}936// If a string was found, terminate it and record in EncClass937if ( start != _ptr ) {938*_ptr = '\0'; // Terminate the string939encoding->add_code(start);940}941942// (2)943// If we are at a replacement variable,944// copy it and record in EncClass945if (_curchar == '$') {946// Found replacement Variable947char* rep_var = get_rep_var_ident_dup();948// Add flag to _strings list indicating we should check _rep_vars949encoding->add_rep_var(rep_var);950}951} // end while part of format description952next_char(); // Skip '%'953next_char(); // Skip '}'954955skipws();956957if (_AD._adlocation_debug) {958encoding->add_code(end_line_marker());959}960961// Debug Stuff962if (_AD._adl_debug > 1) fprintf(stderr,"EncodingClass Form: %s\n", ec_name);963}964965//------------------------------frame_parse-----------------------------------966void ADLParser::frame_parse(void) {967FrameForm *frame; // Information about stack-frame layout968char *desc = NULL; // String representation of frame969970skipws(); // Skip leading whitespace971972frame = new FrameForm(); // Build new Frame object973// Check for open block sequence974skipws(); // Skip leading whitespace975if (_curchar == '%' && *(_ptr+1) == '{') {976next_char(); next_char(); // Skip "%{"977skipws();978while (_curchar != '%' && *(_ptr+1) != '}') {979char *token = get_ident();980if (token == NULL) {981parse_err(SYNERR, "missing identifier inside frame block.\n");982return;983}984if (strcmp(token,"stack_direction")==0) {985stack_dir_parse(frame);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) {1004interpreter_method_oop_parse(frame, false);1005}1006if (strcmp(token,"cisc_spilling_operand_name")==0) {1007cisc_spilling_operand_name_parse(frame, false);1008}1009if (strcmp(token,"stack_alignment")==0) {1010stack_alignment_parse(frame);1011}1012if (strcmp(token,"return_addr")==0) {1013return_addr_parse(frame, false);1014}1015if (strcmp(token,"in_preserve_stack_slots")==0) {1016preserve_stack_parse(frame);1017}1018if (strcmp(token,"out_preserve_stack_slots")==0) {1019parse_err(WARN, "Using obsolete token, out_preserve_stack_slots");1020skipws();1021}1022if (strcmp(token,"varargs_C_out_slots_killed")==0) {1023frame->_varargs_C_out_slots_killed = parse_one_arg("varargs C out slots killed");1024}1025if (strcmp(token,"calling_convention")==0) {1026frame->_calling_convention = calling_convention_parse();1027}1028if (strcmp(token,"return_value")==0) {1029frame->_return_value = return_value_parse();1030}1031if (strcmp(token,"c_frame_pointer")==0) {1032frame_pointer_parse(frame, true);1033}1034if (strcmp(token,"c_return_addr")==0) {1035return_addr_parse(frame, true);1036}1037if (strcmp(token,"c_calling_convention")==0) {1038frame->_c_calling_convention = calling_convention_parse();1039}1040if (strcmp(token,"c_return_value")==0) {1041frame->_c_return_value = return_value_parse();1042}10431044skipws();1045}1046}1047else {1048parse_err(SYNERR, "Missing %c{ ... %c} block after encode keyword.\n",'%','%');1049return;1050}1051// All Java versions are required, native versions are optional1052if(frame->_frame_pointer == NULL) {1053parse_err(SYNERR, "missing frame pointer definition in frame section.\n");1054return;1055}1056// !!!!! !!!!!1057// if(frame->_interpreter_frame_ptr_reg == NULL) {1058// parse_err(SYNERR, "missing interpreter frame pointer definition in frame section.\n");1059// return;1060// }1061if(frame->_alignment == NULL) {1062parse_err(SYNERR, "missing alignment definition in frame section.\n");1063return;1064}1065if(frame->_return_addr == NULL) {1066parse_err(SYNERR, "missing return address location in frame section.\n");1067return;1068}1069if(frame->_in_preserve_slots == NULL) {1070parse_err(SYNERR, "missing stack slot preservation definition in frame section.\n");1071return;1072}1073if(frame->_varargs_C_out_slots_killed == NULL) {1074parse_err(SYNERR, "missing varargs C out slots killed definition in frame section.\n");1075return;1076}1077if(frame->_calling_convention == NULL) {1078parse_err(SYNERR, "missing calling convention 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_calling_convention == NULL) {1094frame->_c_calling_convention = frame->_calling_convention;1095}1096if(frame->_c_return_value == NULL) {1097frame->_c_return_value = frame->_return_value;1098}10991100// Debug Stuff1101if (_AD._adl_debug > 1) fprintf(stderr,"Frame Form: %s\n", desc);11021103// Create the EncodeForm for the architecture description.1104_AD.addForm(frame);1105// skipws();1106}11071108//------------------------------stack_dir_parse--------------------------------1109void ADLParser::stack_dir_parse(FrameForm *frame) {1110char *direction = parse_one_arg("stack direction entry");1111if (strcmp(direction, "TOWARDS_LOW") == 0) {1112frame->_direction = false;1113}1114else if (strcmp(direction, "TOWARDS_HIGH") == 0) {1115frame->_direction = true;1116}1117else {1118parse_err(SYNERR, "invalid value inside stack direction entry.\n");1119return;1120}1121}11221123//------------------------------sync_stack_slots_parse-------------------------1124void ADLParser::sync_stack_slots_parse(FrameForm *frame) {1125// Assign value into frame form1126frame->_sync_stack_slots = parse_one_arg("sync stack slots entry");1127}11281129//------------------------------frame_pointer_parse----------------------------1130void ADLParser::frame_pointer_parse(FrameForm *frame, bool native) {1131char *frame_pointer = parse_one_arg("frame pointer entry");1132// Assign value into frame form1133if (native) { frame->_c_frame_pointer = frame_pointer; }1134else { frame->_frame_pointer = frame_pointer; }1135}11361137//------------------------------interpreter_frame_pointer_parse----------------------------1138void ADLParser::interpreter_frame_pointer_parse(FrameForm *frame, bool native) {1139frame->_interpreter_frame_pointer_reg = parse_one_arg("interpreter frame pointer entry");1140}11411142//------------------------------inline_cache_parse-----------------------------1143void ADLParser::inline_cache_parse(FrameForm *frame, bool native) {1144frame->_inline_cache_reg = parse_one_arg("inline cache reg entry");1145}11461147//------------------------------interpreter_method_oop_parse------------------1148void ADLParser::interpreter_method_oop_parse(FrameForm *frame, bool native) {1149frame->_interpreter_method_oop_reg = parse_one_arg("method oop reg entry");1150}11511152//------------------------------cisc_spilling_operand_parse---------------------1153void ADLParser::cisc_spilling_operand_name_parse(FrameForm *frame, bool native) {1154frame->_cisc_spilling_operand_name = parse_one_arg("cisc spilling operand name");1155}11561157//------------------------------stack_alignment_parse--------------------------1158void ADLParser::stack_alignment_parse(FrameForm *frame) {1159char *alignment = parse_one_arg("stack alignment entry");1160// Assign value into frame1161frame->_alignment = alignment;1162}11631164//------------------------------parse_one_arg-------------------------------1165char *ADLParser::parse_one_arg(const char *description) {1166char *token = NULL;1167if(_curchar == '(') {1168next_char();1169skipws();1170token = get_expr(description, ")");1171if (token == NULL) {1172parse_err(SYNERR, "missing value inside %s.\n", description);1173return NULL;1174}1175next_char(); // skip the close paren1176if(_curchar != ';') { // check for semi-colon1177parse_err(SYNERR, "missing %c in.\n", ';', description);1178return NULL;1179}1180next_char(); // skip the semi-colon1181}1182else {1183parse_err(SYNERR, "Missing %c in.\n", '(', description);1184return NULL;1185}11861187trim(token);1188return token;1189}11901191//------------------------------return_addr_parse------------------------------1192void ADLParser::return_addr_parse(FrameForm *frame, bool native) {1193bool in_register = true;1194if(_curchar == '(') {1195next_char();1196skipws();1197char *token = get_ident();1198if (token == NULL) {1199parse_err(SYNERR, "missing value inside return address entry.\n");1200return;1201}1202// check for valid values for stack/register1203if (strcmp(token, "REG") == 0) {1204in_register = true;1205}1206else if (strcmp(token, "STACK") == 0) {1207in_register = false;1208}1209else {1210parse_err(SYNERR, "invalid value inside return_address entry.\n");1211return;1212}1213if (native) { frame->_c_return_addr_loc = in_register; }1214else { frame->_return_addr_loc = in_register; }12151216// Parse expression that specifies register or stack position1217skipws();1218char *token2 = get_expr("return address entry", ")");1219if (token2 == NULL) {1220parse_err(SYNERR, "missing value inside return address entry.\n");1221return;1222}1223next_char(); // skip the close paren1224if (native) { frame->_c_return_addr = token2; }1225else { frame->_return_addr = token2; }12261227if(_curchar != ';') { // check for semi-colon1228parse_err(SYNERR, "missing %c in return address entry.\n", ';');1229return;1230}1231next_char(); // skip the semi-colon1232}1233else {1234parse_err(SYNERR, "Missing %c in return_address entry.\n", '(');1235}1236}12371238//------------------------------preserve_stack_parse---------------------------1239void ADLParser::preserve_stack_parse(FrameForm *frame) {1240if(_curchar == '(') {1241char *token = get_paren_expr("preserve_stack_slots");1242frame->_in_preserve_slots = token;12431244if(_curchar != ';') { // check for semi-colon1245parse_err(SYNERR, "missing %c in preserve stack slot entry.\n", ';');1246return;1247}1248next_char(); // skip the semi-colon1249}1250else {1251parse_err(SYNERR, "Missing %c in preserve stack slot entry.\n", '(');1252}1253}12541255//------------------------------calling_convention_parse-----------------------1256char *ADLParser::calling_convention_parse() {1257char *desc = NULL; // String representation of calling_convention12581259skipws(); // Skip leading whitespace1260if ( (desc = find_cpp_block("calling convention block")) == NULL ) {1261parse_err(SYNERR, "incorrect or missing block for 'calling_convention'.\n");1262}1263return desc;1264}12651266//------------------------------return_value_parse-----------------------------1267char *ADLParser::return_value_parse() {1268char *desc = NULL; // String representation of calling_convention12691270skipws(); // Skip leading whitespace1271if ( (desc = find_cpp_block("return value block")) == NULL ) {1272parse_err(SYNERR, "incorrect or missing block for 'return_value'.\n");1273}1274return desc;1275}12761277//------------------------------ins_pipe_parse---------------------------------1278void ADLParser::ins_pipe_parse(InstructForm &instr) {1279char * ident;12801281skipws();1282if ( _curchar != '(' ) { // Check for delimiter1283parse_err(SYNERR, "missing \"(\" in ins_pipe definition\n");1284return;1285}12861287next_char();1288ident = get_ident(); // Grab next identifier12891290if (ident == NULL) {1291parse_err(SYNERR, "keyword identifier expected at %c\n", _curchar);1292return;1293}12941295skipws();1296if ( _curchar != ')' ) { // Check for delimiter1297parse_err(SYNERR, "missing \")\" in ins_pipe definition\n");1298return;1299}13001301next_char(); // skip the close paren1302if(_curchar != ';') { // check for semi-colon1303parse_err(SYNERR, "missing %c in return value entry.\n", ';');1304return;1305}1306next_char(); // skip the semi-colon13071308// Check ident for validity1309if (_AD._pipeline && !_AD._pipeline->_classlist.search(ident)) {1310parse_err(SYNERR, "\"%s\" is not a valid pipeline class\n", ident);1311return;1312}13131314// Add this instruction to the list in the pipeline class1315_AD._pipeline->_classdict[ident]->is_pipeclass()->_instructs.addName(instr._ident);13161317// Set the name of the pipeline class in the instruction1318instr._ins_pipe = ident;1319return;1320}13211322//------------------------------pipe_parse-------------------------------------1323void ADLParser::pipe_parse(void) {1324PipelineForm *pipeline; // Encode class for instruction/operand1325char * ident;13261327pipeline = new PipelineForm(); // Build new Source object1328_AD.addForm(pipeline);13291330skipws(); // Skip leading whitespace1331// Check for block delimiter1332if ( (_curchar != '%')1333|| ( next_char(), (_curchar != '{')) ) {1334parse_err(SYNERR, "missing '%%{' in pipeline definition\n");1335return;1336}1337next_char(); // Maintain the invariant1338do {1339ident = get_ident(); // Grab next identifier1340if (ident == NULL) {1341parse_err(SYNERR, "keyword identifier expected at %c\n", _curchar);1342continue;1343}1344if (!strcmp(ident, "resources" )) resource_parse(*pipeline);1345else if (!strcmp(ident, "pipe_desc" )) pipe_desc_parse(*pipeline);1346else if (!strcmp(ident, "pipe_class")) pipe_class_parse(*pipeline);1347else if (!strcmp(ident, "define")) {1348skipws();1349if ( (_curchar != '%')1350|| ( next_char(), (_curchar != '{')) ) {1351parse_err(SYNERR, "expected '%%{'\n");1352return;1353}1354next_char(); skipws();13551356char *node_class = get_ident();1357if (node_class == NULL) {1358parse_err(SYNERR, "expected identifier, found \"%c\"\n", _curchar);1359return;1360}13611362skipws();1363if (_curchar != ',' && _curchar != '=') {1364parse_err(SYNERR, "expected `=`, found '%c'\n", _curchar);1365break;1366}1367next_char(); skipws();13681369char *pipe_class = get_ident();1370if (pipe_class == NULL) {1371parse_err(SYNERR, "expected identifier, found \"%c\"\n", _curchar);1372return;1373}1374if (_curchar != ';' ) {1375parse_err(SYNERR, "expected `;`, found '%c'\n", _curchar);1376break;1377}1378next_char(); // Skip over semi-colon13791380skipws();1381if ( (_curchar != '%')1382|| ( next_char(), (_curchar != '}')) ) {1383parse_err(SYNERR, "expected '%%}', found \"%c\"\n", _curchar);1384}1385next_char();13861387// Check ident for validity1388if (_AD._pipeline && !_AD._pipeline->_classlist.search(pipe_class)) {1389parse_err(SYNERR, "\"%s\" is not a valid pipeline class\n", pipe_class);1390return;1391}13921393// Add this machine node to the list in the pipeline class1394_AD._pipeline->_classdict[pipe_class]->is_pipeclass()->_instructs.addName(node_class);13951396MachNodeForm *machnode = new MachNodeForm(node_class); // Create new machnode form1397machnode->_machnode_pipe = pipe_class;13981399_AD.addForm(machnode);1400}1401else if (!strcmp(ident, "attributes")) {1402bool vsi_seen = false;14031404skipws();1405if ( (_curchar != '%')1406|| ( next_char(), (_curchar != '{')) ) {1407parse_err(SYNERR, "expected '%%{'\n");1408return;1409}1410next_char(); skipws();14111412while (_curchar != '%') {1413ident = get_ident();1414if (ident == NULL)1415break;14161417if (!strcmp(ident, "variable_size_instructions")) {1418skipws();1419if (_curchar == ';') {1420next_char(); skipws();1421}14221423pipeline->_variableSizeInstrs = true;1424vsi_seen = true;1425continue;1426}14271428if (!strcmp(ident, "fixed_size_instructions")) {1429skipws();1430if (_curchar == ';') {1431next_char(); skipws();1432}14331434pipeline->_variableSizeInstrs = false;1435vsi_seen = true;1436continue;1437}14381439if (!strcmp(ident, "branch_has_delay_slot")) {1440skipws();1441if (_curchar == ';') {1442next_char(); skipws();1443}14441445pipeline->_branchHasDelaySlot = true;1446continue;1447}14481449if (!strcmp(ident, "max_instructions_per_bundle")) {1450skipws();1451if (_curchar != '=') {1452parse_err(SYNERR, "expected `=`\n");1453break;1454}14551456next_char(); skipws();1457pipeline->_maxInstrsPerBundle = get_int();1458skipws();14591460if (_curchar == ';') {1461next_char(); skipws();1462}14631464continue;1465}14661467if (!strcmp(ident, "max_bundles_per_cycle")) {1468skipws();1469if (_curchar != '=') {1470parse_err(SYNERR, "expected `=`\n");1471break;1472}14731474next_char(); skipws();1475pipeline->_maxBundlesPerCycle = get_int();1476skipws();14771478if (_curchar == ';') {1479next_char(); skipws();1480}14811482continue;1483}14841485if (!strcmp(ident, "instruction_unit_size")) {1486skipws();1487if (_curchar != '=') {1488parse_err(SYNERR, "expected `=`, found '%c'\n", _curchar);1489break;1490}14911492next_char(); skipws();1493pipeline->_instrUnitSize = get_int();1494skipws();14951496if (_curchar == ';') {1497next_char(); skipws();1498}14991500continue;1501}15021503if (!strcmp(ident, "bundle_unit_size")) {1504skipws();1505if (_curchar != '=') {1506parse_err(SYNERR, "expected `=`, found '%c'\n", _curchar);1507break;1508}15091510next_char(); skipws();1511pipeline->_bundleUnitSize = get_int();1512skipws();15131514if (_curchar == ';') {1515next_char(); skipws();1516}15171518continue;1519}15201521if (!strcmp(ident, "instruction_fetch_unit_size")) {1522skipws();1523if (_curchar != '=') {1524parse_err(SYNERR, "expected `=`, found '%c'\n", _curchar);1525break;1526}15271528next_char(); skipws();1529pipeline->_instrFetchUnitSize = get_int();1530skipws();15311532if (_curchar == ';') {1533next_char(); skipws();1534}15351536continue;1537}15381539if (!strcmp(ident, "instruction_fetch_units")) {1540skipws();1541if (_curchar != '=') {1542parse_err(SYNERR, "expected `=`, found '%c'\n", _curchar);1543break;1544}15451546next_char(); skipws();1547pipeline->_instrFetchUnits = get_int();1548skipws();15491550if (_curchar == ';') {1551next_char(); skipws();1552}15531554continue;1555}15561557if (!strcmp(ident, "nops")) {1558skipws();1559if (_curchar != '(') {1560parse_err(SYNERR, "expected `(`, found '%c'\n", _curchar);1561break;1562}15631564next_char(); skipws();15651566while (_curchar != ')') {1567ident = get_ident();1568if (ident == NULL) {1569parse_err(SYNERR, "expected identifier for nop instruction, found '%c'\n", _curchar);1570break;1571}15721573pipeline->_noplist.addName(ident);1574pipeline->_nopcnt++;1575skipws();15761577if (_curchar == ',') {1578next_char(); skipws();1579}1580}15811582next_char(); skipws();15831584if (_curchar == ';') {1585next_char(); skipws();1586}15871588continue;1589}15901591parse_err(SYNERR, "unknown specifier \"%s\"\n", ident);1592}15931594if ( (_curchar != '%')1595|| ( next_char(), (_curchar != '}')) ) {1596parse_err(SYNERR, "expected '%%}', found \"%c\"\n", _curchar);1597}1598next_char(); skipws();15991600if (pipeline->_maxInstrsPerBundle == 0)1601parse_err(SYNERR, "\"max_instructions_per_bundle\" unspecified\n");1602if (pipeline->_instrUnitSize == 0 && pipeline->_bundleUnitSize == 0)1603parse_err(SYNERR, "\"instruction_unit_size\" and \"bundle_unit_size\" unspecified\n");1604if (pipeline->_instrFetchUnitSize == 0)1605parse_err(SYNERR, "\"instruction_fetch_unit_size\" unspecified\n");1606if (pipeline->_instrFetchUnits == 0)1607parse_err(SYNERR, "\"instruction_fetch_units\" unspecified\n");1608if (!vsi_seen)1609parse_err(SYNERR, "\"variable_size_instruction\" or \"fixed_size_instruction\" unspecified\n");1610}1611else { // Done with staticly defined parts of instruction definition1612parse_err(SYNERR, "expected one of \"resources\", \"pipe_desc\", \"pipe_class\", found \"%s\"\n", ident);1613return;1614}1615skipws();1616if (_curchar == ';')1617skipws();1618} while(_curchar != '%');16191620next_char();1621if (_curchar != '}') {1622parse_err(SYNERR, "missing \"%%}\" in pipeline definition\n");1623return;1624}16251626next_char();1627}16281629//------------------------------resource_parse----------------------------1630void ADLParser::resource_parse(PipelineForm &pipeline) {1631ResourceForm *resource;1632char * ident;1633char * expr;1634unsigned mask;1635pipeline._rescount = 0;16361637skipws(); // Skip leading whitespace16381639if (_curchar != '(') {1640parse_err(SYNERR, "missing \"(\" in resource definition\n");1641return;1642}16431644do {1645next_char(); // Skip "(" or ","1646ident = get_ident(); // Grab next identifier16471648if (_AD._adl_debug > 1) {1649if (ident != NULL) {1650fprintf(stderr, "resource_parse: identifier: %s\n", ident);1651}1652}16531654if (ident == NULL) {1655parse_err(SYNERR, "keyword identifier expected at \"%c\"\n", _curchar);1656return;1657}1658skipws();16591660if (_curchar != '=') {1661mask = (1 << pipeline._rescount++);1662}1663else {1664next_char(); skipws();1665expr = get_ident(); // Grab next identifier1666if (expr == NULL) {1667parse_err(SYNERR, "keyword identifier expected at \"%c\"\n", _curchar);1668return;1669}1670resource = (ResourceForm *) pipeline._resdict[expr];1671if (resource == NULL) {1672parse_err(SYNERR, "resource \"%s\" is not defined\n", expr);1673return;1674}1675mask = resource->mask();16761677skipws();1678while (_curchar == '|') {1679next_char(); skipws();16801681expr = get_ident(); // Grab next identifier1682if (expr == NULL) {1683parse_err(SYNERR, "keyword identifier expected at \"%c\"\n", _curchar);1684return;1685}16861687resource = (ResourceForm *) pipeline._resdict[expr]; // Look up the value1688if (resource == NULL) {1689parse_err(SYNERR, "resource \"%s\" is not defined\n", expr);1690return;1691}16921693mask |= resource->mask();1694skipws();1695}1696}16971698resource = new ResourceForm(mask);16991700pipeline._resdict.Insert(ident, resource);1701pipeline._reslist.addName(ident);1702} while (_curchar == ',');17031704if (_curchar != ')') {1705parse_err(SYNERR, "\")\" expected at \"%c\"\n", _curchar);1706return;1707}17081709next_char(); // Skip ")"1710if (_curchar == ';')1711next_char(); // Skip ";"1712}17131714//------------------------------resource_parse----------------------------1715void ADLParser::pipe_desc_parse(PipelineForm &pipeline) {1716char * ident;17171718skipws(); // Skip leading whitespace17191720if (_curchar != '(') {1721parse_err(SYNERR, "missing \"(\" in pipe_desc definition\n");1722return;1723}17241725do {1726next_char(); // Skip "(" or ","1727ident = get_ident(); // Grab next identifier1728if (ident == NULL) {1729parse_err(SYNERR, "keyword identifier expected at \"%c\"\n", _curchar);1730return;1731}17321733// Add the name to the list1734pipeline._stages.addName(ident);1735pipeline._stagecnt++;17361737skipws();1738} while (_curchar == ',');17391740if (_curchar != ')') {1741parse_err(SYNERR, "\")\" expected at \"%c\"\n", _curchar);1742return;1743}17441745next_char(); // Skip ")"1746if (_curchar == ';')1747next_char(); // Skip ";"1748}17491750//------------------------------pipe_class_parse--------------------------1751void ADLParser::pipe_class_parse(PipelineForm &pipeline) {1752PipeClassForm *pipe_class;1753char * ident;1754char * stage;1755char * read_or_write;1756int is_write;1757int is_read;1758OperandForm *oper;17591760skipws(); // Skip leading whitespace17611762ident = get_ident(); // Grab next identifier17631764if (ident == NULL) {1765parse_err(SYNERR, "keyword identifier expected at \"%c\"\n", _curchar);1766return;1767}17681769// Create a record for the pipe_class1770pipe_class = new PipeClassForm(ident, ++pipeline._classcnt);1771pipeline._classdict.Insert(ident, pipe_class);1772pipeline._classlist.addName(ident);17731774// Then get the operands1775skipws();1776if (_curchar != '(') {1777parse_err(SYNERR, "missing \"(\" in pipe_class definition\n");1778}1779// Parse the operand list1780else get_oplist(pipe_class->_parameters, pipe_class->_localNames);1781skipws(); // Skip leading whitespace1782// Check for block delimiter1783if ( (_curchar != '%')1784|| ( next_char(), (_curchar != '{')) ) {1785parse_err(SYNERR, "missing \"%%{\" in pipe_class definition\n");1786return;1787}1788next_char();17891790do {1791ident = get_ident(); // Grab next identifier1792if (ident == NULL) {1793parse_err(SYNERR, "keyword identifier expected at \"%c\"\n", _curchar);1794continue;1795}1796skipws();17971798if (!strcmp(ident, "fixed_latency")) {1799skipws();1800if (_curchar != '(') {1801parse_err(SYNERR, "missing \"(\" in latency definition\n");1802return;1803}1804next_char(); skipws();1805if( !isdigit(_curchar) ) {1806parse_err(SYNERR, "number expected for \"%c\" in latency definition\n", _curchar);1807return;1808}1809int fixed_latency = get_int();1810skipws();1811if (_curchar != ')') {1812parse_err(SYNERR, "missing \")\" in latency definition\n");1813return;1814}1815next_char(); skipws();1816if (_curchar != ';') {1817parse_err(SYNERR, "missing \";\" in latency definition\n");1818return;1819}18201821pipe_class->setFixedLatency(fixed_latency);1822next_char(); skipws();1823continue;1824}18251826if (!strcmp(ident, "zero_instructions") ||1827!strcmp(ident, "no_instructions")) {1828skipws();1829if (_curchar != ';') {1830parse_err(SYNERR, "missing \";\" in latency definition\n");1831return;1832}18331834pipe_class->setInstructionCount(0);1835next_char(); skipws();1836continue;1837}18381839if (!strcmp(ident, "one_instruction_with_delay_slot") ||1840!strcmp(ident, "single_instruction_with_delay_slot")) {1841skipws();1842if (_curchar != ';') {1843parse_err(SYNERR, "missing \";\" in latency definition\n");1844return;1845}18461847pipe_class->setInstructionCount(1);1848pipe_class->setBranchDelay(true);1849next_char(); skipws();1850continue;1851}18521853if (!strcmp(ident, "one_instruction") ||1854!strcmp(ident, "single_instruction")) {1855skipws();1856if (_curchar != ';') {1857parse_err(SYNERR, "missing \";\" in latency definition\n");1858return;1859}18601861pipe_class->setInstructionCount(1);1862next_char(); skipws();1863continue;1864}18651866if (!strcmp(ident, "instructions_in_first_bundle") ||1867!strcmp(ident, "instruction_count")) {1868skipws();18691870int number_of_instructions = 1;18711872if (_curchar != '(') {1873parse_err(SYNERR, "\"(\" expected at \"%c\"\n", _curchar);1874continue;1875}18761877next_char(); skipws();1878number_of_instructions = get_int();18791880skipws();1881if (_curchar != ')') {1882parse_err(SYNERR, "\")\" expected at \"%c\"\n", _curchar);1883continue;1884}18851886next_char(); skipws();1887if (_curchar != ';') {1888parse_err(SYNERR, "missing \";\" in latency definition\n");1889return;1890}18911892pipe_class->setInstructionCount(number_of_instructions);1893next_char(); skipws();1894continue;1895}18961897if (!strcmp(ident, "multiple_bundles")) {1898skipws();1899if (_curchar != ';') {1900parse_err(SYNERR, "missing \";\" after multiple bundles\n");1901return;1902}19031904pipe_class->setMultipleBundles(true);1905next_char(); skipws();1906continue;1907}19081909if (!strcmp(ident, "has_delay_slot")) {1910skipws();1911if (_curchar != ';') {1912parse_err(SYNERR, "missing \";\" after \"has_delay_slot\"\n");1913return;1914}19151916pipe_class->setBranchDelay(true);1917next_char(); skipws();1918continue;1919}19201921if (!strcmp(ident, "force_serialization")) {1922skipws();1923if (_curchar != ';') {1924parse_err(SYNERR, "missing \";\" after \"force_serialization\"\n");1925return;1926}19271928pipe_class->setForceSerialization(true);1929next_char(); skipws();1930continue;1931}19321933if (!strcmp(ident, "may_have_no_code")) {1934skipws();1935if (_curchar != ';') {1936parse_err(SYNERR, "missing \";\" after \"may_have_no_code\"\n");1937return;1938}19391940pipe_class->setMayHaveNoCode(true);1941next_char(); skipws();1942continue;1943}19441945const Form *parm = pipe_class->_localNames[ident];1946if (parm != NULL) {1947oper = parm->is_operand();1948if (oper == NULL && !parm->is_opclass()) {1949parse_err(SYNERR, "operand name expected at %s\n", ident);1950continue;1951}19521953if (_curchar != ':') {1954parse_err(SYNERR, "\":\" expected at \"%c\"\n", _curchar);1955continue;1956}1957next_char(); skipws();1958stage = get_ident();1959if (stage == NULL) {1960parse_err(SYNERR, "pipeline stage identifier expected at \"%c\"\n", _curchar);1961continue;1962}19631964skipws();1965if (_curchar != '(') {1966parse_err(SYNERR, "\"(\" expected at \"%c\"\n", _curchar);1967continue;1968}19691970next_char();1971read_or_write = get_ident();1972if (read_or_write == NULL) {1973parse_err(SYNERR, "\"read\" or \"write\" expected at \"%c\"\n", _curchar);1974continue;1975}19761977is_read = strcmp(read_or_write, "read") == 0;1978is_write = strcmp(read_or_write, "write") == 0;1979if (!is_read && !is_write) {1980parse_err(SYNERR, "\"read\" or \"write\" expected at \"%c\"\n", _curchar);1981continue;1982}19831984skipws();1985if (_curchar != ')') {1986parse_err(SYNERR, "\")\" expected at \"%c\"\n", _curchar);1987continue;1988}19891990next_char(); skipws();1991int more_instrs = 0;1992if (_curchar == '+') {1993next_char(); skipws();1994if (_curchar < '0' || _curchar > '9') {1995parse_err(SYNERR, "<number> expected at \"%c\"\n", _curchar);1996continue;1997}1998while (_curchar >= '0' && _curchar <= '9') {1999more_instrs *= 10;2000more_instrs += _curchar - '0';2001next_char();2002}2003skipws();2004}20052006PipeClassOperandForm *pipe_operand = new PipeClassOperandForm(stage, is_write, more_instrs);2007pipe_class->_localUsage.Insert(ident, pipe_operand);20082009if (_curchar == '%')2010continue;20112012if (_curchar != ';') {2013parse_err(SYNERR, "\";\" expected at \"%c\"\n", _curchar);2014continue;2015}2016next_char(); skipws();2017continue;2018}20192020// Scan for Resource Specifier2021const Form *res = pipeline._resdict[ident];2022if (res != NULL) {2023int cyclecnt = 1;2024if (_curchar != ':') {2025parse_err(SYNERR, "\":\" expected at \"%c\"\n", _curchar);2026continue;2027}2028next_char(); skipws();2029stage = get_ident();2030if (stage == NULL) {2031parse_err(SYNERR, "pipeline stage identifier expected at \"%c\"\n", _curchar);2032continue;2033}20342035skipws();2036if (_curchar == '(') {2037next_char();2038cyclecnt = get_int();20392040skipws();2041if (_curchar != ')') {2042parse_err(SYNERR, "\")\" expected at \"%c\"\n", _curchar);2043continue;2044}20452046next_char(); skipws();2047}20482049PipeClassResourceForm *resource = new PipeClassResourceForm(ident, stage, cyclecnt);2050int stagenum = pipeline._stages.index(stage);2051if (pipeline._maxcycleused < (stagenum+cyclecnt))2052pipeline._maxcycleused = (stagenum+cyclecnt);2053pipe_class->_resUsage.addForm(resource);20542055if (_curchar == '%')2056continue;20572058if (_curchar != ';') {2059parse_err(SYNERR, "\";\" expected at \"%c\"\n", _curchar);2060continue;2061}2062next_char(); skipws();2063continue;2064}20652066parse_err(SYNERR, "resource expected at \"%s\"\n", ident);2067return;2068} while(_curchar != '%');20692070next_char();2071if (_curchar != '}') {2072parse_err(SYNERR, "missing \"%%}\" in pipe_class definition\n");2073return;2074}20752076next_char();2077}20782079//------------------------------peep_parse-------------------------------------2080void ADLParser::peep_parse(void) {2081Peephole *peep; // Pointer to current peephole rule form2082char *desc = NULL; // String representation of rule20832084skipws(); // Skip leading whitespace20852086peep = new Peephole(); // Build new Peephole object2087// Check for open block sequence2088skipws(); // Skip leading whitespace2089if (_curchar == '%' && *(_ptr+1) == '{') {2090next_char(); next_char(); // Skip "%{"2091skipws();2092while (_curchar != '%' && *(_ptr+1) != '}') {2093char *token = get_ident();2094if (token == NULL) {2095parse_err(SYNERR, "missing identifier inside peephole rule.\n");2096return;2097}2098// check for legal subsections of peephole rule2099if (strcmp(token,"peepmatch")==0) {2100peep_match_parse(*peep); }2101else if (strcmp(token,"peepconstraint")==0) {2102peep_constraint_parse(*peep); }2103else if (strcmp(token,"peepreplace")==0) {2104peep_replace_parse(*peep); }2105else {2106parse_err(SYNERR, "expected peepmatch, peepconstraint, or peepreplace for identifier %s.\n", token);2107}2108skipws();2109}2110}2111else {2112parse_err(SYNERR, "Missing %%{ ... %%} block after peephole keyword.\n");2113return;2114}2115next_char(); // Skip past '%'2116next_char(); // Skip past '}'2117}21182119// ******************** Private Level 2 Parse Functions ********************2120//------------------------------constraint_parse------------------------------2121Constraint *ADLParser::constraint_parse(void) {2122char *func;2123char *arg;21242125// Check for constraint expression2126skipws();2127if (_curchar != '(') {2128parse_err(SYNERR, "missing constraint expression, (...)\n");2129return NULL;2130}2131next_char(); // Skip past '('21322133// Get constraint function2134skipws();2135func = get_ident();2136if (func == NULL) {2137parse_err(SYNERR, "missing function in constraint expression.\n");2138return NULL;2139}2140if (strcmp(func,"ALLOC_IN_RC")==02141|| strcmp(func,"IS_R_CLASS")==0) {2142// Check for '(' before argument2143skipws();2144if (_curchar != '(') {2145parse_err(SYNERR, "missing '(' for constraint function's argument.\n");2146return NULL;2147}2148next_char();21492150// Get it's argument2151skipws();2152arg = get_ident();2153if (arg == NULL) {2154parse_err(SYNERR, "missing argument for constraint function %s\n",func);2155return NULL;2156}2157// Check for ')' after argument2158skipws();2159if (_curchar != ')') {2160parse_err(SYNERR, "missing ')' after constraint function argument %s\n",arg);2161return NULL;2162}2163next_char();2164} else {2165parse_err(SYNERR, "Invalid constraint function %s\n",func);2166return NULL;2167}21682169// Check for closing paren and ';'2170skipws();2171if (_curchar != ')') {2172parse_err(SYNERR, "Missing ')' for constraint function %s\n",func);2173return NULL;2174}2175next_char();2176skipws();2177if (_curchar != ';') {2178parse_err(SYNERR, "Missing ';' after constraint.\n");2179return NULL;2180}2181next_char();21822183// Create new "Constraint"2184Constraint *constraint = new Constraint(func,arg);2185return constraint;2186}21872188//------------------------------constr_parse-----------------------------------2189ConstructRule *ADLParser::construct_parse(void) {2190return NULL;2191}219221932194//------------------------------reg_def_parse----------------------------------2195void ADLParser::reg_def_parse(void) {2196char *rname; // Name of register being defined21972198// Get register name2199skipws(); // Skip whitespace2200rname = get_ident();2201if (rname == NULL) {2202parse_err(SYNERR, "missing register name after reg_def\n");2203return;2204}22052206// Check for definition of register calling convention (save on call, ...),2207// register save type, and register encoding value.2208skipws();2209char *callconv = NULL;2210char *c_conv = NULL;2211char *idealtype = NULL;2212char *encoding = NULL;2213char *concrete = NULL;2214if (_curchar == '(') {2215next_char();2216callconv = get_ident();2217// Parse the internal calling convention, must be NS, SOC, SOE, or AS.2218if (callconv == NULL) {2219parse_err(SYNERR, "missing register calling convention value\n");2220return;2221}2222if(strcmp(callconv, "SOC") && strcmp(callconv,"SOE") &&2223strcmp(callconv, "NS") && strcmp(callconv, "AS")) {2224parse_err(SYNERR, "invalid value for register calling convention\n");2225}2226skipws();2227if (_curchar != ',') {2228parse_err(SYNERR, "missing comma in register definition statement\n");2229return;2230}2231next_char();22322233// Parse the native calling convention, must be NS, SOC, SOE, AS2234c_conv = get_ident();2235if (c_conv == NULL) {2236parse_err(SYNERR, "missing register native calling convention value\n");2237return;2238}2239if(strcmp(c_conv, "SOC") && strcmp(c_conv,"SOE") &&2240strcmp(c_conv, "NS") && strcmp(c_conv, "AS")) {2241parse_err(SYNERR, "invalid value for register calling convention\n");2242}2243skipws();2244if (_curchar != ',') {2245parse_err(SYNERR, "missing comma in register definition statement\n");2246return;2247}2248next_char();2249skipws();22502251// Parse the ideal save type2252idealtype = get_ident();2253if (idealtype == NULL) {2254parse_err(SYNERR, "missing register save type value\n");2255return;2256}2257skipws();2258if (_curchar != ',') {2259parse_err(SYNERR, "missing comma in register definition statement\n");2260return;2261}2262next_char();2263skipws();22642265// Parse the encoding value2266encoding = get_expr("encoding", ",");2267if (encoding == NULL) {2268parse_err(SYNERR, "missing register encoding value\n");2269return;2270}2271trim(encoding);2272if (_curchar != ',') {2273parse_err(SYNERR, "missing comma in register definition statement\n");2274return;2275}2276next_char();2277skipws();2278// Parse the concrete name type2279// concrete = get_ident();2280concrete = get_expr("concrete", ")");2281if (concrete == NULL) {2282parse_err(SYNERR, "missing vm register name value\n");2283return;2284}22852286if (_curchar != ')') {2287parse_err(SYNERR, "missing ')' in register definition statement\n");2288return;2289}2290next_char();2291}22922293// Check for closing ';'2294skipws();2295if (_curchar != ';') {2296parse_err(SYNERR, "missing ';' after reg_def\n");2297return;2298}2299next_char(); // move past ';'23002301// Debug Stuff2302if (_AD._adl_debug > 1) {2303fprintf(stderr,"Register Definition: %s ( %s, %s %s )\n", rname,2304(callconv ? callconv : ""), (c_conv ? c_conv : ""), concrete);2305}23062307// Record new register definition.2308_AD._register->addRegDef(rname, callconv, c_conv, idealtype, encoding, concrete);2309return;2310}23112312//------------------------------reg_class_parse--------------------------------2313void ADLParser::reg_class_parse(void) {2314char *cname; // Name of register class being defined23152316// Get register class name2317skipws(); // Skip leading whitespace2318cname = get_ident();2319if (cname == NULL) {2320parse_err(SYNERR, "missing register class name after 'reg_class'\n");2321return;2322}2323// Debug Stuff2324if (_AD._adl_debug >1) fprintf(stderr,"Register Class: %s\n", cname);23252326skipws();2327if (_curchar == '(') {2328// A register list is defined for the register class.2329// Collect registers into a generic RegClass register class.2330RegClass* reg_class = _AD._register->addRegClass<RegClass>(cname);23312332next_char(); // Skip '('2333skipws();2334while (_curchar != ')') {2335char *rname = get_ident();2336if (rname==NULL) {2337parse_err(SYNERR, "missing identifier inside reg_class list.\n");2338return;2339}2340RegDef *regDef = _AD._register->getRegDef(rname);2341if (!regDef) {2342parse_err(SEMERR, "unknown identifier %s inside reg_class list.\n", rname);2343} else {2344reg_class->addReg(regDef); // add regDef to regClass2345}23462347// Check for ',' and position to next token.2348skipws();2349if (_curchar == ',') {2350next_char(); // Skip trailing ','2351skipws();2352}2353}2354next_char(); // Skip closing ')'2355} else if (_curchar == '%') {2356// A code snippet is defined for the register class.2357// Collect the code snippet into a CodeSnippetRegClass register class.2358CodeSnippetRegClass* reg_class = _AD._register->addRegClass<CodeSnippetRegClass>(cname);2359char *code = find_cpp_block("reg class");2360if (code == NULL) {2361parse_err(SYNERR, "missing code declaration for reg class.\n");2362return;2363}2364reg_class->set_code_snippet(code);2365return;2366}23672368// Check for terminating ';'2369skipws();2370if (_curchar != ';') {2371parse_err(SYNERR, "missing ';' at end of reg_class definition.\n");2372return;2373}2374next_char(); // Skip trailing ';'23752376// Check RegClass size, must be <= 32 registers in class.23772378return;2379}23802381//------------------------------reg_class_dynamic_parse------------------------2382void ADLParser::reg_class_dynamic_parse(void) {2383char *cname; // Name of dynamic register class being defined23842385// Get register class name2386skipws();2387cname = get_ident();2388if (cname == NULL) {2389parse_err(SYNERR, "missing dynamic register class name after 'reg_class_dynamic'\n");2390return;2391}23922393if (_AD._adl_debug > 1) {2394fprintf(stdout, "Dynamic Register Class: %s\n", cname);2395}23962397skipws();2398if (_curchar != '(') {2399parse_err(SYNERR, "missing '(' at the beginning of reg_class_dynamic definition\n");2400return;2401}2402next_char();2403skipws();24042405// Collect two register classes and the C++ code representing the condition code used to2406// select between the two classes into a ConditionalRegClass register class.2407ConditionalRegClass* reg_class = _AD._register->addRegClass<ConditionalRegClass>(cname);2408int i;2409for (i = 0; i < 2; i++) {2410char* name = get_ident();2411if (name == NULL) {2412parse_err(SYNERR, "missing class identifier inside reg_class_dynamic list.\n");2413return;2414}2415RegClass* rc = _AD._register->getRegClass(name);2416if (rc == NULL) {2417parse_err(SEMERR, "unknown identifier %s inside reg_class_dynamic list.\n", name);2418} else {2419reg_class->set_rclass_at_index(i, rc);2420}24212422skipws();2423if (_curchar == ',') {2424next_char();2425skipws();2426} else {2427parse_err(SYNERR, "missing separator ',' inside reg_class_dynamic list.\n");2428}2429}24302431// Collect the condition code.2432skipws();2433if (_curchar == '%') {2434char* code = find_cpp_block("reg class dynamic");2435if (code == NULL) {2436parse_err(SYNERR, "missing code declaration for reg_class_dynamic.\n");2437return;2438}2439reg_class->set_condition_code(code);2440} else {2441parse_err(SYNERR, "missing %% at the beginning of code block in reg_class_dynamic definition\n");2442return;2443}24442445skipws();2446if (_curchar != ')') {2447parse_err(SYNERR, "missing ')' at the end of reg_class_dynamic definition\n");2448return;2449}2450next_char();24512452skipws();2453if (_curchar != ';') {2454parse_err(SYNERR, "missing ';' at the end of reg_class_dynamic definition.\n");2455return;2456}2457next_char(); // Skip trailing ';'24582459return;2460}24612462//------------------------------alloc_class_parse------------------------------2463void ADLParser::alloc_class_parse(void) {2464char *name; // Name of allocation class being defined24652466// Get allocation class name2467skipws(); // Skip leading whitespace2468name = get_ident();2469if (name == NULL) {2470parse_err(SYNERR, "missing allocation class name after 'reg_class'\n");2471return;2472}2473// Debug Stuff2474if (_AD._adl_debug >1) fprintf(stderr,"Allocation Class: %s\n", name);24752476AllocClass *alloc_class = _AD._register->addAllocClass(name);24772478// Collect registers in class2479skipws();2480if (_curchar == '(') {2481next_char(); // Skip '('2482skipws();2483while (_curchar != ')') {2484char *rname = get_ident();2485if (rname==NULL) {2486parse_err(SYNERR, "missing identifier inside reg_class list.\n");2487return;2488}2489// Check if name is a RegDef2490RegDef *regDef = _AD._register->getRegDef(rname);2491if (regDef) {2492alloc_class->addReg(regDef); // add regDef to allocClass2493} else {24942495// name must be a RegDef or a RegClass2496parse_err(SYNERR, "name %s should be a previously defined reg_def.\n", rname);2497return;2498}24992500// Check for ',' and position to next token.2501skipws();2502if (_curchar == ',') {2503next_char(); // Skip trailing ','2504skipws();2505}2506}2507next_char(); // Skip closing ')'2508}25092510// Check for terminating ';'2511skipws();2512if (_curchar != ';') {2513parse_err(SYNERR, "missing ';' at end of reg_class definition.\n");2514return;2515}2516next_char(); // Skip trailing ';'25172518return;2519}25202521//------------------------------peep_match_child_parse-------------------------2522InstructForm *ADLParser::peep_match_child_parse(PeepMatch &match, int parent, int &position, int input){2523char *token = NULL;2524int lparen = 0; // keep track of parenthesis nesting depth2525int rparen = 0; // position of instruction at this depth2526InstructForm *inst_seen = NULL;25272528// Walk the match tree,2529// Record <parent, position, instruction name, input position>2530while ( lparen >= rparen ) {2531skipws();2532// Left paren signals start of an input, collect with recursive call2533if (_curchar == '(') {2534++lparen;2535next_char();2536( void ) peep_match_child_parse(match, parent, position, rparen);2537}2538// Right paren signals end of an input, may be more2539else if (_curchar == ')') {2540++rparen;2541if( rparen == lparen ) { // IF rparen matches an lparen I've seen2542next_char(); // move past ')'2543} else { // ELSE leave ')' for parent2544assert( rparen == lparen + 1, "Should only see one extra ')'");2545// if an instruction was not specified for this paren-pair2546if( ! inst_seen ) { // record signal entry2547match.add_instruction( parent, position, NameList::_signal, input );2548++position;2549}2550// ++input; // TEMPORARY2551return inst_seen;2552}2553}2554// if no parens, then check for instruction name2555// This instruction is the parent of a sub-tree2556else if ((token = get_ident_dup()) != NULL) {2557const Form *form = _AD._globalNames[token];2558if (form) {2559InstructForm *inst = form->is_instruction();2560// Record the first instruction at this level2561if( inst_seen == NULL ) {2562inst_seen = inst;2563}2564if (inst) {2565match.add_instruction( parent, position, token, input );2566parent = position;2567++position;2568} else {2569parse_err(SYNERR, "instruction name expected at identifier %s.\n",2570token);2571return inst_seen;2572}2573}2574else {2575parse_err(SYNERR, "missing identifier in peepmatch rule.\n");2576return NULL;2577}2578}2579else {2580parse_err(SYNERR, "missing identifier in peepmatch rule.\n");2581return NULL;2582}25832584} // end while25852586assert( false, "ShouldNotReachHere();");2587return NULL;2588}25892590//------------------------------peep_match_parse-------------------------------2591// Syntax for a peepmatch rule2592//2593// peepmatch ( root_instr_name [(instruction subtree)] [,(instruction subtree)]* );2594//2595void ADLParser::peep_match_parse(Peephole &peep) {25962597skipws();2598// Check the structure of the rule2599// Check for open paren2600if (_curchar != '(') {2601parse_err(SYNERR, "missing '(' at start of peepmatch rule.\n");2602return;2603}2604next_char(); // skip '('26052606// Construct PeepMatch and parse the peepmatch rule.2607PeepMatch *match = new PeepMatch(_ptr);2608int parent = -1; // parent of root2609int position = 0; // zero-based positions2610int input = 0; // input position in parent's operands2611InstructForm *root= peep_match_child_parse( *match, parent, position, input);2612if( root == NULL ) {2613parse_err(SYNERR, "missing instruction-name at start of peepmatch.\n");2614return;2615}26162617if( _curchar != ')' ) {2618parse_err(SYNERR, "missing ')' at end of peepmatch.\n");2619return;2620}2621next_char(); // skip ')'26222623// Check for closing semicolon2624skipws();2625if( _curchar != ';' ) {2626parse_err(SYNERR, "missing ';' at end of peepmatch.\n");2627return;2628}2629next_char(); // skip ';'26302631// Store match into peep, and store peep into instruction2632peep.add_match(match);2633root->append_peephole(&peep);2634}26352636//------------------------------peep_constraint_parse--------------------------2637// Syntax for a peepconstraint rule2638// A parenthesized list of relations between operands in peepmatch subtree2639//2640// peepconstraint %{2641// (instruction_number.operand_name2642// relational_op2643// instruction_number.operand_name OR register_name2644// [, ...] );2645//2646// // instruction numbers are zero-based using topological order in peepmatch2647//2648void ADLParser::peep_constraint_parse(Peephole &peep) {26492650skipws();2651// Check the structure of the rule2652// Check for open paren2653if (_curchar != '(') {2654parse_err(SYNERR, "missing '(' at start of peepconstraint rule.\n");2655return;2656}2657else {2658next_char(); // Skip '('2659}26602661// Check for a constraint2662skipws();2663while( _curchar != ')' ) {2664// Get information on the left instruction and its operand2665// left-instructions's number2666int left_inst = get_int();2667// Left-instruction's operand2668skipws();2669if( _curchar != '.' ) {2670parse_err(SYNERR, "missing '.' in peepconstraint after instruction number.\n");2671return;2672}2673next_char(); // Skip '.'2674char *left_op = get_ident_dup();26752676skipws();2677// Collect relational operator2678char *relation = get_relation_dup();26792680skipws();2681// Get information on the right instruction and its operand2682int right_inst; // Right-instructions's number2683if( isdigit(_curchar) ) {2684right_inst = get_int();2685// Right-instruction's operand2686skipws();2687if( _curchar != '.' ) {2688parse_err(SYNERR, "missing '.' in peepconstraint after instruction number.\n");2689return;2690}2691next_char(); // Skip '.'2692} else {2693right_inst = -1; // Flag as being a register constraint2694}26952696char *right_op = get_ident_dup();26972698// Construct the next PeepConstraint2699PeepConstraint *constraint = new PeepConstraint( left_inst, left_op,2700relation,2701right_inst, right_op );2702// And append it to the list for this peephole rule2703peep.append_constraint( constraint );27042705// Check for another constraint, or end of rule2706skipws();2707if( _curchar == ',' ) {2708next_char(); // Skip ','2709skipws();2710}2711else if( _curchar != ')' ) {2712parse_err(SYNERR, "expected ',' or ')' after peephole constraint.\n");2713return;2714}2715} // end while( processing constraints )2716next_char(); // Skip ')'27172718// Check for terminating ';'2719skipws();2720if (_curchar != ';') {2721parse_err(SYNERR, "missing ';' at end of peepconstraint.\n");2722return;2723}2724next_char(); // Skip trailing ';'2725}272627272728//------------------------------peep_replace_parse-----------------------------2729// Syntax for a peepreplace rule2730// root instruction name followed by a2731// parenthesized list of whitespace separated instruction.operand specifiers2732//2733// peepreplace ( instr_name ( [instruction_number.operand_name]* ) );2734//2735//2736void ADLParser::peep_replace_parse(Peephole &peep) {2737int lparen = 0; // keep track of parenthesis nesting depth2738int rparen = 0; // keep track of parenthesis nesting depth2739int icount = 0; // count of instructions in rule for naming2740char *str = NULL;2741char *token = NULL;27422743skipws();2744// Check for open paren2745if (_curchar != '(') {2746parse_err(SYNERR, "missing '(' at start of peepreplace rule.\n");2747return;2748}2749else {2750lparen++;2751next_char();2752}27532754// Check for root instruction2755char *inst = get_ident_dup();2756const Form *form = _AD._globalNames[inst];2757if( form == NULL || form->is_instruction() == NULL ) {2758parse_err(SYNERR, "Instruction name expected at start of peepreplace.\n");2759return;2760}27612762// Store string representation of rule into replace2763PeepReplace *replace = new PeepReplace(str);2764replace->add_instruction( inst );27652766skipws();2767// Start of root's operand-list2768if (_curchar != '(') {2769parse_err(SYNERR, "missing '(' at peepreplace root's operand-list.\n");2770return;2771}2772else {2773lparen++;2774next_char();2775}27762777skipws();2778// Get the list of operands2779while( _curchar != ')' ) {2780// Get information on an instruction and its operand2781// instructions's number2782int inst_num = get_int();2783// Left-instruction's operand2784skipws();2785if( _curchar != '.' ) {2786parse_err(SYNERR, "missing '.' in peepreplace after instruction number.\n");2787return;2788}2789next_char(); // Skip '.'2790char *inst_op = get_ident_dup();2791if( inst_op == NULL ) {2792parse_err(SYNERR, "missing operand identifier in peepreplace.\n");2793return;2794}27952796// Record this operand's position in peepmatch2797replace->add_operand( inst_num, inst_op );2798skipws();2799}28002801// Check for the end of operands list2802skipws();2803assert( _curchar == ')', "While loop should have advanced to ')'.");2804next_char(); // Skip ')'28052806skipws();2807// Check for end of peepreplace2808if( _curchar != ')' ) {2809parse_err(SYNERR, "missing ')' at end of peepmatch.\n");2810parse_err(SYNERR, "Support one replacement instruction.\n");2811return;2812}2813next_char(); // Skip ')'28142815// Check for closing semicolon2816skipws();2817if( _curchar != ';' ) {2818parse_err(SYNERR, "missing ';' at end of peepreplace.\n");2819return;2820}2821next_char(); // skip ';'28222823// Store replace into peep2824peep.add_replace( replace );2825}28262827//------------------------------pred_parse-------------------------------------2828Predicate *ADLParser::pred_parse(void) {2829Predicate *predicate; // Predicate class for operand2830char *rule = NULL; // String representation of predicate28312832skipws(); // Skip leading whitespace2833int line = linenum();2834if ( (rule = get_paren_expr("pred expression", true)) == NULL ) {2835parse_err(SYNERR, "incorrect or missing expression for 'predicate'\n");2836return NULL;2837}2838// Debug Stuff2839if (_AD._adl_debug > 1) fprintf(stderr,"Predicate: %s\n", rule);2840if (_curchar != ';') {2841parse_err(SYNERR, "missing ';' in predicate definition\n");2842return NULL;2843}2844next_char(); // Point after the terminator28452846predicate = new Predicate(rule); // Build new predicate object2847skipws();2848return predicate;2849}285028512852//------------------------------ins_encode_parse_block-------------------------2853// Parse the block form of ins_encode. See ins_encode_parse for more details2854void ADLParser::ins_encode_parse_block(InstructForm& inst) {2855// Create a new encoding name based on the name of the instruction2856// definition, which should be unique.2857const char* prefix = "__ins_encode_";2858char* ec_name = (char*) malloc(strlen(inst._ident) + strlen(prefix) + 1);2859sprintf(ec_name, "%s%s", prefix, inst._ident);28602861assert(_AD._encode->encClass(ec_name) == NULL, "shouldn't already exist");2862EncClass* encoding = _AD._encode->add_EncClass(ec_name);2863encoding->_linenum = linenum();28642865// synthesize the arguments list for the enc_class from the2866// arguments to the instruct definition.2867const char* param = NULL;2868inst._parameters.reset();2869while ((param = inst._parameters.iter()) != NULL) {2870OpClassForm* opForm = inst._localNames[param]->is_opclass();2871assert(opForm != NULL, "sanity");2872encoding->add_parameter(opForm->_ident, param);2873}28742875if (!inst._is_postalloc_expand) {2876// Define a MacroAssembler instance for use by the encoding. The2877// name is chosen to match the __ idiom used for assembly in other2878// parts of hotspot and assumes the existence of the standard2879// #define __ _masm.2880encoding->add_code(" MacroAssembler _masm(&cbuf);\n");2881}28822883// Parse the following %{ }% block2884ins_encode_parse_block_impl(inst, encoding, ec_name);28852886// Build an encoding rule which invokes the encoding rule we just2887// created, passing all arguments that we received.2888InsEncode* encrule = new InsEncode(); // Encode class for instruction2889NameAndList* params = encrule->add_encode(ec_name);2890inst._parameters.reset();2891while ((param = inst._parameters.iter()) != NULL) {2892params->add_entry(param);2893}28942895// Check for duplicate ins_encode sections after parsing the block2896// so that parsing can continue and find any other errors.2897if (inst._insencode != NULL) {2898parse_err(SYNERR, "Multiple ins_encode sections defined\n");2899return;2900}29012902// Set encode class of this instruction.2903inst._insencode = encrule;2904}290529062907void ADLParser::ins_encode_parse_block_impl(InstructForm& inst, EncClass* encoding, char* ec_name) {2908skipws_no_preproc(); // Skip leading whitespace2909// Prepend location descriptor, for debugging; cf. ADLParser::find_cpp_block2910if (_AD._adlocation_debug) {2911encoding->add_code(get_line_string());2912}29132914// Collect the parts of the encode description2915// (1) strings that are passed through to output2916// (2) replacement/substitution variable, preceeded by a '$'2917while ((_curchar != '%') && (*(_ptr+1) != '}')) {29182919// (1)2920// Check if there is a string to pass through to output2921char *start = _ptr; // Record start of the next string2922while ((_curchar != '$') && ((_curchar != '%') || (*(_ptr+1) != '}')) ) {2923// If at the start of a comment, skip past it2924if( (_curchar == '/') && ((*(_ptr+1) == '/') || (*(_ptr+1) == '*')) ) {2925skipws_no_preproc();2926} else {2927// ELSE advance to the next character, or start of the next line2928next_char_or_line();2929}2930}2931// If a string was found, terminate it and record in EncClass2932if (start != _ptr) {2933*_ptr = '\0'; // Terminate the string2934encoding->add_code(start);2935}29362937// (2)2938// If we are at a replacement variable,2939// copy it and record in EncClass2940if (_curchar == '$') {2941// Found replacement Variable2942char* rep_var = get_rep_var_ident_dup();29432944// Add flag to _strings list indicating we should check _rep_vars2945encoding->add_rep_var(rep_var);29462947skipws();29482949// Check if this instruct is a MachConstantNode.2950if (strcmp(rep_var, "constanttablebase") == 0) {2951// This instruct is a MachConstantNode.2952inst.set_needs_constant_base(true);2953if (strncmp("MachCall", inst.mach_base_class(_globalNames), strlen("MachCall")) != 0 ) {2954inst.set_is_mach_constant(true);2955}29562957if (_curchar == '(') {2958parse_err(SYNERR, "constanttablebase in instruct %s cannot have an argument "2959"(only constantaddress and constantoffset)", ec_name);2960return;2961}2962}2963else if ((strcmp(rep_var, "constantaddress") == 0) ||2964(strcmp(rep_var, "constantoffset") == 0)) {2965// This instruct is a MachConstantNode.2966inst.set_is_mach_constant(true);29672968// If the constant keyword has an argument, parse it.2969if (_curchar == '(') constant_parse(inst);2970}2971}2972} // end while part of format description2973next_char(); // Skip '%'2974next_char(); // Skip '}'29752976skipws();29772978if (_AD._adlocation_debug) {2979encoding->add_code(end_line_marker());2980}29812982// Debug Stuff2983if (_AD._adl_debug > 1) fprintf(stderr, "EncodingClass Form: %s\n", ec_name);2984}298529862987//------------------------------ins_encode_parse-------------------------------2988// Encode rules have the form2989// ins_encode( encode_class_name(parameter_list), ... );2990//2991// The "encode_class_name" must be defined in the encode section2992// The parameter list contains $names that are locals.2993//2994// Alternatively it can be written like this:2995//2996// ins_encode %{2997// ... // body2998// %}2999//3000// which synthesizes a new encoding class taking the same arguments as3001// the InstructForm, and automatically prefixes the definition with:3002//3003// MacroAssembler masm(&cbuf);\n");3004//3005// making it more compact to take advantage of the MacroAssembler and3006// placing the assembly closer to it's use by instructions.3007void ADLParser::ins_encode_parse(InstructForm& inst) {30083009// Parse encode class name3010skipws(); // Skip whitespace3011if (_curchar != '(') {3012// Check for ins_encode %{ form3013if ((_curchar == '%') && (*(_ptr+1) == '{')) {3014next_char(); // Skip '%'3015next_char(); // Skip '{'30163017// Parse the block form of ins_encode3018ins_encode_parse_block(inst);3019return;3020}30213022parse_err(SYNERR, "missing '%%{' or '(' in ins_encode definition\n");3023return;3024}3025next_char(); // move past '('3026skipws();30273028InsEncode *encrule = new InsEncode(); // Encode class for instruction3029encrule->_linenum = linenum();3030char *ec_name = NULL; // String representation of encode rule3031// identifier is optional.3032while (_curchar != ')') {3033ec_name = get_ident();3034if (ec_name == NULL) {3035parse_err(SYNERR, "Invalid encode class name after 'ins_encode('.\n");3036return;3037}3038// Check that encoding is defined in the encode section3039EncClass *encode_class = _AD._encode->encClass(ec_name);3040if (encode_class == NULL) {3041// Like to defer checking these till later...3042// parse_err(WARN, "Using an undefined encode class '%s' in 'ins_encode'.\n", ec_name);3043}30443045// Get list for encode method's parameters3046NameAndList *params = encrule->add_encode(ec_name);30473048// Parse the parameters to this encode method.3049skipws();3050if ( _curchar == '(' ) {3051next_char(); // move past '(' for parameters30523053// Parse the encode method's parameters3054while (_curchar != ')') {3055char *param = get_ident_or_literal_constant("encoding operand");3056if ( param != NULL ) {30573058// Check if this instruct is a MachConstantNode.3059if (strcmp(param, "constanttablebase") == 0) {3060// This instruct is a MachConstantNode.3061inst.set_needs_constant_base(true);3062if (strncmp("MachCall", inst.mach_base_class(_globalNames), strlen("MachCall")) != 0 ) {3063inst.set_is_mach_constant(true);3064}30653066if (_curchar == '(') {3067parse_err(SYNERR, "constanttablebase in instruct %s cannot have an argument "3068"(only constantaddress and constantoffset)", ec_name);3069return;3070}3071} else {3072// Found a parameter:3073// Check it is a local name, add it to the list, then check for more3074// New: allow hex constants as parameters to an encode method.3075// New: allow parenthesized expressions as parameters.3076// New: allow "primary", "secondary", "tertiary" as parameters.3077// New: allow user-defined register name as parameter3078if ( (inst._localNames[param] == NULL) &&3079!ADLParser::is_literal_constant(param) &&3080(Opcode::as_opcode_type(param) == Opcode::NOT_AN_OPCODE) &&3081((_AD._register == NULL ) || (_AD._register->getRegDef(param) == NULL)) ) {3082parse_err(SYNERR, "Using non-locally defined parameter %s for encoding %s.\n", param, ec_name);3083return;3084}3085}3086params->add_entry(param);30873088skipws();3089if (_curchar == ',' ) {3090// More parameters to come3091next_char(); // move past ',' between parameters3092skipws(); // Skip to next parameter3093}3094else if (_curchar == ')') {3095// Done with parameter list3096}3097else {3098// Only ',' or ')' are valid after a parameter name3099parse_err(SYNERR, "expected ',' or ')' after parameter %s.\n",3100ec_name);3101return;3102}31033104} else {3105skipws();3106// Did not find a parameter3107if (_curchar == ',') {3108parse_err(SYNERR, "Expected encode parameter before ',' in encoding %s.\n", ec_name);3109return;3110}3111if (_curchar != ')') {3112parse_err(SYNERR, "Expected ')' after encode parameters.\n");3113return;3114}3115}3116} // WHILE loop collecting parameters3117next_char(); // move past ')' at end of parameters3118} // done with parameter list for encoding31193120// Check for ',' or ')' after encoding3121skipws(); // move to character after parameters3122if ( _curchar == ',' ) {3123// Found a ','3124next_char(); // move past ',' between encode methods3125skipws();3126}3127else if ( _curchar != ')' ) {3128// If not a ',' then only a ')' is allowed3129parse_err(SYNERR, "Expected ')' after encoding %s.\n", ec_name);3130return;3131}31323133// Check for ',' separating parameters3134// if ( _curchar != ',' && _curchar != ')' ) {3135// parse_err(SYNERR, "expected ',' or ')' after encode method inside ins_encode.\n");3136// return NULL;3137// }31383139} // done parsing ins_encode methods and their parameters3140if (_curchar != ')') {3141parse_err(SYNERR, "Missing ')' at end of ins_encode description.\n");3142return;3143}3144next_char(); // move past ')'3145skipws(); // Skip leading whitespace31463147if ( _curchar != ';' ) {3148parse_err(SYNERR, "Missing ';' at end of ins_encode.\n");3149return;3150}3151next_char(); // move past ';'3152skipws(); // be friendly to oper_parse()31533154// Check for duplicate ins_encode sections after parsing the block3155// so that parsing can continue and find any other errors.3156if (inst._insencode != NULL) {3157parse_err(SYNERR, "Multiple ins_encode sections defined\n");3158return;3159}31603161// Debug Stuff3162if (_AD._adl_debug > 1) fprintf(stderr,"Instruction Encode: %s\n", ec_name);31633164// Set encode class of this instruction.3165inst._insencode = encrule;3166}31673168//------------------------------postalloc_expand_parse---------------------------3169// Encode rules have the form3170// postalloc_expand( encode_class_name(parameter_list) );3171//3172// The "encode_class_name" must be defined in the encode section.3173// The parameter list contains $names that are locals.3174//3175// This is just a copy of ins_encode_parse without the loop.3176void ADLParser::postalloc_expand_parse(InstructForm& inst) {3177inst._is_postalloc_expand = true;31783179// Parse encode class name.3180skipws(); // Skip whitespace.3181if (_curchar != '(') {3182// Check for postalloc_expand %{ form3183if ((_curchar == '%') && (*(_ptr+1) == '{')) {3184next_char(); // Skip '%'3185next_char(); // Skip '{'31863187// Parse the block form of postalloc_expand3188ins_encode_parse_block(inst);3189return;3190}31913192parse_err(SYNERR, "missing '(' in postalloc_expand definition\n");3193return;3194}3195next_char(); // Move past '('.3196skipws();31973198InsEncode *encrule = new InsEncode(); // Encode class for instruction.3199encrule->_linenum = linenum();3200char *ec_name = NULL; // String representation of encode rule.3201// identifier is optional.3202if (_curchar != ')') {3203ec_name = get_ident();3204if (ec_name == NULL) {3205parse_err(SYNERR, "Invalid postalloc_expand class name after 'postalloc_expand('.\n");3206return;3207}3208// Check that encoding is defined in the encode section.3209EncClass *encode_class = _AD._encode->encClass(ec_name);32103211// Get list for encode method's parameters3212NameAndList *params = encrule->add_encode(ec_name);32133214// Parse the parameters to this encode method.3215skipws();3216if (_curchar == '(') {3217next_char(); // Move past '(' for parameters.32183219// Parse the encode method's parameters.3220while (_curchar != ')') {3221char *param = get_ident_or_literal_constant("encoding operand");3222if (param != NULL) {3223// Found a parameter:32243225// First check for constant table support.32263227// Check if this instruct is a MachConstantNode.3228if (strcmp(param, "constanttablebase") == 0) {3229// This instruct is a MachConstantNode.3230inst.set_needs_constant_base(true);3231if (strncmp("MachCall", inst.mach_base_class(_globalNames), strlen("MachCall")) != 0 ) {3232inst.set_is_mach_constant(true);3233}32343235if (_curchar == '(') {3236parse_err(SYNERR, "constanttablebase in instruct %s cannot have an argument "3237"(only constantaddress and constantoffset)", ec_name);3238return;3239}3240}3241else if ((strcmp(param, "constantaddress") == 0) ||3242(strcmp(param, "constantoffset") == 0)) {3243// This instruct is a MachConstantNode.3244inst.set_is_mach_constant(true);32453246// If the constant keyword has an argument, parse it.3247if (_curchar == '(') constant_parse(inst);3248}32493250// Else check it is a local name, add it to the list, then check for more.3251// New: allow hex constants as parameters to an encode method.3252// New: allow parenthesized expressions as parameters.3253// New: allow "primary", "secondary", "tertiary" as parameters.3254// New: allow user-defined register name as parameter.3255else if ((inst._localNames[param] == NULL) &&3256!ADLParser::is_literal_constant(param) &&3257(Opcode::as_opcode_type(param) == Opcode::NOT_AN_OPCODE) &&3258((_AD._register == NULL) || (_AD._register->getRegDef(param) == NULL))) {3259parse_err(SYNERR, "Using non-locally defined parameter %s for encoding %s.\n", param, ec_name);3260return;3261}3262params->add_entry(param);32633264skipws();3265if (_curchar == ',') {3266// More parameters to come.3267next_char(); // Move past ',' between parameters.3268skipws(); // Skip to next parameter.3269} else if (_curchar == ')') {3270// Done with parameter list3271} else {3272// Only ',' or ')' are valid after a parameter name.3273parse_err(SYNERR, "expected ',' or ')' after parameter %s.\n", ec_name);3274return;3275}32763277} else {3278skipws();3279// Did not find a parameter.3280if (_curchar == ',') {3281parse_err(SYNERR, "Expected encode parameter before ',' in postalloc_expand %s.\n", ec_name);3282return;3283}3284if (_curchar != ')') {3285parse_err(SYNERR, "Expected ')' after postalloc_expand parameters.\n");3286return;3287}3288}3289} // WHILE loop collecting parameters.3290next_char(); // Move past ')' at end of parameters.3291} // Done with parameter list for encoding.32923293// Check for ',' or ')' after encoding.3294skipws(); // Move to character after parameters.3295if (_curchar != ')') {3296// Only a ')' is allowed.3297parse_err(SYNERR, "Expected ')' after postalloc_expand %s.\n", ec_name);3298return;3299}3300} // Done parsing postalloc_expand method and their parameters.3301if (_curchar != ')') {3302parse_err(SYNERR, "Missing ')' at end of postalloc_expand description.\n");3303return;3304}3305next_char(); // Move past ')'.3306skipws(); // Skip leading whitespace.33073308if (_curchar != ';') {3309parse_err(SYNERR, "Missing ';' at end of postalloc_expand.\n");3310return;3311}3312next_char(); // Move past ';'.3313skipws(); // Be friendly to oper_parse().33143315// Debug Stuff.3316if (_AD._adl_debug > 1) fprintf(stderr, "Instruction postalloc_expand: %s\n", ec_name);33173318// Set encode class of this instruction.3319inst._insencode = encrule;3320}332133223323//------------------------------constant_parse---------------------------------3324// Parse a constant expression.3325void ADLParser::constant_parse(InstructForm& inst) {3326// Create a new encoding name based on the name of the instruction3327// definition, which should be unique.3328const char* prefix = "__constant_";3329char* ec_name = (char*) malloc(strlen(inst._ident) + strlen(prefix) + 1);3330sprintf(ec_name, "%s%s", prefix, inst._ident);33313332assert(_AD._encode->encClass(ec_name) == NULL, "shouldn't already exist");3333EncClass* encoding = _AD._encode->add_EncClass(ec_name);3334encoding->_linenum = linenum();33353336// synthesize the arguments list for the enc_class from the3337// arguments to the instruct definition.3338const char* param = NULL;3339inst._parameters.reset();3340while ((param = inst._parameters.iter()) != NULL) {3341OpClassForm* opForm = inst._localNames[param]->is_opclass();3342assert(opForm != NULL, "sanity");3343encoding->add_parameter(opForm->_ident, param);3344}33453346// Parse the following ( ) expression.3347constant_parse_expression(encoding, ec_name);33483349// Build an encoding rule which invokes the encoding rule we just3350// created, passing all arguments that we received.3351InsEncode* encrule = new InsEncode(); // Encode class for instruction3352NameAndList* params = encrule->add_encode(ec_name);3353inst._parameters.reset();3354while ((param = inst._parameters.iter()) != NULL) {3355params->add_entry(param);3356}33573358// Set encode class of this instruction.3359inst._constant = encrule;3360}336133623363//------------------------------constant_parse_expression----------------------3364void ADLParser::constant_parse_expression(EncClass* encoding, char* ec_name) {3365skipws();33663367// Prepend location descriptor, for debugging; cf. ADLParser::find_cpp_block3368if (_AD._adlocation_debug) {3369encoding->add_code(get_line_string());3370}33713372// Start code line.3373encoding->add_code(" _constant = C->constant_table().add");33743375// Parse everything in ( ) expression.3376encoding->add_code("(this, ");3377next_char(); // Skip '('3378int parens_depth = 1;33793380// Collect the parts of the constant expression.3381// (1) strings that are passed through to output3382// (2) replacement/substitution variable, preceeded by a '$'3383while (parens_depth > 0) {3384if (_curchar == '(') {3385parens_depth++;3386encoding->add_code("(");3387next_char();3388}3389else if (_curchar == ')') {3390parens_depth--;3391if (parens_depth > 0)3392encoding->add_code(")");3393next_char();3394}3395else {3396// (1)3397// Check if there is a string to pass through to output3398char *start = _ptr; // Record start of the next string3399while ((_curchar != '$') && (_curchar != '(') && (_curchar != ')')) {3400next_char();3401}3402// If a string was found, terminate it and record in EncClass3403if (start != _ptr) {3404*_ptr = '\0'; // Terminate the string3405encoding->add_code(start);3406}34073408// (2)3409// If we are at a replacement variable, copy it and record in EncClass.3410if (_curchar == '$') {3411// Found replacement Variable3412char* rep_var = get_rep_var_ident_dup();3413encoding->add_rep_var(rep_var);3414}3415}3416}34173418// Finish code line.3419encoding->add_code(");");34203421if (_AD._adlocation_debug) {3422encoding->add_code(end_line_marker());3423}34243425// Debug Stuff3426if (_AD._adl_debug > 1) fprintf(stderr, "EncodingClass Form: %s\n", ec_name);3427}342834293430//------------------------------size_parse-----------------------------------3431// Parse a 'size(<expr>)' attribute which specifies the size of the3432// emitted instructions in bytes. <expr> can be a C++ expression,3433// e.g. a constant.3434char* ADLParser::size_parse(InstructForm *instr) {3435char* sizeOfInstr = NULL;34363437// Get value of the instruction's size3438skipws();34393440// Parse size3441sizeOfInstr = get_paren_expr("size expression");3442if (sizeOfInstr == NULL) {3443parse_err(SYNERR, "size of opcode expected at %c\n", _curchar);3444return NULL;3445}34463447skipws();34483449// Check for terminator3450if (_curchar != ';') {3451parse_err(SYNERR, "missing ';' in ins_attrib definition\n");3452return NULL;3453}3454next_char(); // Advance past the ';'3455skipws(); // necessary for instr_parse()34563457// Debug Stuff3458if (_AD._adl_debug > 1) {3459if (sizeOfInstr != NULL) {3460fprintf(stderr,"size of opcode: %s\n", sizeOfInstr);3461}3462}34633464return sizeOfInstr;3465}346634673468//------------------------------opcode_parse-----------------------------------3469Opcode * ADLParser::opcode_parse(InstructForm *instr) {3470char *primary = NULL;3471char *secondary = NULL;3472char *tertiary = NULL;34733474char *val = NULL;3475Opcode *opcode = NULL;34763477// Get value of the instruction's opcode3478skipws();3479if (_curchar != '(') { // Check for parenthesized operand list3480parse_err(SYNERR, "missing '(' in expand instruction declaration\n");3481return NULL;3482}3483next_char(); // skip open paren3484skipws();3485if (_curchar != ')') {3486// Parse primary, secondary, and tertiary opcodes, if provided.3487if ( ((primary = get_ident_or_literal_constant("primary opcode")) == NULL) ) {3488parse_err(SYNERR, "primary hex opcode expected at %c\n", _curchar);3489return NULL;3490}3491skipws();3492if (_curchar == ',') {3493next_char();3494skipws();3495// Parse secondary opcode3496if ( ((secondary = get_ident_or_literal_constant("secondary opcode")) == NULL) ) {3497parse_err(SYNERR, "secondary hex opcode expected at %c\n", _curchar);3498return NULL;3499}3500skipws();3501if (_curchar == ',') {3502next_char();3503skipws();3504// Parse tertiary opcode3505if ( ((tertiary = get_ident_or_literal_constant("tertiary opcode")) == NULL) ) {3506parse_err(SYNERR,"tertiary hex opcode expected at %c\n", _curchar);3507return NULL;3508}3509skipws();3510}3511}3512skipws();3513if (_curchar != ')') {3514parse_err(SYNERR, "Missing ')' in opcode description\n");3515return NULL;3516}3517}3518next_char(); // Skip ')'3519skipws();3520// Check for terminator3521if (_curchar != ';') {3522parse_err(SYNERR, "missing ';' in ins_attrib definition\n");3523return NULL;3524}3525next_char(); // Advance past the ';'3526skipws(); // necessary for instr_parse()35273528// Debug Stuff3529if (_AD._adl_debug > 1) {3530if (primary != NULL) fprintf(stderr,"primary opcode: %s\n", primary);3531if (secondary != NULL) fprintf(stderr,"secondary opcode: %s\n", secondary);3532if (tertiary != NULL) fprintf(stderr,"tertiary opcode: %s\n", tertiary);3533}35343535// Generate new object and return3536opcode = new Opcode(primary, secondary, tertiary);3537return opcode;3538}353935403541//------------------------------interface_parse--------------------------------3542Interface *ADLParser::interface_parse(void) {3543char *iface_name = NULL; // Name of interface class being used3544char *iface_code = NULL; // Describe components of this class35453546// Get interface class name3547skipws(); // Skip whitespace3548if (_curchar != '(') {3549parse_err(SYNERR, "Missing '(' at start of interface description.\n");3550return NULL;3551}3552next_char(); // move past '('3553skipws();3554iface_name = get_ident();3555if (iface_name == NULL) {3556parse_err(SYNERR, "missing interface name after 'interface'.\n");3557return NULL;3558}3559skipws();3560if (_curchar != ')') {3561parse_err(SYNERR, "Missing ')' after name of interface.\n");3562return NULL;3563}3564next_char(); // move past ')'35653566// Get details of the interface,3567// for the type of interface indicated by iface_name.3568Interface *inter = NULL;3569skipws();3570if ( _curchar != ';' ) {3571if ( strcmp(iface_name,"MEMORY_INTER") == 0 ) {3572inter = mem_interface_parse();3573}3574else if ( strcmp(iface_name,"COND_INTER") == 0 ) {3575inter = cond_interface_parse();3576}3577// The parse routines consume the "%}"35783579// Check for probable extra ';' after defining block.3580if ( _curchar == ';' ) {3581parse_err(SYNERR, "Extra ';' after defining interface block.\n");3582next_char(); // Skip ';'3583return NULL;3584}3585} else {3586next_char(); // move past ';'35873588// Create appropriate interface object3589if ( strcmp(iface_name,"REG_INTER") == 0 ) {3590inter = new RegInterface();3591}3592else if ( strcmp(iface_name,"CONST_INTER") == 0 ) {3593inter = new ConstInterface();3594}3595}3596skipws(); // be friendly to oper_parse()3597// Debug Stuff3598if (_AD._adl_debug > 1) fprintf(stderr,"Interface Form: %s\n", iface_name);35993600// Create appropriate interface object and return.3601return inter;3602}360336043605//------------------------------mem_interface_parse----------------------------3606Interface *ADLParser::mem_interface_parse(void) {3607// Fields for MemInterface3608char *base = NULL;3609char *index = NULL;3610char *scale = NULL;3611char *disp = NULL;36123613if (_curchar != '%') {3614parse_err(SYNERR, "Missing '%%{' for 'interface' block.\n");3615return NULL;3616}3617next_char(); // Skip '%'3618if (_curchar != '{') {3619parse_err(SYNERR, "Missing '%%{' for 'interface' block.\n");3620return NULL;3621}3622next_char(); // Skip '{'3623skipws();3624do {3625char *field = get_ident();3626if (field == NULL) {3627parse_err(SYNERR, "Expected keyword, base|index|scale|disp, or '%%}' ending interface.\n");3628return NULL;3629}3630if ( strcmp(field,"base") == 0 ) {3631base = interface_field_parse();3632}3633else if ( strcmp(field,"index") == 0 ) {3634index = interface_field_parse();3635}3636else if ( strcmp(field,"scale") == 0 ) {3637scale = interface_field_parse();3638}3639else if ( strcmp(field,"disp") == 0 ) {3640disp = interface_field_parse();3641}3642else {3643parse_err(SYNERR, "Expected keyword, base|index|scale|disp, or '%%}' ending interface.\n");3644return NULL;3645}3646} while( _curchar != '%' );3647next_char(); // Skip '%'3648if ( _curchar != '}' ) {3649parse_err(SYNERR, "Missing '%%}' for 'interface' block.\n");3650return NULL;3651}3652next_char(); // Skip '}'36533654// Construct desired object and return3655Interface *inter = new MemInterface(base, index, scale, disp);3656return inter;3657}365836593660//------------------------------cond_interface_parse---------------------------3661Interface *ADLParser::cond_interface_parse(void) {3662char *equal;3663char *not_equal;3664char *less;3665char *greater_equal;3666char *less_equal;3667char *greater;3668char *overflow;3669char *no_overflow;3670const char *equal_format = "eq";3671const char *not_equal_format = "ne";3672const char *less_format = "lt";3673const char *greater_equal_format = "ge";3674const char *less_equal_format = "le";3675const char *greater_format = "gt";3676const char *overflow_format = "o";3677const char *no_overflow_format = "no";36783679if (_curchar != '%') {3680parse_err(SYNERR, "Missing '%%{' for 'cond_interface' block.\n");3681return NULL;3682}3683next_char(); // Skip '%'3684if (_curchar != '{') {3685parse_err(SYNERR, "Missing '%%{' for 'cond_interface' block.\n");3686return NULL;3687}3688next_char(); // Skip '{'3689skipws();3690do {3691char *field = get_ident();3692if (field == NULL) {3693parse_err(SYNERR, "Expected keyword, base|index|scale|disp, or '%%}' ending interface.\n");3694return NULL;3695}3696if ( strcmp(field,"equal") == 0 ) {3697equal = interface_field_parse(&equal_format);3698}3699else if ( strcmp(field,"not_equal") == 0 ) {3700not_equal = interface_field_parse(¬_equal_format);3701}3702else if ( strcmp(field,"less") == 0 ) {3703less = interface_field_parse(&less_format);3704}3705else if ( strcmp(field,"greater_equal") == 0 ) {3706greater_equal = interface_field_parse(&greater_equal_format);3707}3708else if ( strcmp(field,"less_equal") == 0 ) {3709less_equal = interface_field_parse(&less_equal_format);3710}3711else if ( strcmp(field,"greater") == 0 ) {3712greater = interface_field_parse(&greater_format);3713}3714else if ( strcmp(field,"overflow") == 0 ) {3715overflow = interface_field_parse(&overflow_format);3716}3717else if ( strcmp(field,"no_overflow") == 0 ) {3718no_overflow = interface_field_parse(&no_overflow_format);3719}3720else {3721parse_err(SYNERR, "Expected keyword, base|index|scale|disp, or '%%}' ending interface.\n");3722return NULL;3723}3724} while( _curchar != '%' );3725next_char(); // Skip '%'3726if ( _curchar != '}' ) {3727parse_err(SYNERR, "Missing '%%}' for 'interface' block.\n");3728return NULL;3729}3730next_char(); // Skip '}'37313732// Construct desired object and return3733Interface *inter = new CondInterface(equal, equal_format,3734not_equal, not_equal_format,3735less, less_format,3736greater_equal, greater_equal_format,3737less_equal, less_equal_format,3738greater, greater_format,3739overflow, overflow_format,3740no_overflow, no_overflow_format);3741return inter;3742}374337443745//------------------------------interface_field_parse--------------------------3746char *ADLParser::interface_field_parse(const char ** format) {3747char *iface_field = NULL;37483749// Get interface field3750skipws(); // Skip whitespace3751if (_curchar != '(') {3752parse_err(SYNERR, "Missing '(' at start of interface field.\n");3753return NULL;3754}3755next_char(); // move past '('3756skipws();3757if ( _curchar != '0' && _curchar != '$' ) {3758parse_err(SYNERR, "missing or invalid interface field contents.\n");3759return NULL;3760}3761iface_field = get_rep_var_ident();3762if (iface_field == NULL) {3763parse_err(SYNERR, "missing or invalid interface field contents.\n");3764return NULL;3765}3766skipws();3767if (format != NULL && _curchar == ',') {3768next_char();3769skipws();3770if (_curchar != '"') {3771parse_err(SYNERR, "Missing '\"' in field format .\n");3772return NULL;3773}3774next_char();3775char *start = _ptr; // Record start of the next string3776while ((_curchar != '"') && (_curchar != '%') && (_curchar != '\n')) {3777if (_curchar == '\\') next_char(); // superquote3778if (_curchar == '\n') parse_err(SYNERR, "newline in string"); // unimplemented!3779next_char();3780}3781if (_curchar != '"') {3782parse_err(SYNERR, "Missing '\"' at end of field format .\n");3783return NULL;3784}3785// If a string was found, terminate it and record in FormatRule3786if ( start != _ptr ) {3787*_ptr = '\0'; // Terminate the string3788*format = start;3789}3790next_char();3791skipws();3792}3793if (_curchar != ')') {3794parse_err(SYNERR, "Missing ')' after interface field.\n");3795return NULL;3796}3797next_char(); // move past ')'3798skipws();3799if ( _curchar != ';' ) {3800parse_err(SYNERR, "Missing ';' at end of interface field.\n");3801return NULL;3802}3803next_char(); // move past ';'3804skipws(); // be friendly to interface_parse()38053806return iface_field;3807}380838093810//------------------------------match_parse------------------------------------3811MatchRule *ADLParser::match_parse(FormDict &operands) {3812MatchRule *match; // Match Rule class for instruction/operand3813char *cnstr = NULL; // Code for constructor3814int depth = 0; // Counter for matching parentheses3815int numleaves = 0; // Counter for number of leaves in rule38163817// Parse the match rule tree3818MatchNode *mnode = matchNode_parse(operands, depth, numleaves, true);38193820// Either there is a block with a constructor, or a ';' here3821skipws(); // Skip whitespace3822if ( _curchar == ';' ) { // Semicolon is valid terminator3823cnstr = NULL; // no constructor for this form3824next_char(); // Move past the ';', replaced with '\0'3825}3826else if ((cnstr = find_cpp_block("match constructor")) == NULL ) {3827parse_err(SYNERR, "invalid construction of match rule\n"3828"Missing ';' or invalid '%%{' and '%%}' constructor\n");3829return NULL; // No MatchRule to return3830}3831if (_AD._adl_debug > 1)3832if (cnstr) fprintf(stderr,"Match Constructor: %s\n", cnstr);3833// Build new MatchRule object3834match = new MatchRule(_AD, mnode, depth, cnstr, numleaves);3835skipws(); // Skip any trailing whitespace3836return match; // Return MatchRule object3837}38383839//------------------------------format_parse-----------------------------------3840FormatRule* ADLParser::format_parse(void) {3841char *desc = NULL;3842FormatRule *format = (new FormatRule(desc));38433844// Without expression form, MUST have a code block;3845skipws(); // Skip whitespace3846if ( _curchar == ';' ) { // Semicolon is valid terminator3847desc = NULL; // no constructor for this form3848next_char(); // Move past the ';', replaced with '\0'3849}3850else if ( _curchar == '%' && *(_ptr+1) == '{') {3851next_char(); // Move past the '%'3852next_char(); // Move past the '{'38533854skipws();3855if (_curchar == '$') {3856char* ident = get_rep_var_ident();3857if (strcmp(ident, "$$template") == 0) return template_parse();3858parse_err(SYNERR, "Unknown \"%s\" directive in format", ident);3859return NULL;3860}3861// Check for the opening '"' inside the format description3862if ( _curchar == '"' ) {3863next_char(); // Move past the initial '"'3864if( _curchar == '"' ) { // Handle empty format string case3865*_ptr = '\0'; // Terminate empty string3866format->_strings.addName(_ptr);3867}38683869// Collect the parts of the format description3870// (1) strings that are passed through to tty->print3871// (2) replacement/substitution variable, preceeded by a '$'3872// (3) multi-token ANSIY C style strings3873while ( true ) {3874if ( _curchar == '%' || _curchar == '\n' ) {3875if ( _curchar != '"' ) {3876parse_err(SYNERR, "missing '\"' at end of format block");3877return NULL;3878}3879}38803881// (1)3882// Check if there is a string to pass through to output3883char *start = _ptr; // Record start of the next string3884while ((_curchar != '$') && (_curchar != '"') && (_curchar != '%') && (_curchar != '\n')) {3885if (_curchar == '\\') {3886next_char(); // superquote3887if ((_curchar == '$') || (_curchar == '%'))3888// hack to avoid % escapes and warnings about undefined \ escapes3889*(_ptr-1) = _curchar;3890}3891if (_curchar == '\n') parse_err(SYNERR, "newline in string"); // unimplemented!3892next_char();3893}3894// If a string was found, terminate it and record in FormatRule3895if ( start != _ptr ) {3896*_ptr = '\0'; // Terminate the string3897format->_strings.addName(start);3898}38993900// (2)3901// If we are at a replacement variable,3902// copy it and record in FormatRule3903if ( _curchar == '$' ) {3904next_char(); // Move past the '$'3905char* rep_var = get_ident(); // Nil terminate the variable name3906rep_var = strdup(rep_var);// Copy the string3907*_ptr = _curchar; // and replace Nil with original character3908format->_rep_vars.addName(rep_var);3909// Add flag to _strings list indicating we should check _rep_vars3910format->_strings.addName(NameList::_signal);3911}39123913// (3)3914// Allow very long strings to be broken up,3915// using the ANSI C syntax "foo\n" <newline> "bar"3916if ( _curchar == '"') {3917next_char(); // Move past the '"'3918skipws(); // Skip white space before next string token3919if ( _curchar != '"') {3920break;3921} else {3922// Found one. Skip both " and the whitespace in between.3923next_char();3924}3925}3926} // end while part of format description39273928// Check for closing '"' and '%}' in format description3929skipws(); // Move to closing '%}'3930if ( _curchar != '%' ) {3931parse_err(SYNERR, "non-blank characters between closing '\"' and '%%' in format");3932return NULL;3933}3934} // Done with format description inside39353936skipws();3937// Past format description, at '%'3938if ( _curchar != '%' || *(_ptr+1) != '}' ) {3939parse_err(SYNERR, "missing '%%}' at end of format block");3940return NULL;3941}3942next_char(); // Move past the '%'3943next_char(); // Move past the '}'3944}3945else { // parameter list alone must terminate with a ';'3946parse_err(SYNERR, "missing ';' after Format expression");3947return NULL;3948}3949// Debug Stuff3950if (_AD._adl_debug > 1) fprintf(stderr,"Format Rule: %s\n", desc);39513952skipws();3953return format;3954}395539563957//------------------------------template_parse-----------------------------------3958FormatRule* ADLParser::template_parse(void) {3959char *desc = NULL;3960FormatRule *format = (new FormatRule(desc));39613962skipws();3963while ( (_curchar != '%') && (*(_ptr+1) != '}') ) {39643965// (1)3966// Check if there is a string to pass through to output3967{3968char *start = _ptr; // Record start of the next string3969while ((_curchar != '$') && ((_curchar != '%') || (*(_ptr+1) != '}')) ) {3970// If at the start of a comment, skip past it3971if( (_curchar == '/') && ((*(_ptr+1) == '/') || (*(_ptr+1) == '*')) ) {3972skipws_no_preproc();3973} else {3974// ELSE advance to the next character, or start of the next line3975next_char_or_line();3976}3977}3978// If a string was found, terminate it and record in EncClass3979if ( start != _ptr ) {3980*_ptr = '\0'; // Terminate the string3981// Add flag to _strings list indicating we should check _rep_vars3982format->_strings.addName(NameList::_signal2);3983format->_strings.addName(start);3984}3985}39863987// (2)3988// If we are at a replacement variable,3989// copy it and record in EncClass3990if ( _curchar == '$' ) {3991// Found replacement Variable3992char *rep_var = get_rep_var_ident_dup();3993if (strcmp(rep_var, "$emit") == 0) {3994// switch to normal format parsing3995next_char();3996next_char();3997skipws();3998// Check for the opening '"' inside the format description3999if ( _curchar == '"' ) {4000next_char(); // Move past the initial '"'4001if( _curchar == '"' ) { // Handle empty format string case4002*_ptr = '\0'; // Terminate empty string4003format->_strings.addName(_ptr);4004}40054006// Collect the parts of the format description4007// (1) strings that are passed through to tty->print4008// (2) replacement/substitution variable, preceeded by a '$'4009// (3) multi-token ANSIY C style strings4010while ( true ) {4011if ( _curchar == '%' || _curchar == '\n' ) {4012parse_err(SYNERR, "missing '\"' at end of format block");4013return NULL;4014}40154016// (1)4017// Check if there is a string to pass through to output4018char *start = _ptr; // Record start of the next string4019while ((_curchar != '$') && (_curchar != '"') && (_curchar != '%') && (_curchar != '\n')) {4020if (_curchar == '\\') next_char(); // superquote4021if (_curchar == '\n') parse_err(SYNERR, "newline in string"); // unimplemented!4022next_char();4023}4024// If a string was found, terminate it and record in FormatRule4025if ( start != _ptr ) {4026*_ptr = '\0'; // Terminate the string4027format->_strings.addName(start);4028}40294030// (2)4031// If we are at a replacement variable,4032// copy it and record in FormatRule4033if ( _curchar == '$' ) {4034next_char(); // Move past the '$'4035char* next_rep_var = get_ident(); // Nil terminate the variable name4036next_rep_var = strdup(next_rep_var);// Copy the string4037*_ptr = _curchar; // and replace Nil with original character4038format->_rep_vars.addName(next_rep_var);4039// Add flag to _strings list indicating we should check _rep_vars4040format->_strings.addName(NameList::_signal);4041}40424043// (3)4044// Allow very long strings to be broken up,4045// using the ANSI C syntax "foo\n" <newline> "bar"4046if ( _curchar == '"') {4047next_char(); // Move past the '"'4048skipws(); // Skip white space before next string token4049if ( _curchar != '"') {4050break;4051} else {4052// Found one. Skip both " and the whitespace in between.4053next_char();4054}4055}4056} // end while part of format description4057}4058} else {4059// Add flag to _strings list indicating we should check _rep_vars4060format->_rep_vars.addName(rep_var);4061// Add flag to _strings list indicating we should check _rep_vars4062format->_strings.addName(NameList::_signal3);4063}4064} // end while part of format description4065}40664067skipws();4068// Past format description, at '%'4069if ( _curchar != '%' || *(_ptr+1) != '}' ) {4070parse_err(SYNERR, "missing '%%}' at end of format block");4071return NULL;4072}4073next_char(); // Move past the '%'4074next_char(); // Move past the '}'40754076// Debug Stuff4077if (_AD._adl_debug > 1) fprintf(stderr,"Format Rule: %s\n", desc);40784079skipws();4080return format;4081}408240834084//------------------------------effect_parse-----------------------------------4085void ADLParser::effect_parse(InstructForm *instr) {4086char* desc = NULL;40874088skipws(); // Skip whitespace4089if (_curchar != '(') {4090parse_err(SYNERR, "missing '(' in effect definition\n");4091return;4092}4093// Get list of effect-operand pairs and insert into dictionary4094else get_effectlist(instr->_effects, instr->_localNames, instr->_has_call);40954096// Debug Stuff4097if (_AD._adl_debug > 1) fprintf(stderr,"Effect description: %s\n", desc);4098if (_curchar != ';') {4099parse_err(SYNERR, "missing ';' in Effect definition\n");4100}4101next_char(); // Skip ';'41024103}41044105//------------------------------expand_parse-----------------------------------4106ExpandRule* ADLParser::expand_parse(InstructForm *instr) {4107char *ident, *ident2;4108NameAndList *instr_and_operands = NULL;4109ExpandRule *exp = new ExpandRule();41104111// Expand is a block containing an ordered list of operands with initializers,4112// or instructions, each of which has an ordered list of operands.4113// Check for block delimiter4114skipws(); // Skip leading whitespace4115if ((_curchar != '%')4116|| (next_char(), (_curchar != '{')) ) { // If not open block4117parse_err(SYNERR, "missing '%%{' in expand definition\n");4118return(NULL);4119}4120next_char(); // Maintain the invariant4121do {4122ident = get_ident(); // Grab next identifier4123if (ident == NULL) {4124parse_err(SYNERR, "identifier expected at %c\n", _curchar);4125continue;4126}41274128// Check whether we should parse an instruction or operand.4129const Form *form = _globalNames[ident];4130bool parse_oper = false;4131bool parse_ins = false;4132if (form == NULL) {4133skipws();4134// Check whether this looks like an instruction specification. If so,4135// just parse the instruction. The declaration of the instruction is4136// not needed here.4137if (_curchar == '(') parse_ins = true;4138} else if (form->is_instruction()) {4139parse_ins = true;4140} else if (form->is_operand()) {4141parse_oper = true;4142} else {4143parse_err(SYNERR, "instruction/operand name expected at %s\n", ident);4144continue;4145}41464147if (parse_oper) {4148// This is a new operand4149OperandForm *oper = form->is_operand();4150if (oper == NULL) {4151parse_err(SYNERR, "instruction/operand name expected at %s\n", ident);4152continue;4153}4154// Throw the operand on the _newopers list4155skipws();4156ident = get_unique_ident(instr->_localNames,"Operand");4157if (ident == NULL) {4158parse_err(SYNERR, "identifier expected at %c\n", _curchar);4159continue;4160}4161exp->_newopers.addName(ident);4162// Add new operand to LocalNames4163instr->_localNames.Insert(ident, oper);4164// Grab any constructor code and save as a string4165char *c = NULL;4166skipws();4167if (_curchar == '%') { // Need a constructor for the operand4168c = find_cpp_block("Operand Constructor");4169if (c == NULL) {4170parse_err(SYNERR, "Invalid code block for operand constructor\n", _curchar);4171continue;4172}4173// Add constructor to _newopconst Dict4174exp->_newopconst.Insert(ident, c);4175}4176else if (_curchar != ';') { // If no constructor, need a ;4177parse_err(SYNERR, "Missing ; in expand rule operand declaration\n");4178continue;4179}4180else next_char(); // Skip the ;4181skipws();4182}4183else {4184assert(parse_ins, "sanity");4185// Add instruction to list4186instr_and_operands = new NameAndList(ident);4187// Grab operands, build nameList of them, and then put into dictionary4188skipws();4189if (_curchar != '(') { // Check for parenthesized operand list4190parse_err(SYNERR, "missing '(' in expand instruction declaration\n");4191continue;4192}4193do {4194next_char(); // skip open paren & comma characters4195skipws();4196if (_curchar == ')') break;4197ident2 = get_ident();4198skipws();4199if (ident2 == NULL) {4200parse_err(SYNERR, "identifier expected at %c\n", _curchar);4201continue;4202} // Check that you have a valid operand4203const Form *form2 = instr->_localNames[ident2];4204if (!form2) {4205parse_err(SYNERR, "operand name expected at %s\n", ident2);4206continue;4207}4208OperandForm *oper = form2->is_operand();4209if (oper == NULL && !form2->is_opclass()) {4210parse_err(SYNERR, "operand name expected at %s\n", ident2);4211continue;4212} // Add operand to list4213instr_and_operands->add_entry(ident2);4214} while(_curchar == ',');4215if (_curchar != ')') {4216parse_err(SYNERR, "missing ')'in expand instruction declaration\n");4217continue;4218}4219next_char();4220if (_curchar != ';') {4221parse_err(SYNERR, "missing ';'in expand instruction declaration\n");4222continue;4223}4224next_char();42254226// Record both instruction name and its operand list4227exp->add_instruction(instr_and_operands);42284229skipws();4230}42314232} while(_curchar != '%');4233next_char();4234if (_curchar != '}') {4235parse_err(SYNERR, "missing '%%}' in expand rule definition\n");4236return(NULL);4237}4238next_char();42394240// Debug Stuff4241if (_AD._adl_debug > 1) fprintf(stderr,"Expand Rule:\n");42424243skipws();4244return (exp);4245}42464247//------------------------------rewrite_parse----------------------------------4248RewriteRule* ADLParser::rewrite_parse(void) {4249char* params = NULL;4250char* desc = NULL;425142524253// This feature targeted for second generation description language.42544255skipws(); // Skip whitespace4256// Get parameters for rewrite4257if ((params = get_paren_expr("rewrite parameters")) == NULL) {4258parse_err(SYNERR, "missing '(' in rewrite rule\n");4259return NULL;4260}4261// Debug Stuff4262if (_AD._adl_debug > 1) fprintf(stderr,"Rewrite parameters: %s\n", params);42634264// For now, grab entire block;4265skipws();4266if ( (desc = find_cpp_block("rewrite block")) == NULL ) {4267parse_err(SYNERR, "incorrect or missing block for 'rewrite'.\n");4268return NULL;4269}4270// Debug Stuff4271if (_AD._adl_debug > 1) fprintf(stderr,"Rewrite Rule: %s\n", desc);42724273skipws();4274return (new RewriteRule(params,desc));4275}42764277//------------------------------attr_parse-------------------------------------4278Attribute *ADLParser::attr_parse(char* ident) {4279Attribute *attrib; // Attribute class4280char *cost = NULL; // String representation of cost attribute42814282skipws(); // Skip leading whitespace4283if ( (cost = get_paren_expr("attribute")) == NULL ) {4284parse_err(SYNERR, "incorrect or missing expression for 'attribute'\n");4285return NULL;4286}4287// Debug Stuff4288if (_AD._adl_debug > 1) fprintf(stderr,"Attribute: %s\n", cost);4289if (_curchar != ';') {4290parse_err(SYNERR, "missing ';' in attribute definition\n");4291return NULL;4292}4293next_char(); // Point after the terminator42944295skipws();4296attrib = new Attribute(ident,cost,INS_ATTR); // Build new predicate object4297return attrib;4298}429943004301//------------------------------matchNode_parse--------------------------------4302MatchNode *ADLParser::matchNode_parse(FormDict &operands, int &depth, int &numleaves, bool atroot) {4303// Count depth of parenthesis nesting for both left and right children4304int lParens = depth;4305int rParens = depth;43064307// MatchNode objects for left, right, and root of subtree.4308MatchNode *lChild = NULL;4309MatchNode *rChild = NULL;4310char *token; // Identifier which may be opcode or operand43114312// Match expression starts with a '('4313if (cur_char() != '(')4314return NULL;43154316next_char(); // advance past '('43174318// Parse the opcode4319token = get_ident(); // Get identifier, opcode4320if (token == NULL) {4321parse_err(SYNERR, "missing opcode in match expression\n");4322return NULL;4323}43244325// Take note if we see one of a few special operations - those that are4326// treated differently on different architectures in the sense that on4327// one architecture there is a match rule and on another there isn't (so4328// a call will eventually be generated).43294330for (int i = _last_machine_leaf + 1; i < _last_opcode; i++) {4331if (strcmp(token, NodeClassNames[i]) == 0) {4332_AD.has_match_rule(i, true);4333}4334}43354336// Lookup the root value in the operands dict to perform substitution4337const char *result = NULL; // Result type will be filled in later4338const char *name = token; // local name associated with this node4339const char *operation = token; // remember valid operation for later4340const Form *form = operands[token];4341OpClassForm *opcForm = form ? form->is_opclass() : NULL;4342if (opcForm != NULL) {4343// If this token is an entry in the local names table, record its type4344if (!opcForm->ideal_only()) {4345operation = opcForm->_ident;4346result = operation; // Operands result in their own type4347}4348// Otherwise it is an ideal type, and so, has no local name4349else name = NULL;4350}43514352// Parse the operands4353skipws();4354if (cur_char() != ')') {43554356// Parse the left child4357if (strcmp(operation,"Set"))4358lChild = matchChild_parse(operands, lParens, numleaves, false);4359else4360lChild = matchChild_parse(operands, lParens, numleaves, true);43614362skipws();4363if (cur_char() != ')' ) {4364if(strcmp(operation, "Set"))4365rChild = matchChild_parse(operands,rParens,numleaves,false);4366else4367rChild = matchChild_parse(operands,rParens,numleaves,true);4368}4369}43704371// Check for required ')'4372skipws();4373if (cur_char() != ')') {4374parse_err(SYNERR, "missing ')' in match expression\n");4375return NULL;4376}4377next_char(); // skip the ')'43784379MatchNode* mroot = new MatchNode(_AD,result,name,operation,lChild,rChild);43804381// If not the root, reduce this subtree to an internal operand4382if (!atroot) {4383mroot->build_internalop();4384}4385// depth is greater of left and right paths.4386depth = (lParens > rParens) ? lParens : rParens;43874388return mroot;4389}439043914392//------------------------------matchChild_parse-------------------------------4393MatchNode *ADLParser::matchChild_parse(FormDict &operands, int &parens, int &numleaves, bool atroot) {4394MatchNode *child = NULL;4395const char *result = NULL;4396const char *token = NULL;4397const char *opType = NULL;43984399if (cur_char() == '(') { // child is an operation4400++parens;4401child = matchNode_parse(operands, parens, numleaves, atroot);4402}4403else { // child is an operand4404token = get_ident();4405const Form *form = operands[token];4406OpClassForm *opcForm = form ? form->is_opclass() : NULL;4407if (opcForm != NULL) {4408opType = opcForm->_ident;4409result = opcForm->_ident; // an operand's result matches its type4410} else {4411parse_err(SYNERR, "undefined operand %s in match rule\n", token);4412return NULL;4413}44144415if (opType == NULL) {4416parse_err(SYNERR, "missing type for argument '%s'\n", token);4417}44184419child = new MatchNode(_AD, result, token, opType);4420++numleaves;4421}44224423return child;4424}4425442644274428// ******************** Private Utility Functions *************************442944304431char* ADLParser::find_cpp_block(const char* description) {4432char *next; // Pointer for finding block delimiters4433char* cppBlock = NULL; // Beginning of C++ code block44344435if (_curchar == '%') { // Encoding is a C++ expression4436next_char();4437if (_curchar != '{') {4438parse_err(SYNERR, "missing '{' in %s \n", description);4439return NULL;4440}4441next_char(); // Skip block delimiter4442skipws_no_preproc(); // Skip leading whitespace4443cppBlock = _ptr; // Point to start of expression4444int line = linenum();4445next = _ptr + 1;4446while(((_curchar != '%') || (*next != '}')) && (_curchar != '\0')) {4447next_char_or_line();4448next = _ptr+1; // Maintain the next pointer4449} // Grab string4450if (_curchar == '\0') {4451parse_err(SYNERR, "invalid termination of %s \n", description);4452return NULL;4453}4454*_ptr = '\0'; // Terminate string4455_ptr += 2; // Skip block delimiter4456_curchar = *_ptr; // Maintain invariant44574458// Prepend location descriptor, for debugging.4459if (_AD._adlocation_debug) {4460char* location = get_line_string(line);4461char* end_loc = end_line_marker();4462char* result = (char *)malloc(strlen(location) + strlen(cppBlock) + strlen(end_loc) + 1);4463strcpy(result, location);4464strcat(result, cppBlock);4465strcat(result, end_loc);4466cppBlock = result;4467free(location);4468}4469}44704471return cppBlock;4472}44734474// Move to the closing token of the expression we are currently at,4475// as defined by stop_chars. Match parens and quotes.4476char* ADLParser::get_expr(const char *desc, const char *stop_chars) {4477char* expr = NULL;4478int paren = 0;44794480expr = _ptr;4481while (paren > 0 || !strchr(stop_chars, _curchar)) {4482if (_curchar == '(') { // Down level of nesting4483paren++; // Bump the parenthesis counter4484next_char(); // maintain the invariant4485}4486else if (_curchar == ')') { // Up one level of nesting4487if (paren == 0) {4488// Paren underflow: We didn't encounter the required stop-char.4489parse_err(SYNERR, "too many )'s, did not find %s after %s\n",4490stop_chars, desc);4491return NULL;4492}4493paren--; // Drop the parenthesis counter4494next_char(); // Maintain the invariant4495}4496else if (_curchar == '"' || _curchar == '\'') {4497int qchar = _curchar;4498while (true) {4499next_char();4500if (_curchar == qchar) { next_char(); break; }4501if (_curchar == '\\') next_char(); // superquote4502if (_curchar == '\n' || _curchar == '\0') {4503parse_err(SYNERR, "newline in string in %s\n", desc);4504return NULL;4505}4506}4507}4508else if (_curchar == '%' && (_ptr[1] == '{' || _ptr[1] == '}')) {4509// Make sure we do not stray into the next ADLC-level form.4510parse_err(SYNERR, "unexpected %%%c in %s\n", _ptr[1], desc);4511return NULL;4512}4513else if (_curchar == '\0') {4514parse_err(SYNERR, "unexpected EOF in %s\n", desc);4515return NULL;4516}4517else {4518// Always walk over whitespace, comments, preprocessor directives, etc.4519char* pre_skip_ptr = _ptr;4520skipws();4521// If the parser declined to make progress on whitespace,4522// skip the next character, which is therefore NOT whitespace.4523if (pre_skip_ptr == _ptr) {4524next_char();4525} else if (pre_skip_ptr+strlen(pre_skip_ptr) != _ptr+strlen(_ptr)) {4526parse_err(SYNERR, "unimplemented: preprocessor must not elide subexpression in %s", desc);4527}4528}4529}45304531assert(strchr(stop_chars, _curchar), "non-null return must be at stop-char");4532*_ptr = '\0'; // Replace ')' or other stop-char with '\0'4533return expr;4534}45354536// Helper function around get_expr4537// Sets _curchar to '(' so that get_paren_expr will search for a matching ')'4538char *ADLParser::get_paren_expr(const char *description, bool include_location) {4539int line = linenum();4540if (_curchar != '(') // Escape if not valid starting position4541return NULL;4542next_char(); // Skip the required initial paren.4543char *token2 = get_expr(description, ")");4544if (_curchar == ')')4545next_char(); // Skip required final paren.4546int junk = 0;4547if (include_location && _AD._adlocation_debug && !is_int_token(token2, junk)) {4548// Prepend location descriptor, for debugging.4549char* location = get_line_string(line);4550char* end_loc = end_line_marker();4551char* result = (char *)malloc(strlen(location) + strlen(token2) + strlen(end_loc) + 1);4552strcpy(result, location);4553strcat(result, token2);4554strcat(result, end_loc);4555token2 = result;4556free(location);4557}4558return token2;4559}45604561//------------------------------get_ident_common-------------------------------4562// Looks for an identifier in the buffer, and turns it into a null terminated4563// string(still inside the file buffer). Returns a pointer to the string or4564// NULL if some other token is found instead.4565char *ADLParser::get_ident_common(bool do_preproc) {4566register char c;4567char *start; // Pointer to start of token4568char *end; // Pointer to end of token45694570if( _curline == NULL ) // Return NULL at EOF.4571return NULL;45724573skipws_common(do_preproc); // Skip whitespace before identifier4574start = end = _ptr; // Start points at first character4575end--; // unwind end by one to prepare for loop4576do {4577end++; // Increment end pointer4578c = *end; // Grab character to test4579} while ( ((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z'))4580|| ((c >= '0') && (c <= '9'))4581|| ((c == '_')) || ((c == ':')) || ((c == '#')) );4582if (start == end) { // We popped out on the first try4583// It can occur that `start' contains the rest of the input file.4584// In this case the output should be truncated.4585if (strlen(start) > 24) {4586char buf[32];4587strncpy(buf, start, 20);4588buf[20] = '\0';4589strcat(buf, "[...]");4590parse_err(SYNERR, "Identifier expected, but found '%s'.", buf);4591} else {4592parse_err(SYNERR, "Identifier expected, but found '%s'.", start);4593}4594start = NULL;4595}4596else {4597_curchar = c; // Save the first character of next token4598*end = '\0'; // NULL terminate the string in place4599}4600_ptr = end; // Reset _ptr to point to next char after token46014602// Make sure we do not try to use #defined identifiers. If start is4603// NULL an error was already reported.4604if (do_preproc && start != NULL) {4605const char* def = _AD.get_preproc_def(start);4606if (def != NULL && strcmp(def, start)) {4607const char* def1 = def;4608const char* def2 = _AD.get_preproc_def(def1);4609// implement up to 2 levels of #define4610if (def2 != NULL && strcmp(def2, def1)) {4611def = def2;4612const char* def3 = _AD.get_preproc_def(def2);4613if (def3 != NULL && strcmp(def3, def2) && strcmp(def3, def1)) {4614parse_err(SYNERR, "unimplemented: using %s defined as %s => %s => %s",4615start, def1, def2, def3);4616}4617}4618start = strdup(def);4619}4620}46214622return start; // Pointer to token in filebuf4623}46244625//------------------------------get_ident_dup----------------------------------4626// Looks for an identifier in the buffer, and returns a duplicate4627// or NULL if some other token is found instead.4628char *ADLParser::get_ident_dup(void) {4629char *ident = get_ident();46304631// Duplicate an identifier before returning and restore string.4632if( ident != NULL ) {4633ident = strdup(ident); // Copy the string4634*_ptr = _curchar; // and replace Nil with original character4635}46364637return ident;4638}46394640//----------------------get_ident_or_literal_constant--------------------------4641// Looks for an identifier in the buffer, or a parenthesized expression.4642char *ADLParser::get_ident_or_literal_constant(const char* description) {4643char* param = NULL;4644skipws();4645if (_curchar == '(') {4646// Grab a constant expression.4647param = get_paren_expr(description);4648if (param[0] != '(') {4649char* buf = (char*) malloc(strlen(param) + 3);4650sprintf(buf, "(%s)", param);4651param = buf;4652}4653assert(is_literal_constant(param),4654"expr must be recognizable as a constant");4655} else {4656param = get_ident();4657}4658return param;4659}46604661//------------------------------get_rep_var_ident-----------------------------4662// Do NOT duplicate,4663// Leave nil terminator in buffer4664// Preserve initial '$'(s) in string4665char *ADLParser::get_rep_var_ident(void) {4666// Remember starting point4667char *rep_var = _ptr;46684669// Check for replacement variable indicator '$' and pass if present4670if ( _curchar == '$' ) {4671next_char();4672}4673// Check for a subfield indicator, a second '$', and pass if present4674if ( _curchar == '$' ) {4675next_char();4676}46774678// Check for a control indicator, a third '$':4679if ( _curchar == '$' ) {4680next_char();4681}46824683// Check for more than three '$'s in sequence, SYNERR4684if( _curchar == '$' ) {4685parse_err(SYNERR, "Replacement variables and field specifiers can not start with '$$$$'");4686next_char();4687return NULL;4688}46894690// Nil terminate the variable name following the '$'4691char *rep_var_name = get_ident();4692assert( rep_var_name != NULL,4693"Missing identifier after replacement variable indicator '$'");46944695return rep_var;4696}4697469846994700//------------------------------get_rep_var_ident_dup-------------------------4701// Return the next replacement variable identifier, skipping first '$'4702// given a pointer into a line of the buffer.4703// Null terminates string, still inside the file buffer,4704// Returns a pointer to a copy of the string, or NULL on failure4705char *ADLParser::get_rep_var_ident_dup(void) {4706if( _curchar != '$' ) return NULL;47074708next_char(); // Move past the '$'4709char *rep_var = _ptr; // Remember starting point47104711// Check for a subfield indicator, a second '$':4712if ( _curchar == '$' ) {4713next_char();4714}47154716// Check for a control indicator, a third '$':4717if ( _curchar == '$' ) {4718next_char();4719}47204721// Check for more than three '$'s in sequence, SYNERR4722if( _curchar == '$' ) {4723parse_err(SYNERR, "Replacement variables and field specifiers can not start with '$$$$'");4724next_char();4725return NULL;4726}47274728// Nil terminate the variable name following the '$'4729char *rep_var_name = get_ident();4730assert( rep_var_name != NULL,4731"Missing identifier after replacement variable indicator '$'");4732rep_var = strdup(rep_var); // Copy the string4733*_ptr = _curchar; // and replace Nil with original character47344735return rep_var;4736}473747384739//------------------------------get_unique_ident------------------------------4740// Looks for an identifier in the buffer, terminates it with a NULL,4741// and checks that it is unique4742char *ADLParser::get_unique_ident(FormDict& dict, const char* nameDescription){4743char* ident = get_ident();47444745if (ident == NULL) {4746parse_err(SYNERR, "missing %s identifier at %c\n", nameDescription, _curchar);4747}4748else {4749if (dict[ident] != NULL) {4750parse_err(SYNERR, "duplicate name %s for %s\n", ident, nameDescription);4751ident = NULL;4752}4753}47544755return ident;4756}475747584759//------------------------------get_int----------------------------------------4760// Looks for a character string integer in the buffer, and turns it into an int4761// invokes a parse_err if the next token is not an integer.4762// This routine does not leave the integer null-terminated.4763int ADLParser::get_int(void) {4764register char c;4765char *start; // Pointer to start of token4766char *end; // Pointer to end of token4767int result; // Storage for integer result47684769if( _curline == NULL ) // Return NULL at EOF.4770return 0;47714772skipws(); // Skip whitespace before identifier4773start = end = _ptr; // Start points at first character4774c = *end; // Grab character to test4775while ((c >= '0') && (c <= '9')4776|| ((c == '-') && (end == start))) {4777end++; // Increment end pointer4778c = *end; // Grab character to test4779}4780if (start == end) { // We popped out on the first try4781parse_err(SYNERR, "integer expected at %c\n", c);4782result = 0;4783}4784else {4785_curchar = c; // Save the first character of next token4786*end = '\0'; // NULL terminate the string in place4787result = atoi(start); // Convert the string to an integer4788*end = _curchar; // Restore buffer to original condition4789}47904791// Reset _ptr to next char after token4792_ptr = end;47934794return result; // integer4795}479647974798//------------------------------get_relation_dup------------------------------4799// Looks for a relational operator in the buffer4800// invokes a parse_err if the next token is not a relation4801// This routine creates a duplicate of the string in the buffer.4802char *ADLParser::get_relation_dup(void) {4803char *result = NULL; // relational operator being returned48044805if( _curline == NULL ) // Return NULL at EOF.4806return NULL;48074808skipws(); // Skip whitespace before relation4809char *start = _ptr; // Store start of relational operator4810char first = *_ptr; // the first character4811if( (first == '=') || (first == '!') || (first == '<') || (first == '>') ) {4812next_char();4813char second = *_ptr; // the second character4814if( (second == '=') ) {4815next_char();4816char tmp = *_ptr;4817*_ptr = '\0'; // NULL terminate4818result = strdup(start); // Duplicate the string4819*_ptr = tmp; // restore buffer4820} else {4821parse_err(SYNERR, "relational operator expected at %s\n", _ptr);4822}4823} else {4824parse_err(SYNERR, "relational operator expected at %s\n", _ptr);4825}48264827return result;4828}4829483048314832//------------------------------get_oplist-------------------------------------4833// Looks for identifier pairs where first must be the name of an operand, and4834// second must be a name unique in the scope of this instruction. Stores the4835// names with a pointer to the OpClassForm of their type in a local name table.4836void ADLParser::get_oplist(NameList ¶meters, FormDict &operands) {4837OpClassForm *opclass = NULL;4838char *ident = NULL;48394840do {4841next_char(); // skip open paren & comma characters4842skipws();4843if (_curchar == ')') break;48444845// Get operand type, and check it against global name table4846ident = get_ident();4847if (ident == NULL) {4848parse_err(SYNERR, "optype identifier expected at %c\n", _curchar);4849return;4850}4851else {4852const Form *form = _globalNames[ident];4853if( form == NULL ) {4854parse_err(SYNERR, "undefined operand type %s\n", ident);4855return;4856}48574858// Check for valid operand type4859OpClassForm *opc = form->is_opclass();4860OperandForm *oper = form->is_operand();4861if((oper == NULL) && (opc == NULL)) {4862parse_err(SYNERR, "identifier %s not operand type\n", ident);4863return;4864}4865opclass = opc;4866}4867// Debugging Stuff4868if (_AD._adl_debug > 1) fprintf(stderr, "\tOperand Type: %s\t", ident);48694870// Get name of operand and add it to local name table4871if( (ident = get_unique_ident(operands, "operand")) == NULL) {4872return;4873}4874// Parameter names must not be global names.4875if( _globalNames[ident] != NULL ) {4876parse_err(SYNERR, "Reuse of global name %s as operand.\n",ident);4877return;4878}4879operands.Insert(ident, opclass);4880parameters.addName(ident);48814882// Debugging Stuff4883if (_AD._adl_debug > 1) fprintf(stderr, "\tOperand Name: %s\n", ident);4884skipws();4885} while(_curchar == ',');48864887if (_curchar != ')') parse_err(SYNERR, "missing ')'\n");4888else {4889next_char(); // set current character position past the close paren4890}4891}489248934894//------------------------------get_effectlist---------------------------------4895// Looks for identifier pairs where first must be the name of a pre-defined,4896// effect, and the second must be the name of an operand defined in the4897// operand list of this instruction. Stores the names with a pointer to the4898// effect form in a local effects table.4899void ADLParser::get_effectlist(FormDict &effects, FormDict &operands, bool& has_call) {4900OperandForm *opForm;4901Effect *eForm;4902char *ident;49034904do {4905next_char(); // skip open paren & comma characters4906skipws();4907if (_curchar == ')') break;49084909// Get effect type, and check it against global name table4910ident = get_ident();4911if (ident == NULL) {4912parse_err(SYNERR, "effect type identifier expected at %c\n", _curchar);4913return;4914}4915else {4916// Check for valid effect type4917const Form *form = _globalNames[ident];4918if( form == NULL ) {4919parse_err(SYNERR, "undefined effect type %s\n", ident);4920return;4921}4922else {4923if( (eForm = form->is_effect()) == NULL) {4924parse_err(SYNERR, "identifier %s not effect type\n", ident);4925return;4926}4927}4928}4929// Debugging Stuff4930if (_AD._adl_debug > 1) fprintf(stderr, "\tEffect Type: %s\t", ident);4931skipws();4932if (eForm->is(Component::CALL)) {4933if (_AD._adl_debug > 1) fprintf(stderr, "\n");4934has_call = true;4935} else {4936// Get name of operand and check that it is in the local name table4937if( (ident = get_unique_ident(effects, "effect")) == NULL) {4938parse_err(SYNERR, "missing operand identifier in effect list\n");4939return;4940}4941const Form *form = operands[ident];4942opForm = form ? form->is_operand() : NULL;4943if( opForm == NULL ) {4944if( form && form->is_opclass() ) {4945const char* cname = form->is_opclass()->_ident;4946parse_err(SYNERR, "operand classes are illegal in effect lists (found %s %s)\n", cname, ident);4947} else {4948parse_err(SYNERR, "undefined operand %s in effect list\n", ident);4949}4950return;4951}4952// Add the pair to the effects table4953effects.Insert(ident, eForm);4954// Debugging Stuff4955if (_AD._adl_debug > 1) fprintf(stderr, "\tOperand Name: %s\n", ident);4956}4957skipws();4958} while(_curchar == ',');49594960if (_curchar != ')') parse_err(SYNERR, "missing ')'\n");4961else {4962next_char(); // set current character position past the close paren4963}4964}496549664967//-------------------------------preproc_line----------------------------------4968// A "#line" keyword has been seen, so parse the rest of the line.4969void ADLParser::preproc_line(void) {4970int line = get_int();4971skipws_no_preproc();4972const char* file = NULL;4973if (_curchar == '"') {4974next_char(); // Move past the initial '"'4975file = _ptr;4976while (true) {4977if (_curchar == '\n') {4978parse_err(SYNERR, "missing '\"' at end of #line directive");4979return;4980}4981if (_curchar == '"') {4982*_ptr = '\0'; // Terminate the string4983next_char();4984skipws_no_preproc();4985break;4986}4987next_char();4988}4989}4990ensure_end_of_line();4991if (file != NULL)4992_AD._ADL_file._name = file;4993_buf.set_linenum(line);4994}49954996//------------------------------preproc_define---------------------------------4997// A "#define" keyword has been seen, so parse the rest of the line.4998void ADLParser::preproc_define(void) {4999char* flag = get_ident_no_preproc();5000skipws_no_preproc();5001// only #define x y is supported for now5002char* def = get_ident_no_preproc();5003_AD.set_preproc_def(flag, def);5004skipws_no_preproc();5005if (_curchar != '\n') {5006parse_err(SYNERR, "non-identifier in preprocessor definition\n");5007}5008}50095010//------------------------------preproc_undef----------------------------------5011// An "#undef" keyword has been seen, so parse the rest of the line.5012void ADLParser::preproc_undef(void) {5013char* flag = get_ident_no_preproc();5014skipws_no_preproc();5015ensure_end_of_line();5016_AD.set_preproc_def(flag, NULL);5017}5018501950205021//------------------------------parse_err--------------------------------------5022// Issue a parser error message, and skip to the end of the current line5023void ADLParser::parse_err(int flag, const char *fmt, ...) {5024va_list args;50255026va_start(args, fmt);5027if (flag == 1)5028_AD._syntax_errs += _AD.emit_msg(0, flag, linenum(), fmt, args);5029else if (flag == 2)5030_AD._semantic_errs += _AD.emit_msg(0, flag, linenum(), fmt, args);5031else5032_AD._warnings += _AD.emit_msg(0, flag, linenum(), fmt, args);50335034int error_char = _curchar;5035char* error_ptr = _ptr+1;5036for(;*_ptr != '\n'; _ptr++) ; // Skip to the end of the current line5037_curchar = '\n';5038va_end(args);5039_AD._no_output = 1;50405041if (flag == 1) {5042char* error_tail = strchr(error_ptr, '\n');5043char tem = *error_ptr;5044error_ptr[-1] = '\0';5045char* error_head = error_ptr-1;5046while (error_head > _curline && *error_head) --error_head;5047if (error_tail) *error_tail = '\0';5048fprintf(stderr, "Error Context: %s>>>%c<<<%s\n",5049error_head, error_char, error_ptr);5050if (error_tail) *error_tail = '\n';5051error_ptr[-1] = tem;5052}5053}50545055//---------------------------ensure_start_of_line------------------------------5056// A preprocessor directive has been encountered. Be sure it has fallen at5057// the beginning of a line, or else report an error.5058void ADLParser::ensure_start_of_line(void) {5059if (_curchar == '\n') { next_line(); return; }5060assert( _ptr >= _curline && _ptr < _curline+strlen(_curline),5061"Must be able to find which line we are in" );50625063for (char *s = _curline; s < _ptr; s++) {5064if (*s > ' ') {5065parse_err(SYNERR, "'%c' must be at beginning of line\n", _curchar);5066break;5067}5068}5069}50705071//---------------------------ensure_end_of_line--------------------------------5072// A preprocessor directive has been parsed. Be sure there is no trailing5073// garbage at the end of this line. Set the scan point to the beginning of5074// the next line.5075void ADLParser::ensure_end_of_line(void) {5076skipws_no_preproc();5077if (_curchar != '\n' && _curchar != '\0') {5078parse_err(SYNERR, "garbage char '%c' at end of line\n", _curchar);5079} else {5080next_char_or_line();5081}5082}50835084//---------------------------handle_preproc------------------------------------5085// The '#' character introducing a preprocessor directive has been found.5086// Parse the whole directive name (e.g., #define, #endif) and take appropriate5087// action. If we are in an "untaken" span of text, simply keep track of5088// #ifdef nesting structure, so we can find out when to start taking text5089// again. (In this state, we "sort of support" C's #if directives, enough5090// to disregard their associated #else and #endif lines.) If we are in a5091// "taken" span of text, there are two cases: "#define" and "#undef"5092// directives are preserved and passed up to the caller, which eventually5093// passes control to the top-level parser loop, which handles #define and5094// #undef directly. (This prevents these directives from occurring in5095// arbitrary positions in the AD file--we require better structure than C.)5096// In the other case, and #ifdef, #ifndef, #else, or #endif is silently5097// processed as whitespace, with the "taken" state of the text correctly5098// updated. This routine returns "false" exactly in the case of a "taken"5099// #define or #undef, which tells the caller that a preprocessor token5100// has appeared which must be handled explicitly by the parse loop.5101bool ADLParser::handle_preproc_token() {5102assert(*_ptr == '#', "must be at start of preproc");5103ensure_start_of_line();5104next_char();5105skipws_no_preproc();5106char* start_ident = _ptr;5107char* ident = (_curchar == '\n') ? NULL : get_ident_no_preproc();5108if (ident == NULL) {5109parse_err(SYNERR, "expected preprocessor command, got end of line\n");5110} else if (!strcmp(ident, "ifdef") ||5111!strcmp(ident, "ifndef")) {5112char* flag = get_ident_no_preproc();5113ensure_end_of_line();5114// Test the identifier only if we are already in taken code:5115bool flag_def = preproc_taken() && (_AD.get_preproc_def(flag) != NULL);5116bool now_taken = !strcmp(ident, "ifdef") ? flag_def : !flag_def;5117begin_if_def(now_taken);5118} else if (!strcmp(ident, "if")) {5119if (preproc_taken())5120parse_err(SYNERR, "unimplemented: #%s %s", ident, _ptr+1);5121next_line();5122// Intelligently skip this nested C preprocessor directive:5123begin_if_def(true);5124} else if (!strcmp(ident, "else")) {5125ensure_end_of_line();5126invert_if_def();5127} else if (!strcmp(ident, "endif")) {5128ensure_end_of_line();5129end_if_def();5130} else if (preproc_taken()) {5131// pass this token up to the main parser as "#define" or "#undef"5132_ptr = start_ident;5133_curchar = *--_ptr;5134if( _curchar != '#' ) {5135parse_err(SYNERR, "no space allowed after # in #define or #undef");5136assert(_curchar == '#', "no space allowed after # in #define or #undef");5137}5138return false;5139}5140return true;5141}51425143//---------------------------skipws_common-------------------------------------5144// Skip whitespace, including comments and newlines, while keeping an accurate5145// line count.5146// Maybe handle certain preprocessor constructs: #ifdef, #ifndef, #else, #endif5147void ADLParser::skipws_common(bool do_preproc) {5148char *start = _ptr;5149char *next = _ptr + 1;51505151if (*_ptr == '\0') {5152// Check for string terminator5153if (_curchar > ' ') return;5154if (_curchar == '\n') {5155if (!do_preproc) return; // let caller handle the newline5156next_line();5157_ptr = _curline; next = _ptr + 1;5158}5159else if (_curchar == '#' ||5160(_curchar == '/' && (*next == '/' || *next == '*'))) {5161parse_err(SYNERR, "unimplemented: comment token in a funny place");5162}5163}5164while(_curline != NULL) { // Check for end of file5165if (*_ptr == '\n') { // keep proper track of new lines5166if (!do_preproc) break; // let caller handle the newline5167next_line();5168_ptr = _curline; next = _ptr + 1;5169}5170else if ((*_ptr == '/') && (*next == '/')) // C++ comment5171do { _ptr++; next++; } while(*_ptr != '\n'); // So go to end of line5172else if ((*_ptr == '/') && (*next == '*')) { // C comment5173_ptr++; next++;5174do {5175_ptr++; next++;5176if (*_ptr == '\n') { // keep proper track of new lines5177next_line(); // skip newlines within comments5178if (_curline == NULL) { // check for end of file5179parse_err(SYNERR, "end-of-file detected inside comment\n");5180break;5181}5182_ptr = _curline; next = _ptr + 1;5183}5184} while(!((*_ptr == '*') && (*next == '/'))); // Go to end of comment5185_ptr = ++next; next++; // increment _ptr past comment end5186}5187else if (do_preproc && *_ptr == '#') {5188// Note that this calls skipws_common(false) recursively!5189bool preproc_handled = handle_preproc_token();5190if (!preproc_handled) {5191if (preproc_taken()) {5192return; // short circuit5193}5194++_ptr; // skip the preprocessor character5195}5196next = _ptr+1;5197} else if(*_ptr > ' ' && !(do_preproc && !preproc_taken())) {5198break;5199}5200else if (*_ptr == '"' || *_ptr == '\'') {5201assert(do_preproc, "only skip strings if doing preproc");5202// skip untaken quoted string5203int qchar = *_ptr;5204while (true) {5205++_ptr;5206if (*_ptr == qchar) { ++_ptr; break; }5207if (*_ptr == '\\') ++_ptr;5208if (*_ptr == '\n' || *_ptr == '\0') {5209parse_err(SYNERR, "newline in string");5210break;5211}5212}5213next = _ptr + 1;5214}5215else { ++_ptr; ++next; }5216}5217if( _curline != NULL ) // at end of file _curchar isn't valid5218_curchar = *_ptr; // reset _curchar to maintain invariant5219}52205221//---------------------------cur_char-----------------------------------------5222char ADLParser::cur_char() {5223return (_curchar);5224}52255226//---------------------------next_char-----------------------------------------5227void ADLParser::next_char() {5228if (_curchar == '\n') parse_err(WARN, "must call next_line!");5229_curchar = *++_ptr;5230// if ( _curchar == '\n' ) {5231// next_line();5232// }5233}52345235//---------------------------next_char_or_line---------------------------------5236void ADLParser::next_char_or_line() {5237if ( _curchar != '\n' ) {5238_curchar = *++_ptr;5239} else {5240next_line();5241_ptr = _curline;5242_curchar = *_ptr; // maintain invariant5243}5244}52455246//---------------------------next_line-----------------------------------------5247void ADLParser::next_line() {5248_curline = _buf.get_line();5249_curchar = ' ';5250}52515252//------------------------get_line_string--------------------------------------5253// Prepended location descriptor, for debugging.5254// Must return a malloced string (that can be freed if desired).5255char* ADLParser::get_line_string(int linenum) {5256const char* file = _AD._ADL_file._name;5257int line = linenum ? linenum : this->linenum();5258char* location = (char *)malloc(strlen(file) + 100);5259sprintf(location, "\n#line %d \"%s\"\n", line, file);5260return location;5261}52625263//-------------------------is_literal_constant---------------------------------5264bool ADLParser::is_literal_constant(const char *param) {5265if (param[0] == 0) return false; // null string5266if (param[0] == '(') return true; // parenthesized expression5267if (param[0] == '0' && (param[1] == 'x' || param[1] == 'X')) {5268// Make sure it's a hex constant.5269int i = 2;5270do {5271if( !ADLParser::is_hex_digit(*(param+i)) ) return false;5272++i;5273} while( *(param+i) != 0 );5274return true;5275}5276return false;5277}52785279//---------------------------is_hex_digit--------------------------------------5280bool ADLParser::is_hex_digit(char digit) {5281return ((digit >= '0') && (digit <= '9'))5282||((digit >= 'a') && (digit <= 'f'))5283||((digit >= 'A') && (digit <= 'F'));5284}52855286//---------------------------is_int_token--------------------------------------5287bool ADLParser::is_int_token(const char* token, int& intval) {5288const char* cp = token;5289while (*cp != '\0' && *cp <= ' ') cp++;5290if (*cp == '-') cp++;5291int ndigit = 0;5292while (*cp >= '0' && *cp <= '9') { cp++; ndigit++; }5293while (*cp != '\0' && *cp <= ' ') cp++;5294if (ndigit == 0 || *cp != '\0') {5295return false;5296}5297intval = atoi(token);5298return true;5299}53005301static const char* skip_expr_ws(const char* str) {5302const char * cp = str;5303while (cp[0]) {5304if (cp[0] <= ' ') {5305++cp;5306} else if (cp[0] == '#') {5307++cp;5308while (cp[0] == ' ') ++cp;5309assert(0 == strncmp(cp, "line", 4), "must be a #line directive");5310const char* eol = strchr(cp, '\n');5311assert(eol != NULL, "must find end of line");5312if (eol == NULL) eol = cp + strlen(cp);5313cp = eol;5314} else {5315break;5316}5317}5318return cp;5319}53205321//-----------------------equivalent_expressions--------------------------------5322bool ADLParser::equivalent_expressions(const char* str1, const char* str2) {5323if (str1 == str2)5324return true;5325else if (str1 == NULL || str2 == NULL)5326return false;5327const char* cp1 = str1;5328const char* cp2 = str2;5329char in_quote = '\0';5330while (cp1[0] && cp2[0]) {5331if (!in_quote) {5332// skip spaces and/or cpp directives5333const char* cp1a = skip_expr_ws(cp1);5334const char* cp2a = skip_expr_ws(cp2);5335if (cp1a > cp1 && cp2a > cp2) {5336cp1 = cp1a; cp2 = cp2a;5337continue;5338}5339if (cp1a > cp1 || cp2a > cp2) break; // fail5340}5341// match one non-space char5342if (cp1[0] != cp2[0]) break; // fail5343char ch = cp1[0];5344cp1++; cp2++;5345// watch for quotes5346if (in_quote && ch == '\\') {5347if (cp1[0] != cp2[0]) break; // fail5348if (!cp1[0]) break;5349cp1++; cp2++;5350}5351if (in_quote && ch == in_quote) {5352in_quote = '\0';5353} else if (!in_quote && (ch == '"' || ch == '\'')) {5354in_quote = ch;5355}5356}5357return (!cp1[0] && !cp2[0]);5358}535953605361//-------------------------------trim------------------------------------------5362void ADLParser::trim(char* &token) {5363while (*token <= ' ') token++;5364char* end = token + strlen(token);5365while (end > token && *(end-1) <= ' ') --end;5366*end = '\0';5367}536853695370