/* Parser 6/6/01 Gabriel Redner */ #include #include #include #include // Test mode - for testing basic C functionality without VxWorks libraries #ifndef __TEST_MODE__ // Socket stuff #include #include #include #include #include #include #include #include #include #endif // #include "parser.hh" #include "server_symb.hh" #include "dev_aliases.hh" //***************************************************************************** // Class Parser //***************************************************************************** // Constructor Parser::Parser() :mStatus(kOK), mIsInBlock(false), mLongBlock(false), mNumDeviceAliases(MAX_NUM_OF_DEV), mNumMemoryTypes(4), mNumGlobals(0), mDepth(0) { // Load standard device aliases (defined in "dev_aliases.hh") mDeviceAliases[0]=DA00; mDeviceAliases[1]=DA01; mDeviceAliases[2]=DA02; mDeviceAliases[3]=DA03; mDeviceAliases[4]=DA04; mDeviceAliases[5]=DA10; mDeviceAliases[6]=DA11; mDeviceAliases[7]=DA12; mDeviceAliases[8]=DA13; mDeviceAliases[9]=DA14; mDeviceAliases[10]=DA21; mDeviceAliases[11]=DA22; mDeviceAliases[12]=DA23; mDeviceAliases[13]=DA24; // Load standard memory type aliases mMemoryTypes[0]="conf"; mMemoryTypes[1]="mem"; mMemoryTypes[2]="fmem"; mMemoryTypes[3]="io"; } // Destructor Parser::~Parser() {} // Process lines until data is found, then return int Parser::ProcessLine(pciWriteData &outData) { // Check whether this parser has been used up if (mStatus == kError) { printf("Can't reuse a parser after error\n"); return Error(); } else if (mStatus == kEOF) { printf("Can't reuse a parser after EOF\n"); return kEOF; } // Variables char *currLine=new char[kMaxDataLength]; int lineType, sts; sts = GetNextLine(currLine); // loop until eof or return while (sts == kOK || sts == kEOF) { if (sts == kEOF) { if (mDepth == 0) break; else { BranchCleanup(); return ProcessLine(outData); } } // Determine what command lineType=GetLineType(currLine); // If not a remark or define, expand '$' symbols if (lineType!=kRemark && lineType!=kDefine) if (!(currLine=ExpandMacros(currLine))) { delete [] currLine; return Error(); } // If not a remark, expand logical OR ("|") statements if (lineType!=kRemark) currLine=ExpandBitwiseOps(currLine); switch ( lineType ) { case kLongWrite: // Data write in long format if (CollectLongDest(outData, currLine) && CollectLongData(outData, currLine)) { EndLine(); return kOK; } else { ErrorPrint(currLine); delete [] currLine; return Error(); } break; case kShortWrite: // Data write in short format if (CollectShortDest(outData, currLine) && CollectShortData(outData, currLine)) { EndLine(); return kOK; } else { ErrorPrint(currLine); delete [] currLine; return Error(); } break; case kBlockStartLong: // Start of a long-format block mIsInBlock=true; mLongBlock=true; // Save dest data to mData if (!CollectLongDest(mData, currLine)) { ErrorPrint(currLine); delete [] currLine; return Error(); } break; case kBlockStartShort: // Start of a short-format block mIsInBlock=true; mLongBlock=false; // Save dest data to mData if (!CollectShortDest(mData, currLine)) { ErrorPrint(currLine); delete [] currLine; return Error(); } break; case kBlockLong: // Inside a long-format block if (!CollectLongData(mData, currLine)) { ErrorPrint(currLine); delete [] currLine; return Error(); } // return stored mData outData=mData; EndLine(); return kOK; break; case kBlockShort: // inside a short-format block if (!(CollectShortData(mData, currLine))) { ErrorPrint(currLine); delete [] currLine; return Error(); } // return stored mData outData=mData; EndLine(); return kOK; break; case kBlockEnd: // block "end" command mIsInBlock=false; break; case kDefine: // Standard definition if (!AddDefinition(SkipNext(currLine, ' '), FindDefinition(SkipNext(currLine, ' ')))) { printf("Error: Couldn't process definition.\n"); delete [] currLine; return Error(); } break; case kLoad: // Load standard definitions from a file // Attempt to set up branch if (BranchSetup(SubString(SkipNext(currLine, '"'), 0, '"')) == kError) { printf("Error opening file %s\n", SubString(SkipNext(currLine, '"'), 0, '"')); delete [] currLine; return Error(); } break; case kLoad_C: // Load C-style definitions from a file // Attempt to set up branch if (BranchSetup(SubString(SkipNext(currLine, '"'), 0, '"')) == kError) { printf("Error opening file %s\n", SubString(SkipNext(currLine, '"'), 0, '"')); delete [] currLine; return Error(); } // Attempt to read definitions if (ProcessCStyleDefinitions()==kError) { printf("Error processing symbol file \"%s\"\n", SubString(SkipNext(currLine, '"'), 0, '"')); delete [] currLine; return Error(); } // Attempt to clean up from branch if (BranchCleanup() == kError) { printf("Error cleaning up from branch file %s\n", SubString(SkipNext(currLine, '"'), 0, '"')); delete [] currLine; return Error(); } // else // printf("Symbol file \"%s\" processed successfully\n", SubString(SkipNext(currLine, '"'), 0, '"')); break; // Load data from an Intel-Hex file - handled by CCrate case kLoad_IHex: // printf("kLoad_IHex command: loading file %s\n", SubString(SkipNext(currLine, '"'), 0, '"')); if (!mIsInBlock) { delete [] currLine; return Error(); } outData=mData; outData.thePtr=SubString(SkipNext(currLine, '"'), 0, '"'); EndLine(); return kIHex; break; // Load data from an ADP file - handled by CPciDevice case kLoad_Adp: // printf("kLoad_Adp command: loading file %s\n", SubString(SkipNext(currLine, '"'), 0, '"')); if (!mIsInBlock) { delete [] currLine; return Error(); } outData=mData; outData.thePtr=SubString(SkipNext(currLine, '"'), 0, '"'); EndLine(); return kAdp; break; case kUnknown: // Error - return false ErrorPrint(currLine); delete [] currLine; return Error(); break; } EndLine(); sts = GetNextLine(currLine); } // while ( (sts = GetNextLine(currLine)) == kOK ) delete [] currLine; mStatus=sts; return sts; } // Process a file of define statements in #define format int Parser::ProcessCStyleDefinitions() { int stat; char *currLine=new char[kMaxDataLength]; char *start, *end; // Loop until eof or return while ( (stat=GetNextLine(currLine)) == kOK ) { if (IsFirst(currLine, "#define ")) { start=currLine+8; end=FindNext(start, ' '); if (end==NULL || end[0]=='\0' || end[1]==' ' || end[1]=='\0' || end[1]=='\n' || end[1]=='/') continue; else { if (!AddCStyleDefinition(start)) { printf("Error in %s: Couldn't process definition.\n", currLine); delete [] currLine; return Error(); } } } } delete [] currLine; if ( stat == kError ) return Error(); else return kEOF; } // Add a macro to the library - read from a c-stule "#define" statement bool Parser::AddCStyleDefinition(const char *inLine, int loc) { // default condition - use next open slot if (loc==-1) loc=mNumGlobals++; // if too many global symbols if (loc>kMaxNumGlobals-1) return false; // set symbol mGlobals[loc]=SubString(inLine, 0, ' '); inLine=SkipNext(inLine, ' '); if (!inLine) return false; // set definition (skip parentheses if present) if (inLine[0]=='(') { inLine++; mDefinitions[loc]=SubString(inLine, 0, ')'); } else mDefinitions[loc]=SubString(inLine, 0, '\0'); return true; } // Add a macro to the library from a regular "define" statement bool Parser::AddDefinition(const char *inLine, int loc) { // default condition - use next open slot if (loc==-1) loc=mNumGlobals++; // if too many global symbols if (loc>kMaxNumGlobals-1) return false; // set symbol mGlobals[loc]=SubString(inLine, 0, ' '); inLine=SkipNext(inLine, '"'); if (!inLine) return false; // set definition mDefinitions[loc]=SubString(inLine, 0, '"'); return true; } // Look up a definition in the library int Parser::FindDefinition(const char *inLine) { // skip symbol identifier if (inLine[0]=='$') inLine++; for (int i=0; i<=mNumGlobals-1; i++) { if (strchr(inLine, ' ')) { if(strcmp(SubString(inLine, 0, ' '), mGlobals[i])==0) return i; } else { if(strcmp(SubString(inLine, 0, '\0'), mGlobals[i]) == 0 ) return i; } } // not found return -1; } // Determine what type of line is being processed int Parser::GetLineType(const char *theLine) const { // Short-circut if inside a block if (mIsInBlock && theLine[0] != 'e' && theLine[0]!='#' && theLine[0]!='l' && theLine[0]!='d') if (mLongBlock) return kBlockLong; else return kBlockShort; // Examine start of line switch ( theLine[0] ) { case '\0': // Null case '#': // Comment case '\n': // Empty case ' ': // Whitespace return kRemark; break; case 'w': if (theLine[1]==' ' ) // starts with "w" return kShortWrite; else // starts with "write" return kLongWrite; break; case 'd': if (IsFirst(theLine, "destination")) // Starts with "destination" return kBlockStartLong; else if (IsFirst(theLine, "dest")) // starts with "dest" return kBlockStartShort; else if (IsFirst(theLine, "def")) return kDefine; break; case 'e': // starts with "end" return kBlockEnd; break; case 'l': if (IsFirst(theLine, "load_C")) return kLoad_C; // starts with "load_C" else if (IsFirst(theLine, "load_I")) return kLoad_IHex; // starts with "load_IHex" else if (IsFirst(theLine, "load_A")) return kLoad_Adp; // starts with "load_ADP" else return kLoad; // starts with "load" break; default: return kUnknown; break; } return kUnknown; // dead code, but it keeps the compiler happy! } // Expand macros on a line char * Parser::ExpandMacros(char *inLine) { char *ret, *loc, *temp; int def; // locate first constant, if any temp=strchr(inLine, '$'); if (!temp) return inLine; else { // Cut off macro string loc=SubString(temp, 0, ' ', '|', '<', '>', '~'); ret=new char[kMaxDataLength]; def=FindDefinition(loc); // if no definiton exists if (def==-1) { printf("\nDefinition of macro \"%s\" not found\n", loc); printf("Couldn't expand macro on this line:\n%s\n", inLine); delete [] loc; delete [] ret; return 0; } // reassemble string ret=strncpy(ret, inLine, (temp-inLine)); ret[temp-inLine]='\0'; ret=strcat(ret, mDefinitions[def]); ret=strcat(ret, inLine+(temp-inLine+strlen(loc))); if ((temp=strchr(loc, ' '))) ret=strcat(ret, temp); delete [] loc; delete [] inLine; return ExpandMacros(ret); } } // Evaluate bitwise operators char * Parser::ExpandBitwiseOps(char *inLine) { char *ret, *temp, *op, *rightNum, *leftNum; unsigned int result=0; // Find first operator op=FindNext(inLine, '|', '<', '>', '&', '^', '~'); if (!op) return inLine; else { ret=new char[kMaxDataLength]; temp=new char[kMaxDataLength]; leftNum=op-1; // Seek back to start of number if (op[0] != '~') while(isdigit((leftNum--)[0])); if (leftNum[0]=='x') leftNum--; else leftNum++; // Different action based on operator type switch (op[0]) { case '|': // bitwise OR rightNum=op+1; result=GetNum(leftNum) | GetNum(rightNum); break; case '<': // left bit shift rightNum=op+2; result=GetNum(leftNum) << GetNum(rightNum); break; case '>': // right bit shift rightNum=op+2; result=GetNum(leftNum) >> GetNum(rightNum); break; case '&': // bitwise AND rightNum=op+1; result=GetNum(leftNum) & GetNum(rightNum); break; case '^': // bitwise XOR rightNum=op+1; result=GetNum(leftNum) ^ GetNum(rightNum); case '~': // bitwise two's complement rightNum=op+1; result= ~ GetNum(rightNum); break; } // reassemble string ret=strncpy(ret, inLine, (leftNum-inLine)); ret[leftNum-inLine+1]='\0'; sprintf(temp, "%x", result); strcat(ret, "0x"); strcat(ret, temp); op=FindNext(rightNum, '|', ' ', '<', '>', '~'); if (op) strcat(ret, op); delete [] temp; delete [] inLine; return ExpandBitwiseOps(ret); } } // Collect destination data in long format bool Parser::CollectLongDest(pciWriteData &outData, const char *inLine) { // See header file for language info // Reads the data following each equals sign bool IsDest=IsFirst(inLine, "destination"); inLine=SkipNext(inLine, '='); if (!inLine || !isdigit(inLine[0])) return false; outData.mbSlotNo=GetNum(inLine); // Read slot number if (!(outData.mbSlotNo>=2 && outData.mbSlotNo<=21)) return false; inLine=SkipNext(inLine, '='); if (!inLine) return false; if (FindNext(inLine, ' ')) outData.deviceAlias=SubString(inLine, 0, ' '); // Read device alias else outData.deviceAlias=SubString(inLine, 0, '\n'); if (!IsValidDeviceAlias(outData.deviceAlias)) return false; if (IsDest) inLine=SkipNext(inLine, '='); else // if it's a regular write command inLine=SkipNext(inLine, '=', 3); if (!inLine) { outData.pciMemoryType="conf"; outData.barOffset=0x10; return true; } if (FindNext(inLine, ' ')) outData.pciMemoryType=SubString(inLine, 0, ' '); // Read memory type else outData.pciMemoryType=SubString(inLine, 0, '\n'); if (!IsValidMemoryType(outData.pciMemoryType)) return false; inLine=SkipNext(inLine, '='); if (!inLine) { outData.barOffset=0x10; return true; } if (!IsFirst(inLine, "bar")) return false; inLine=SkipNext(inLine, 'r'); if (!isdigit(inLine[0]) || !inLine) return false; outData.barOffset=0x10 + GetNum(inLine)*4; // Read BAR offset if (!(outData.barOffset>=0x10 && outData.barOffset<=0x24)) return false; return true; } // Collect destination data in short format bool Parser::CollectShortDest(pciWriteData &outData, const char *inLine) { // See header file for language info // Reads the data following each space bool IsDest=IsFirst(inLine, "dest"); inLine=SkipNext(inLine, ' '); if (!inLine || !isdigit(inLine[0])) return false; outData.mbSlotNo=GetNum(inLine); // Read slot numner if (!(outData.mbSlotNo>=2 && outData.mbSlotNo<=21)) return false; inLine=SkipNext(inLine, ' '); if (!inLine) return false; if (FindNext(inLine, ' ')) outData.deviceAlias=SubString(inLine, 0, ' '); // Read device alias else outData.deviceAlias=SubString(inLine, 0, '\n'); if (!IsValidDeviceAlias(outData.deviceAlias)) return false; if (IsDest) inLine=SkipNext(inLine, ' '); else // if it's a regular write command { inLine=SkipNext(inLine, ' ', 3); } if (!inLine) { outData.pciMemoryType="conf"; outData.barOffset=0x10; return true; } if (FindNext(inLine, ' ')) outData.pciMemoryType=SubString(inLine, 0, ' '); // Read memory type else outData.pciMemoryType=SubString(inLine, 0, '\n'); if (!IsValidMemoryType(outData.pciMemoryType)) return false; inLine=SkipNext(inLine, ' '); if (!inLine) { outData.barOffset=0x10; return true; } if (!IsFirst(inLine, "bar") || !inLine) return false; inLine=SkipNext(inLine, 'r'); if (!isdigit(inLine[0]) || !inLine) return false; outData.barOffset=0x10 + GetNum(inLine)*0x04; // Read BAR offset if (!(outData.barOffset>=0x10 && outData.barOffset<=0x24)) return false; return true; } // Collect write data in long format bool Parser::CollectLongData(pciWriteData &outData, const char *inLine) { // See header file for language info // Reads the data following each equals sign if (IsFirst(inLine, "write")) inLine=SkipNext(inLine, '=', 3); else inLine=SkipNext(inLine, '='); if (!(isdigit(inLine[0]))) return false; outData.offset=GetNum(inLine); // Read memory offset inLine=SkipNext(inLine, '='); if (!(isdigit(inLine[0]))) return false; outData.data=GetNum(inLine); // Read data return true; } // Collect write data in short format bool Parser::CollectShortData(pciWriteData &outData, const char *inLine) { // See header file for language info // Reads the data following each space if (IsFirst(inLine, "w")) inLine=SkipNext(inLine, ' ', 3); if (!(isdigit(inLine[0]))) return false; outData.offset=GetNum(inLine); // Read memory offset inLine=SkipNext(inLine, ' '); if (!(isdigit(inLine[0]))) return false; outData.data=GetNum(inLine); // Read data return true; } // Determine whether specified alias is valid bool Parser::IsValidDeviceAlias(const char *inString) { for (int i=0; i kMaxLoadDepth) return Error(); mFiles[mDepth]=fopen(fileName, "r"); if (!mFiles[mDepth]) return Error(); return kOK; } // Clean up from a file branch int File_Parser::BranchCleanup() { fclose(mFiles[mDepth]); mDepth--; mStatus=kOK; return kOK; } /* // ***************************************************************************** // class Network_Parser // ***************************************************************************** // See top #ifndef __TEST_MODE__ // Constructor Network_Parser::Network_Parser(int inSocket) { if (inSocket == ERROR) mStatus=kError; mSocket=inSocket; } // Destructor Network_Parser::~Network_Parser() {} // Set up for a file branch int Network_Parser::BranchSetup(char *fileName) { if (++mDepth > kMaxLoadDepth) return Error(); // add branch command to filename char *temp=new char[strlen(fileName) + 2]; temp[0]=CONFIG_BRANCH; strcpy(temp+1, fileName); temp[strlen(fileName)+1]='\0'; send(mSocket, temp, (strlen(fileName)+2), 0); return kOK; } // Clean up from a file branch int Network_Parser::BranchCleanup() { mDepth--; mStatus=kOK; return kOK; } // Obtain the next line of data int Network_Parser::GetNextLine(char * & outLine) { // This implementation is meant to save space. A more time-efficient one // would move the char * one byte forward for each call (to bypass the // control byte), leaking one byte each time. int status, bytes; char *temp=new char[kMaxDataLength]; // printf("Sending send request..."); send(mSocket, (char *)(& SEND_CONFIG_LINE), 1, 0); // printf("Done\n"); //printf("Waiting to receve line from client..."); bytes=recv(mSocket, temp, kMaxDataLength, 0); temp[bytes]='\0'; //printf("%d bytes recieved\n", bytes); //printf("Line: %s \n", temp); if (bytes>0) status=temp[0]; else status=CONFIG_ERROR; switch(status) { case CONFIG_ERROR: printf("Error signal recieved from client\n"); delete [] temp; return Error(); break; case CONFIG_EOF: //printf("EOF\n"); mStatus=kEOF; delete [] temp; return kEOF; break; case SEND_CONFIG_LINE: //printf("Line OK\n"); strcpy(outLine, temp+1); delete [] temp; return kOK; break; } return kError; // dead code } // End-of-line processing int Network_Parser::EndLine() { // printf("Sending end line\n"); send(mSocket, (char *)(& SEND_CONFIG_LINE), 1, 0); return kOK; } // Process, then return the error int Network_Parser::Error() { if (mStatus != kError) { mStatus=kError; // printf("Sending error\n"); send(mSocket, (char *)(& CONFIG_ERROR), 1, 0); } return kError; } #endif */ // ***************************************************************************** // Utility non-member functions // See header file "parser.hh" for documentation // ***************************************************************************** const char * SkipNext(const char * inString, char inChar) { while (inString[0]) { if (inString[0] == inChar) return ++inString; inString++; } return 0; } const char * SkipNext(const char *inString, char inChar, int num) { for (int i=1; i<=num; i++) if (inString) inString=SkipNext(inString, inChar); return inString; } char * FindNext(char *inString, char A, char B, char C, char D, char E, char F, char G) { while (inString[0]!='\0' && inString[0]!=A && inString[0]!=B && inString[0]!=C && inString[0]!=D && inString[0]!=E && inString[0]!=F && inString[0]!=G) inString++; if (inString[0]=='\0') return 0; return inString; } const char * FindNext(const char *inString, char A, char B, char C, char D, char E, char F, char G) { while (inString[0]!='\0' && inString[0]!=A && inString[0]!=B && inString[0]!=C && inString[0]!=D && inString[0]!=E && inString[0]!=F && inString[0]!=G) inString++; if (inString[0]=='\0') return 0; return inString; } bool IsFirst(const char *bigString, const char *inString) { for (int i=0; inString[i]!='\0'; i++) { if ((bigString[i]==0) || (bigString[i] != inString[i])) return false; } return true; } char * SubString(const char *inString, int start, int length) { int i; if ( ((int)strlen(inString) < (start+length)) || start < 0 ) return 0; char *retValue=new char[length+1]; retValue[length]='\0'; for (i=start; i<=(start+length-1); i++) retValue[i-start]=inString[i]; return retValue; } char * SubString(const char *inString, int start, char A, char B, char C, char D, char E, char F, char G) { int i; char *retValue=new char[strlen(inString)]; for (i=start; inString[i] != '\0' && inString[i] != A && inString[i] != B && inString[i] != C && inString[i] != D && inString[i] != E && inString[i] != F && inString[i] != G; i++) retValue[i-start]=inString[i]; retValue[i-start]='\0'; return retValue; } unsigned int GetNum(const char *inString) { if (IsFirst(inString, "0x")) return strtoul(inString, 0, 16); else return strtoul(inString, 0, 10); }