/* * Copyright (c) 1987 Fujitsu * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ /* lexer.c -- Lexical scanner for the Macross assembler Chip Morningstar -- Lucasfilm Ltd. 3-November-1984 */ #include "macrossTypes.h" #include "macrossGlobals.h" #include "y.tab.h" #include "debugPrint.h" #include "errorStuff.h" #include "lexer.h" #include "lexerTables.h" #include "listing.h" #include "lookups.h" #include "parserMisc.h" extern int yylval; extern int yydebug; static char lineBuffer[LINE_BUFFER_SIZE] = { '\0' }; static int lineBufferPtr = 0; #define getNextChar() (lineBuffer[lineBufferPtr] ? \ lineBuffer[lineBufferPtr++] : \ readAnotherLine()) /*int getNextChar() {int c;c=xgetNextChar();printf("read '%c'\n",c);return(c);}*/ #define oopsThatWasTheWrongChar(c) { if(lineBufferPtr) \ lineBuffer[--lineBufferPtr] = c; } /*oopsThatWasTheWrongChar(c)char c;{printf("ungetting '%c'\n", c);xoopsThatWasTheWrongChar(c);}*/ #define isAlphabetic(c) (alphabeticCharacterTable[c]) #define isNumeric(c) (numericCharacterTable[c]) #define isAlphaNumeric(c) (alphaNumericCharacterTable[c]) int yylex(void) { int result; result = lexer(); if (yydebug) { printf("lexer returns "); printToken(result); printf(", value=%d (0x%x)\n", yylval, yylval); } return(result); } int lexer(void) { char c; if ((c = skipWhitespaceAndComments()) == EOF) return(lexLiteral(c)); else return((*lexDispatchTable[c])(c)); } void initializeLexDispatchTable(void) { int c; for (c = 0; c < LEX_DISPATCH_TABLE_SIZE; c++) { if (isAlphabetic(c) || c=='$') lexDispatchTable[c] = lexIdentifier; else if (isNumeric(c)) lexDispatchTable[c] = lexNumber; else if (isMacrossLiteralCharacter(c)) lexDispatchTable[c] = lexLiteral; else if (c == '\'') lexDispatchTable[c] = lexCharacterConstant; else if (c == '"') lexDispatchTable[c] = lexStringConstant; else lexDispatchTable[c] = lexOperator; } } bool isMacrossLiteralCharacter(char c) { return(c==':' || c==',' || c=='@' || c=='#' || c=='(' || c==')' || c=='{' || c=='}' || c=='[' || c==']' || c=='\n' || c==EOF); } void snarfAlphanumericString(char c, char *buffer) { char *bufferPtr; bufferPtr = buffer; do { if (bufferPtr < &buffer[MAX_NAME_SIZE]) *bufferPtr++ = c; c = getNextChar(); } while (c!=EOF && isAlphaNumeric(c)); *bufferPtr = '\0'; oopsThatWasTheWrongChar(c); } char nameBuffer[MAX_NAME_SIZE+1]; int lexIdentifier(char c) { int hashValue; snarfAlphanumericString(c, nameBuffer); hashValue = hashString(nameBuffer); if (yylval = lookupOpcode(nameBuffer, hashValue)) return(Opcode); else if (yylval = lookupKeyword(nameBuffer, hashValue)) return(yylval); else if ((yylval = lookupConditionCode(nameBuffer, hashValue)) != (int)NOT_FOUND_COND) return(ConditionCode); else if (yylval = lookupMacroName(nameBuffer, hashValue)) return(MacroName); else { yylval = (int) saveString(nameBuffer); return(Identifier); } } char numberBuffer[MAX_NAME_SIZE+1]; int lexNumber(char c) { int base; int start; snarfAlphanumericString(c, numberBuffer); if (numberBuffer[0] != '0') { base = 10; start = 0; } else if (numberBuffer[1]=='b' || numberBuffer[1]=='B') { base = 2; start = 2; } else if (numberBuffer[1]=='q' || numberBuffer[1]=='Q') { base = 4; start = 2; } else if (numberBuffer[1]=='x' || numberBuffer[1]=='X') { base = 16; start = 2; } else { base = 8; start = 1; } yylval = fancyAtoI(&numberBuffer[start], base); return(Number); } int fancyAtoI(char *buffer, int base) { int value; int digit; char c; value = 0; while (*buffer != '\0') { if ((digit = digitValue(c = *buffer++)) >= base) { error(DIGIT_OUT_OF_RADIX_ERROR, c, base); return(0); } value = value*base + digit; } return(value); } int digitValue(char c) { if (isNumeric(c)) return(c - '0'); else return(toLowerCase(c) - 'a' + 10); } int lexLiteral(char c) { static bool passedEnd = FALSE; yylval = 0; if (c == '\n') { return(EOL); } else if (c == EOF) { if (passedEnd) { return(0); } else { passedEnd = TRUE; return(ENDFILE); } } else { return(c); } } int lexCharacterConstant(void) { char c; yylval = getStringCharacter(input); if (getNextChar() != '\'') { error(UNCLOSED_CHARACTER_CONSTANT_ERROR); while ((c = getNextChar())!='\'' && c!='\n' && c!=EOF) ; } return(Number); } bool escaped; /* true if last string character read was an escape code. */ int getStringCharacter(FILE *input) { char c; char *numberPtr; int result; escaped = FALSE; c = getNextChar(); if (c == '\\') { escaped = TRUE; c = getNextChar(); if (c == '^') return(controlCharacter(getNextChar())); else if ('0'<=c && c<='7') { numberPtr = numberBuffer; while ('0'<=c && c<='7') { *numberPtr++ = c; c = getNextChar(); } *numberPtr = '\0'; oopsThatWasTheWrongChar(c); result = fancyAtoI(numberBuffer, 8); if (result > 0377) error(OCTAL_CHARACTER_TOO_BIG_ERROR, result); return (result % 0377); } else return(escapeCodes[c]); } else return(c); } char stringBuffer[MAX_NAME_SIZE + 1]; int lexStringConstant(void) { char *stringPtr; char c; stringPtr = stringBuffer; while (((c = getStringCharacter(input))!='"' && c!='\n' && c!=EOF) || escaped) *stringPtr++ = c; *stringPtr = '\0'; if (c=='\n' || c==EOF) error(UNCLOSED_STRING_CONSTANT_ERROR); yylval = (int)saveString(stringBuffer); return(TextString); } int lexOperator(char firstC) { char secondC; char thirdC; int op; int oper; secondC = getNextChar(); for (op=0; operatorTable[op].first!='\0'; op++) { if (operatorTable[op].first==firstC && operatorTable[op].second==secondC) break; else if (operatorTable[op].first==firstC && operatorTable[op].second=='\0') { oopsThatWasTheWrongChar(secondC); break; } } if (operatorTable[op].first == '\0') { error(UNRECOGNIZED_SOMETHING_OR_OTHER_ERROR, firstC); return(yylex()); } /* kludge to deal with the two three-character operators: */ if ((oper=operatorTable[op].token)==RIGHT_SHIFT || oper==LEFT_SHIFT) { thirdC = getNextChar(); if (thirdC == '=') { yylval = (int)((oper==RIGHT_SHIFT) ? RIGHT_SHIFT_ASSIGN : LEFT_SHIFT_ASSIGN); return(ASSIGN); } else oopsThatWasTheWrongChar(thirdC); } yylval = (int)operatorTable[op].value; return(operatorTable[op].token); } char controlCharacter(char c) { #define CONTROL_CHARACTER_MASK (~0100) return(c & CONTROL_CHARACTER_MASK); } char skipWhitespaceAndComments(void) { char c; while ((c=getNextChar())==' ' || c=='\t' || c=='/') { if (c == '/') { if ((c = getNextChar()) == '*') { while (TRUE) { while ((c = getNextChar()) != '*') { if (c == EOF) { error(UNCLOSED_COMMENT_ERROR); return(c); } } if ((c = getNextChar()) == '/') { break; } else if (c == '*') { oopsThatWasTheWrongChar(c); } } } else { oopsThatWasTheWrongChar(c); return('/'); } } } if (c == ';') { while ((c = getNextChar()) != '\n') { if (c == EOF) { error(UNCLOSED_LINE_COMMENT_ERROR); return(c); } } } return(c); } int popInputFileStack(void) { fileNameListType *oldFile; if (inputFileStack->nextFileName == NULL) return(EOF); oldFile = inputFileStack; inputFileStack = inputFileStack->nextFileName; qfree(oldFile); currentLineNumber = inputFileStack->lineNumber; currentFileName = inputFileStack->name; cumulativeLineNumber--; fclose(input); if (!inputFileStack->openFlag) { if ((inputFileStack->fildes = fopen(inputFileStack->name, "r")) == NULL) { fatalSystemError(UNABLE_TO_OPEN_INPUT_FILE_ERROR, inputFileStack->name); } else { inputFileStack->openFlag = TRUE; } } input = inputFileStack->fildes; if (includeNestingDepth > 0) { includeNestingDepth--; currentLineNumber--; } return(getNextChar()); } void pushInputFileStack(stringType *fileName) { fileNameListType *newFileName; inputFileStack->lineNumber = currentLineNumber; newFileName = typeAlloc(fileNameListType); if ((input = newFileName->fildes = fopen(fileName, "r")) == NULL) { fatalSystemError(UNABLE_TO_OPEN_INCLUDE_FILE_ERROR, fileName); } newFileName->openFlag = TRUE; newFileName->nextFileName = inputFileStack; inputFileStack = newFileName; currentFileName = newFileName->name = fileName; currentLineNumber = newFileName->lineNumber = 1; includeNestingDepth++; if (statementEvaluationDepth == 1) oopsThatWasTheWrongChar('\n'); /* hack for line #'s */ } void resynchronizeInput(void) { char c; while ((c = getNextChar())!='\n' && c!=EOF) ; oopsThatWasTheWrongChar(c); } bool longLineFlag = FALSE; static bool previousLongLineFlag = FALSE; void saveLineForListing(stringType *line) { if (!previousLongLineFlag) { putw(currentLocationCounter.value, saveFileForPass2); putw(includeNestingDepth, saveFileForPass2); } previousLongLineFlag = longLineFlag; fputs(line, saveFileForPass2); } void saveEOLForListing(void) { putw(-1, saveFileForPass2); putw(includeNestingDepth, saveFileForPass2); fputs("\n", saveFileForPass2); } void saveIndexForListing(statementKindType kindOfStatement, int cumulativeLineNumber) { if (!amExpanding() || !notListable(kindOfStatement)) { putw(kindOfStatement, indexFileForPass2); putw(currentLocationCounter.value, indexFileForPass2); if (amExpanding()) putw(-cumulativeLineNumber, indexFileForPass2); else putw( cumulativeLineNumber, indexFileForPass2); } } void saveEndMifForListing(int cumulativeLineNumber) { putw(MIF_STATEMENT, indexFileForPass2); putw(-1, indexFileForPass2); if (amExpanding()) putw(-cumulativeLineNumber, indexFileForPass2); else putw(cumulativeLineNumber, indexFileForPass2); } void saveListingOff(void) { saveIndexForListing(-1, cumulativeLineNumber); } void saveListingOn(void) { if (currentCodeMode == ABSOLUTE_BUFFER) saveIndexForListing(-1, cumulativeLineNumber); else saveIndexForListing(-2, cumulativeLineNumber); } char * myfgets(char *buffer, int length, FILE *stream) { char *result; char c; result = buffer; while (length-- > 1 && (c = getc(stream)) != EOF && c != '\n') *buffer++ = c; if (c == EOF) { *result = '\0'; return(NULL); } if (length > 0) *buffer++ = c; if (length == 0 && c != '\n') longLineFlag = TRUE; else longLineFlag = FALSE; *buffer = '\0'; return(result); } int readAnotherLine(void) { int result; if (myfgets(lineBuffer, LINE_BUFFER_SIZE, input)) { if (amListing()) saveLineForListing(lineBuffer); lineBufferPtr = 1; result = lineBuffer[0]; } else { result = popInputFileStack(); } currentLineNumber++; cumulativeLineNumber++; return(result); }