/* * C S/SL Processor * * Translated from Turing S/SL Processor V3.01 * by Rayan Zachariassen, February 1988. * * Original code by James R. Cordy, * 14 January 1980 (Revised 2 March 1983) * * * Copyright 1979,1980,1981,1983,1988 The University of Toronto * * This implementation is freely redistributable with the following * two conditions: * * 1. This notice, stating the copyright, origin, and conditions on use, * of this software, must be retained at the beginning of this file * and of any derived works. * * 2. Any use of S/SL technology should acknowledge that fact, as well as * the University of Toronto as the origin of the S/SL system, and * J.R. Cordy and R.C. Holt as its authors. * * * For information about S/SL, see the paper: * * "An Introduction to S/SL: Syntax/Semantic Language" * by R.C. Holt, J.R. Cordy, and D.B. Wortman, * in ACM Transactions on Programming Languages and Systems (TOPLAS), * Vol 4, No. 2, April 1982, Pages 149-178. * * The authors may be contacted through the Computer Systems Research Institute * at the University of Toronto. */ /* * Note: The structure and feel of this program is that of a Pascal * program because it was transliterated from the Turing version of * the Pascal S/SL Processor. * * * This program is the processor for Syntax/Semantic Langauge programs. * An S/SL program must be processed by this program, which will output * C declarations for the constants defining the input tokens, output * tokens, error codes, type values and semantic operation codes used in * the S/SL program and an array constant declaration for the S/SL table * for the program. These declarations must be merged into the global * declarations C S/SL Walker. * * Input files: * sourcefp - the S/SL program source * * Output files: * headerfp - the output constant definitions * for the program * tablefp - the output S/SL table file for * the program * listFile - a listing of the S/SL source * program with table coordinates * in the left margin (if requested) * * The following are recognized options: * * l - produce a listing of the S/SL source * program with table coordinates in the * left margin in listfp * s - summarize usage of symbol and output * tables * T - trace S/SL processor execution * */ #include #include #include #include "hostenv.h" #ifdef HAVE_UNISTD_H #include #endif #ifdef HAVE_STDLIB_H #include #endif extern int optind; extern char *optarg; /* extern char *malloc(); */ #ifndef __STDC__ extern FILE *fopen(); /* extern char *sprintf(); extern int fprintf(); extern int printf(); */ #ifndef strcpy extern char *strcpy(); #endif #ifndef strcmp extern int strcmp(); #endif #ifndef strlen extern int strlen(); #endif extern int atoi(); extern int getopt(); /* extern int tolower(); */ /* extern void abort(); */ /* extern void exit(); */ #endif #ifndef SELFCONTAINED #include "ssl_sst.h" #endif /* The S/SL table file produced by the S/SL Processor */ #include "ssl_sst.c" #define true 1 #define false 0 #define assertionFailure abort() #define xSymbolClass(X) X = symClass[symIndex] #define SymbolValue(X) X = symValue[symIndex] #define SymbolName(X) X = symText[symIndex] #define CurrentSymbolIndex(X) X = symIndex #define ClassOfChoice(X) X = choiceClass[choiceTop] #define CurrentClass(X) X = symCurrentClass #define SymbolParameterClass(X) X = symParmClass[symIndex] #define SymbolResultClass(X) X = symResultClass[symIndex] #define CycleDepth(X) X = cycleTop #define CycleExits(X) X = exitTop - cycleExitIndex[cycleTop] #define EndRules() /*(void)0*/ #define StartRules() /*(void)0*/ #define BeginRule() /*(void)0*/ #define SaveRule() /*(void)0*/ char const * machineOpNames[200] = { "oCall", "oReturn", "oRuleEnd", "oJump", "oInput", "oInputAny", "oInputChoice", "oEmit", "oError", "oChoice", "oChoiceEnd", "oSetParameter", "oSetResult", "oSetResultFromInput", NULL }; const char * errorCodeNames[100] = { "eNoError", "eSyntaxError", "ePrematureEndOfFile", "eExtraneousProgramText", NULL }; #ifdef SELFCONTAINED /* * Primitive S/SL Table Operations: * These will remain the same independent of the * pass and form the fundamental table operations. */ typedef enum { oCall = 0, /* 0 */ oReturn, /* 1 */ oRuleEnd, /* 2 */ oJump, /* 3 */ oInput, /* 4 */ oInputAny, /* 5 */ oInputChoice, /* 6 */ oEmit, /* 7 */ oError, /* 8 */ oChoice, /* 9 */ oChoiceEnd, /* 10 */ oSetParameter, /* 11 */ oSetResult, /* 12 */ oSetResultFromInput, /* 13 */ /* * Pass Dependent Semantic Operations: * These will be different for each pass. The * semantic operations are implemented by the * Semantic Mechanisms of the pass. * There are two basic kinds of semantic operations: * Update operations, which cause an update to the * Semantic Mechanism, and Choice operations, which * return a value based on the state of the Semantic * Mechanism which is then used as the tag in a semantic * choice. Both Update and Choice operations may be * parameterized by a single constant value. */ oEnterCall, /* 14 */ oEmitNullCallAddress, /* 15 */ oResolveCalls, /* 16 */ oSetClass, /* 17 */ oSetClassFromSymbolClass, /* 18 */ oxSetClassFromSymbolValue, /* 19 */ oySetClassFromSymbolResultClass, /* 20 */ ozSetClassFromSymbolParameterClass, /* 21 */ ovSetClassFromChoiceClass, /* 22 */ oChooseClass, /* 23 */ oSetClassValue, /* 24 */ owSetClassValueFromSymbolValue, /* 25 */ oIncrementClassValue, /* 26 */ oEnterNewSymbol, /* 27 */ oLookupSymbol, /* 28 */ oChangeSymbolClass, /* 29 */ oChooseSymbolClass, /* 30 */ oVerifySymbolClass, /* 31 */ oxEnterNewSymbolValue, /* 32 */ oEnterSecondNewSymbolValue, /* 33 */ oEnterSymbolValueFromAddress, /* 34 */ oxChooseSymbolValue, /* 35 */ oEmitSymbolValue, /* 36 */ oxVerifySymbolClassValue, /* 37 */ oxEnterSymbolParameterClass, /* 38 */ oyEnterSymbolResultClass, /* 39 */ oyChooseSymbolResultClass, /* 40 */ oSaveEnclosingSymbol, /* 41 */ oRestoreEnclosingSymbol, /* 42 */ oSaveCurrentSymbol, /* 43 */ oRestoreCurrentSymbol, /* 44 */ oPushCycle, /* 45 */ oPopCycle, /* 46 */ oChooseCycleDepth, /* 47 */ oEmitCycleAddress, /* 48 */ oEnterCycleExit, /* 49 */ oResolveCycleExits, /* 50 */ oxChooseCycleExits, /* 51 */ oPushChoice, /* 52 */ oPopChoice, /* 53 */ oChangeChoiceClass, /* 54 */ oChooseChoiceClass, /* 55 */ oVerifyChoiceSymbolLabel, /* 56 */ oEnterChoiceSymbolLabel, /* 57 */ oxEnterChoiceMerge, /* 58 */ oResolveChoiceMerges, /* 59 */ oEmitChoiceTable, /* 60 */ oxResolveChoiceTableAddress, /* 61 */ oEmitFirstChoiceValue, /* 62 */ oxEmitFirstChoiceAddress, /* 63 */ oStartRules, /* 64 */ oBeginRule, /* 65 */ oSaveRule, /* 66 */ oEndRules, /* 67 */ oGenerateDefinitions, /* 68 */ oGenerateTable, /* 69 */ oEmitValue, /* 70 */ oEmitNullAddress /* 71 */ } TableOperation; #endif /* SELFCONTAINED */ /* S/SL Table Size */ #define sslTableSize 30000 /* Maximum */ /* The S/SL Rule Call Stack Size */ #define sslStackSize 127 #ifdef SELFCONTAINED /* Operation Result Values */ typedef enum { invalid, valid } Validity; #endif /* SELFCONTAINED */ /* Maximum Source Lines */ #define maxLineNumber 9999 /* S/SL System Failure Codes */ typedef enum { fSemanticChoiceFailed, /* 0 */ fChoiceRuleFailed /* 1 */ } FailureCodes; /* S/SL System Failure Code Type */ #ifdef SELFCONTAINED /* Error Signal Codes */ typedef enum { eNoError = 0, /* 0 */ eSyntaxError, /* 1 */ ePrematureEndOfFile, /* 2 */ eExtraneousProgramText, /* 3 */ /* Semantic Errors */ eCycleHasNoExits = 10, /* 10 */ eDuplicateLabel, /* 11 */ eExitNotInCycle, /* 12 */ eIllegalParameterClass, /* 13 */ eIllegalResultClass, /* 14 */ eIllegalNonvaluedReturn, /* 15 */ eIllegalStringSynonym, /* 16 */ eIllegalValuedReturn, /* 17 */ eSymbolPreviouslyDefined, /* 18 */ eUndefinedSymbol, /* 19 */ eWrongDeclaredResultClass, /* 20 */ eWrongLabelClass, /* 21 */ eWrongParameterClass, /* 22 */ eWrongResultClass, /* 23 */ eWrongSymbolClass, /* 24 */ /* Non-S/SL Semantic Errors */ eUnresolvedRule = 30, /* 30 */ eSymbolTooLong, /* 31 */ eNumberTooLarge, /* 32 */ eStringTooLong, /* 33 */ eValueOutOfRange, /* 34 */ eJumpOutOfRange, /* 35 */ /* Fatal Errors */ eSslStackOverflow = 40, /* 40 */ eCallStackOverflow, /* 41 */ eTooManyTotalSymbolChars, /* 42 */ eTooManySymbols, /* 43 */ eTableTooLarge, /* 44 */ eCyclesTooDeep, /* 45 */ eTooManyExits, /* 46 */ eChoicesTooDeep, /* 47 */ eTooManyLabels, /* 48 */ eTooManyMerges, /* 49 */ eTooManyCalls, /* 50 */ eRuleTooLarge, /* 51 */ } ErrorCodes; /* Error Code Type */ #endif /* SELFCONTAINED */ ErrorCodes firstFatalErrorCode = eSslStackOverflow; /* Maximum Error Count */ #define maxErrors 100 #ifdef SELFCONTAINED /* Input Tokens */ typedef enum { /* Nonexistent input token used only in syntax error recovery */ tSyntaxError = -1, /* -1 */ /* Compound Input Tokens */ tIdent = 0, /* 0 */ tString, /* 1 */ tInteger, /* 2 */ /* Non-Compound Input Tokens */ tColon, /* 3 */ tSemicolon, /* 4 */ tEqual, /* 5 */ tQuestionMark, /* 6 */ tPeriod, /* 7 */ tErrorSignal, /* 8 */ tCall, /* 9 */ tExit, /* 10 */ tReturn, /* 11 */ tLeftParen, /* 12 */ tRightParen, /* 13 */ tCycle, /* 14 */ tCycleEnd, /* 15 */ tChoice, /* 16 */ tChoiceEnd, /* 17 */ tComma, /* 18 */ tOr, /* 19 */ tOtherwise, /* 20 */ tInput, /* 21 */ tOutput, /* 22 */ tError, /* 23 */ tType, /* 24 */ tMechanism, /* 25 */ tRules, /* 26 */ tEnd, /* 27 */ tNewLine, /* 28 */ tEndOfFile, /* 29 */ /* Special token returned by Input Scanner for garbage */ tIllegal /* 30 */ } InputTokens; /* Input Token Type */ #endif /* SELFCONTAINED */ InputTokens firstCompoundToken = tIdent; InputTokens lastCompoundToken = tInteger; InputTokens firstInputToken = tSyntaxError; InputTokens lastInputToken = tIllegal; /* Input Scanner Limits and Parameters */ #define maxInputTokenLength 100 /* must be <= 127 */ #define maxIdentLength maxInputTokenLength #define maxStringLiteralLength maxIdentLength #define maxNumberLength 5 /* Character Constants */ #define newline '\n' #define tab '\t' #define blank ' ' #define quote '\'' #define breakChar '_' #ifdef SELFCONTAINED /* * Output Tokens for the S/SL Processor, * these are the primitive operations of S/SL */ typedef enum { aCall = oCall, aReturn = oReturn, aRuleEnd = oRuleEnd, aJump = oJump, aInput = oInput, aInputAny = oInputAny, aInputChoice = oInputChoice, aEmit = oEmit, aError = oError, aChoice = oChoice, aChoiceEnd = oChoiceEnd, aSetParameter = oSetParameter, aSetResult = oSetResult, aSetResultFromInput = oSetResultFromInput } OutputTokens; /* Output Token Type */ #endif /* SELFCONTAINED */ /* Limits on the Assembled Output S/SL Table */ #define maxOutputTableSize 30000 #define nullAddress -7777 /* * Limits and Constants Associated with the * Semantic Mechanisms of the S/SL Processor */ /* The Symbol Table */ #ifdef SELFCONTAINED /* Classes of Symbols */ typedef enum { cNotFound = 0, /* 0 */ cInput, /* 1 */ cOutput, /* 2 */ cInputOutput, /* 3 */ cError, /* 4 */ cType, /* 5 */ cMechanism, /* 6 */ cUpdateOp, /* 7 */ cParmUpdateOp, /* 8 */ cChoiceOp, /* 9 */ cParmChoiceOp, /* 10 */ cRule, /* 11 */ cChoiceRule, /* 12 */ maxClasses = 50 /* 50 */ } SymbolClass; #endif /* SELFCONTAINED */ SymbolClass firstTypeClass = (SymbolClass)(((int)cChoiceRule) + 1); /* Symbol Table Limits */ #define maxSymbolChars 30000 /* Total length of all identifiers */ #define maxSymbols 1500 /* Symbol index of nonexistent symbol */ #define notFound 0 /* First values for classes */ ErrorCodes firstUserErrorSignalValue = eCycleHasNoExits; TableOperation firstUserSemanticOperationValue = oEnterCall; /* Undefined value */ #ifdef SELFCONTAINED typedef enum { zero = 0, undefined = -9999 } Integer; #endif /* SELFCONTAINED */ #define nullValue (int)undefined /* The Call Table */ #define maxCalls 2000 #define maxCallsPlusOne (maxCalls+1) /* The Cycle Stack */ #define maxExits 30 /* Pending resolution */ #define maxCycles 15 /* Deep */ /* The Choice Stack */ #define maxMerges 100 /* Pending resolution */ #define maxLabels 100 /* Active */ #define maxChoices 15 /* Deep */ /* Assembled S/SL Table Index */ typedef u_int OutputAddress; /* 0 .. maxOutputTableSize */ /* Types Used in the Semantic Mechanisms of the S/SL Processor */ /* The Symbol Table */ typedef int SymbolIndex; /* 0 .. maxSymbols */ /* Standard Characters */ #define newpage '\f' #define endfile -1 /* The Syntax/Semantic Table */ typedef int boolean; typedef int sslPointerRange; /* 0 .. sslTableSize */ /* Table Walker State */ boolean processing = true; sslPointerRange sslPointer = 0; TableOperation operation; /* Abort Flag */ boolean abortflag = false; /* * The S/SL Rule Call Stack: * The Rule Call Stack implements Syntax/Semantic * Language rule call and return. * Each time an oCall operation is executed, * the table return address is pushed onto the * Rule Call Stack. When an oReturn is executed, * the return address is popped from the stack. * An oReturn executed when the Rule Call Stack is * empty terminates table execution. */ typedef int sslTableIndex; /* 0 .. sslTableSize */ /*X: 1 base in turing */ typedef int sslStackIndex; /* 0 .. sslStackSize */ sslTableIndex sslStack[sslStackSize]; sslStackIndex sslTop = 0; /* * Choice Match Flag: * Set by the Choice Handler to indicate whether * a match was made or the otherwise path was taken. * Set to true if a match was made and false otherwise. * This flag is used in input choices to indicate * whether the choice input token should be accepted or * not. */ boolean choiceTagMatched; /* * Parameterized And Choice Semantic Operation Values: * These are used to hold the decoded parameter value to * a parameterized semantic operation and the result * value returned by a choice semantic operation * or rule respectively. */ int parameterValue; int resultValue; /* Line Counters */ int nextLineNumber = 0; int lineNumber; /* Error Counter */ int noErrors = 0; typedef char InputText[maxInputTokenLength]; /* Input Interface */ InputTokens nextToken; int nextTokenValue; InputText nextTokenText; /* * The Compound Input Token Buffer * When a compound input token is accepted from * the input stream, its associated value is * saved in the compound token buffer for use by * the Semantic Mechanisms of the pass. */ InputTokens compoundToken; /* Last compound input token accepted */ int compoundValue; /* Its associated value */ InputText compoundText; /* Variables Used in Syntax Error Recovery */ boolean newInputLine = false; InputTokens savedToken; /* Input Scanner Interface and Tables */ /* Lookahead Character */ int nextChar; /* Keyword Token Table */ const char *keywordText[] = { "mechanism", "output", "input", "error", "rules", "type", "end", "do", "od", "if", "fi" }; InputTokens keywordToken[] = { tMechanism, tOutput, tInput, tError, tRules, tType, tEnd, tCycle, tCycleEnd, tChoice, tChoiceEnd }; /* Special Symbol Token Table */ int XspecialChar[(int)tIllegal-(int)tSyntaxError+1]; int *specialChar=XspecialChar-(int)tSyntaxError; /* First read flag */ boolean firstChar = true; /* The Assembled Table */ int outputTable[maxOutputTableSize]; const char *outputNameTable[maxOutputTableSize]; OutputAddress outputPointer = 0; /* The Semantic Mechanism Data Structures of the S/SL Processor */ /* The Symbol Table */ SymbolClass symClass[maxSymbols]; const char *symText[maxSymbols]; int symHash[maxSymbols]; int symValue[maxSymbols]; SymbolClass symParmClass[maxSymbols]; SymbolClass symResultClass[maxSymbols]; SymbolIndex symTop = 0; /* * symIndex is the index in the Symbol Table * of the symbol last referenced symIndex = 0 (notFound) * indicates the referenced symbol is not present in the table. */ SymbolIndex symIndex = 0; /* * savedSymIndex is used to save the * the value of symIndex for later recall */ SymbolIndex savedSymIndex; /* * enclosingSymIndex is used to save the symbol index of the * enclosing S/SL rule or type for later recall */ SymbolIndex enclosingSymIndex; /* Next Symbol Value */ int symNextValue[(int)maxClasses]; /* Current Definition Class */ SymbolClass symCurrentClass = cNotFound; /* The Call Table */ OutputAddress callAddress[maxCalls]; /* * callRule is the SymbolIndex of the called rule and * is later resolved to an OutputAddress */ int callRule[maxCalls]; u_int callTop = 0; /* 0 .. maxCalls */ /* The Cycle Stack */ /* The Cycle Exit Stack */ OutputAddress exitAddress[maxExits]; u_int exitTop = 0; /* 0 .. maxExits */ /* The Cycle Stack */ OutputAddress cycleAddress[maxCycles]; /* * cycleExitIndex is the origin of the * portion of the Exit Stack for the cycle */ u_int cycleExitIndex[maxCycles]; u_int cycleTop = 0; /* The Choice Stack */ /* * The Choice Merge Stack: used to save the addresses * of the merge branches following each alternative of a choice */ OutputAddress mergeAddress[maxMerges]; u_int mergeTop = 0; /* * The Choice Label Stack: used to save the alternative * values and corresponding table addresses in a choice */ int labelValue[maxLabels]; OutputAddress labelAddress[maxLabels]; u_int labelTop = 0; /* The Choice Stack */ SymbolClass choiceClass[maxChoices]; OutputAddress choiceAddress[maxChoices]; /* * choiceMergeIndex is the origin of the portion * of the Merge Stack for the choice */ u_int choiceMergeIndex[maxChoices]; /* * choiceLabelIndex is the origin of the portion * of the Label Stack for the choice */ u_int choiceLabelIndex[maxChoices]; u_int choiceTop = 0; /* Input/Output Streams */ FILE *sourcefp; FILE *headerfp; FILE *tablefp; FILE *listfp; FILE *entryfp; char *progname; #ifndef __ #ifdef __STDC__ # define __(x) x #else # define __(x) () #endif #endif extern char *ssl_basename __((char *)); extern char *strsave __((char *)); extern Validity VerifyChoiceLabel __((int)); extern void AcceptInputToken __((void)); extern void ChangeChoiceClass __((SymbolClass)); extern void ChangeSymbolClass __((void)); static void Emit __((const int value, const char *name)); extern void EmitChoiceTable __((void)); extern void EmitCycleAddress __((void)); extern void EmitFirstChoiceAddress __((void)); extern void EmitFixup __((OutputAddress, int, const char *)); extern void EmitJumpAddress __((OutputAddress)); extern void EmitJumpFixup __((OutputAddress)); extern void EmitNullAddress __((void)); extern void EmitNullCallAddress __((void)); extern void EnterCall __((void)); extern void EnterChoiceMerge __((void)); extern void EnterCycleExit __((void)); extern void EnterNewSymbol __((void)); extern void EnterSecondNewSymbolValue __((void)); extern void EnterSymbolValueFromAddress __((void)); extern void Error __((ErrorCodes)); extern void EvaluateNumber __((void)); extern void GenerateClass __((SymbolClass, const char *)); extern void GenerateEntryPoints __((const char *)); extern void GenerateOutputTable __((const char *)); extern void GenerateSymbolDefinitions __((void)); extern void IncrementCurrentClassValue __((void)); extern void InitCallTable __((void)); extern void InitChoiceStack __((void)); extern void InitCycleStack __((void)); extern void InitInputScanner __((void)); extern void InitSymbolTable __((void)); extern void LookupKeyword __((void)); extern void LookupSymbol __((void)); extern void PopChoice __((void)); extern void PopCycle __((void)); extern void PushChoice __((SymbolClass)); extern void PushCycle __((void)); extern void ResolveCalls __((void)); extern void ResolveChoiceMerges __((void)); extern void ResolveCycleExits __((void)); extern void RestoreCurrentSymbol __((void)); extern void RestoreEnclosingSymbol __((void)); extern void SaveCurrentSymbol __((void)); extern void SaveEnclosingSymbol __((void)); extern void SetCurrentSymbol __((SymbolIndex)); extern void SetNextValueOfCurrentClass __((int)); extern void SslChoice __((int)); extern void SslFailure __((FailureCodes)); extern void SslGenerateCompoundInputToken __((InputTokens)); extern void SslSyntaxError __((void)); extern void SslTrace __((void)); extern int hash __((const char *)); extern void xEmitFirstChoiceValue __((void)); extern void xEnterChoiceLabel __((int)); extern void xEnterNewSymbolValue __((void)); extern void xEnterSymbolParameterClass __((void)); extern void xResolveChoiceTableAddress __((void)); extern void xSetCurrentClass __((SymbolClass)); extern void yEnterSymbolResultClass __((void)); boolean tracing; boolean summarize; extern int main __((int argc, char *argv[])); int main(argc, argv) int argc; char *argv[]; { SymbolClass c, d; int ch, errflag; int v; const char *n; boolean listing; char buf[1024 /* PATH_MAX */]; const char *useEnum, *typeName; char *inFile, *tableFile, *headerFile, *listFile, *entryFile; progname = argv[0]; /* Get Run Options */ /* Default no listing, tracing, summary, Turing tables */ tracing = false; summarize = false; listing = false; errflag = 0; inFile = tableFile = headerFile = listFile = entryFile = NULL; typeName = useEnum = NULL; sourcefp = tablefp = headerfp = listfp = entryfp = NULL; while ((ch = getopt(argc, argv, "TLsi:h:t:l:e:E:D:")) != EOF) { switch (ch) { case 'T': tracing = true; break; case 'L': listing = true; break; case 'D': if (*optarg != '\0') typeName = optarg; else ++errflag; break; case 'E': if (*optarg != '\0') useEnum = optarg; else ++errflag; break; case 's': summarize = true; break; case 'i': /* input S/SL code file */ if (*optarg != '\0') inFile = optarg; else ++errflag; break; case 'h': /* output C header file */ if (*optarg != '\0') headerFile = optarg; else ++errflag; break; case 't': /* output C S/SL table file */ if (*optarg != '\0') tableFile = optarg; else ++errflag; break; case 'l': /* output listing file */ if (*optarg != '\0') listFile = optarg; else ++errflag; break; case 'e': /* entry points saved here */ if (*optarg != '\0') entryFile = optarg; else ++errflag; break; default: ++errflag; break; } } if (errflag || argc < optind + 1) { fprintf(stderr, "Usage: %s [-TLs] [-E Name] [-D type] [-h file.sst.h] [-t file.sst.c] [-l file.lst] [-e file.entry] [-i] file.ssl\n", progname); exit(1); } /* Input/Output File Assignments */ if (inFile == NULL && optind >= argc) sourcefp = stdin; else { if (inFile == NULL) inFile = argv[optind++]; if ((sourcefp = fopen(inFile, "r")) == NULL) { fprintf(stderr, "%s: cannot open '%s'\n", progname, inFile); exit(1); } } if (inFile != NULL && headerFile == NULL) sprintf(headerFile = buf, "%s.sst.h", ssl_basename(inFile)); if (headerFile != NULL && (headerfp = fopen(headerFile, "w")) == NULL) { fprintf(stderr, "%s: cannot open '%s'\n", progname, headerFile); exit(1); } if (inFile != NULL && tableFile == NULL) sprintf(tableFile = buf, "%s.sst.c", ssl_basename(inFile)); if (tableFile != NULL && (tablefp = fopen(tableFile, "w")) == NULL) { fprintf(stderr, "%s: cannot open '%s'\n", progname, tableFile); exit(1); } if (inFile != NULL && listFile == NULL && listing) sprintf(listFile = buf, "%s.lst", ssl_basename(inFile)); if (listFile != NULL && (listfp = fopen(listFile, "w")) == NULL) { fprintf(stderr, "%s: cannot open '%s'\n", progname, listFile); exit(1); } if (inFile != NULL && entryFile == NULL) sprintf(entryFile = buf, "%s.entry", ssl_basename(inFile)); if (entryFile != NULL && (entryfp = fopen(entryFile, "w")) == NULL) { fprintf(stderr, "%s: cannot open '%s'\n", progname, entryFile); exit(1); } /* Initialize Table Walker State */ processing = true; sslPointer = 0; sslTop = 0; noErrors = 0; abortflag = false; /* Initialize Semantic Mechanisms */ InitSymbolTable(); InitCallTable(); InitCycleStack(); InitChoiceStack(); /* Initialize Output */ outputPointer = 0; /* Initialize Input */ InitInputScanner(); nextToken = tNewLine; nextLineNumber = 0; newInputLine = false; AcceptInputToken(); /* Walk the S/SL Table */ while (processing) { operation = (TableOperation)sslTable[sslPointer]; ++sslPointer; /* Trace Execution */ if (tracing) SslTrace(); switch (operation) { case oCall: if (sslTop < sslStackSize) { sslStack[++sslTop] = sslPointer + 1; sslPointer = sslTable[sslPointer]; } else { Error(eSslStackOverflow); processing = false; } break; case oReturn: if (sslTop == 0) /* Return from main S/SL rule */ processing = false; else sslPointer = sslStack[sslTop--]; break; case oRuleEnd: SslFailure(fChoiceRuleFailed); break; case oJump: sslPointer = sslTable[sslPointer]; break; case oInput: if (sslTable[sslPointer] == (int)nextToken) AcceptInputToken(); else /* Syntax error in input */ SslSyntaxError(); ++sslPointer; break; case oInputAny: if (nextToken != tEndOfFile) AcceptInputToken(); else /* Premature end of file */ SslSyntaxError(); break; case oInputChoice: SslChoice(nextToken); if (choiceTagMatched) AcceptInputToken(); break; case oEmit: Emit(sslTable[sslPointer], machineOpNames[sslTable[sslPointer]]); ++sslPointer; break; case oError: Error((ErrorCodes)sslTable[sslPointer]); ++sslPointer; break; case oChoice: SslChoice(resultValue); break; case oChoiceEnd: SslFailure(fSemanticChoiceFailed); break; case oSetParameter: parameterValue = sslTable[sslPointer]; ++sslPointer; break; case oSetResult: resultValue = sslTable[sslPointer]; ++sslPointer; break; case oSetResultFromInput: resultValue = (int)nextToken; break; /* Semantic Operations of the S/SL Processor */ /* Call Table Mechanism Operations */ case oEnterCall: EnterCall(); break; case oEmitNullCallAddress: EmitNullCallAddress(); break; case oResolveCalls: ResolveCalls(); break; /* Symbol Table Mechanism Operations */ case oSetClass: xSetCurrentClass((SymbolClass)parameterValue); break; case oSetClassFromSymbolClass: xSymbolClass(c); xSetCurrentClass(c); break; case oxSetClassFromSymbolValue: SymbolValue(v); xSetCurrentClass((SymbolClass)v); break; case oySetClassFromSymbolResultClass: SymbolResultClass(c); xSetCurrentClass(c); break; case ozSetClassFromSymbolParameterClass: SymbolParameterClass(c); xSetCurrentClass(c); break; case ovSetClassFromChoiceClass: ClassOfChoice(c); xSetCurrentClass(c); break; case oChooseClass: CurrentClass(c); resultValue = (int)c; break; case oSetClassValue: SetNextValueOfCurrentClass(compoundValue); break; case owSetClassValueFromSymbolValue: SymbolValue(v); SetNextValueOfCurrentClass(v); break; case oIncrementClassValue: IncrementCurrentClassValue(); break; case oEnterNewSymbol: EnterNewSymbol(); break; case oLookupSymbol: LookupSymbol(); break; case oChangeSymbolClass: ChangeSymbolClass(); break; case oChooseSymbolClass: xSymbolClass(c); resultValue = (int)c; break; case oVerifySymbolClass: xSymbolClass(c); CurrentClass(d); if (c == d) resultValue = (int)valid; else resultValue = (int)invalid; break; case oxEnterNewSymbolValue: xEnterNewSymbolValue(); break; case oEnterSecondNewSymbolValue: EnterSecondNewSymbolValue(); break; case oEnterSymbolValueFromAddress: EnterSymbolValueFromAddress(); break; case oxChooseSymbolValue: SymbolValue(resultValue); break; case oEmitSymbolValue: SymbolValue(v); SymbolName(n); Emit(v,n); break; case oxVerifySymbolClassValue: SymbolValue(v); CurrentClass(c); if (v == (int)c) resultValue = (int)valid; else resultValue = (int)invalid; break; case oxEnterSymbolParameterClass: xEnterSymbolParameterClass(); break; case oyEnterSymbolResultClass: yEnterSymbolResultClass(); break; case oyChooseSymbolResultClass: SymbolResultClass(c); resultValue = (int)c; break; case oSaveEnclosingSymbol: SaveEnclosingSymbol(); break; case oRestoreEnclosingSymbol: RestoreEnclosingSymbol(); break; case oSaveCurrentSymbol: SaveCurrentSymbol(); break; case oRestoreCurrentSymbol: RestoreCurrentSymbol(); break; /* Cycle Stack Mechanism Operations */ case oPushCycle: PushCycle(); break; case oPopCycle: PopCycle(); break; case oChooseCycleDepth: CycleDepth(resultValue); break; case oEmitCycleAddress: EmitCycleAddress(); break; case oEnterCycleExit: EnterCycleExit(); break; case oResolveCycleExits: ResolveCycleExits(); break; case oxChooseCycleExits: CycleExits(resultValue); break; /* Choice Stack Mechanism Operations */ case oPushChoice: CurrentClass(c); PushChoice(c); break; case oPopChoice: PopChoice(); break; case oChangeChoiceClass: CurrentClass(c); ChangeChoiceClass(c); break; case oChooseChoiceClass: ClassOfChoice(c); resultValue = (int)c; break; case oVerifyChoiceSymbolLabel: SymbolValue(v); resultValue = (int)VerifyChoiceLabel(v); break; case oEnterChoiceSymbolLabel: SymbolValue(v); xEnterChoiceLabel(v); break; case oxEnterChoiceMerge: EnterChoiceMerge(); break; case oResolveChoiceMerges: ResolveChoiceMerges(); break; case oEmitChoiceTable: EmitChoiceTable(); break; case oxResolveChoiceTableAddress: xResolveChoiceTableAddress(); break; case oEmitFirstChoiceValue: xEmitFirstChoiceValue(); break; case oxEmitFirstChoiceAddress: EmitFirstChoiceAddress(); break; /* Rule Table Operations */ case oStartRules: StartRules(); break; case oBeginRule: BeginRule(); break; case oSaveRule: SaveRule(); break; case oEndRules: EndRules(); break; /* Generate Output Operations */ case oGenerateDefinitions: GenerateSymbolDefinitions(); break; case oGenerateTable: GenerateOutputTable(typeName); GenerateEntryPoints(useEnum); break; /* Miscellaneous Output Operations */ case oEmitValue: Emit(compoundValue,strsave(compoundText)); break; case oEmitNullAddress: EmitNullAddress(); break; default: break; } } if (nextToken != tEndOfFile && !abortflag) Error(eExtraneousProgramText); /* Summarize Table Usage if Requested */ if (summarize) printf("%d/%d table entries, %d/%d symbols, %d/%d calls.\n", outputPointer+1, maxOutputTableSize, symTop, maxSymbols, callTop, maxCalls); exit(0); } char * ssl_basename(s) char *s; { char *cp; if (strlen(s) > 4 && strcmp(s + strlen(s) - 4, ".ssl") == 0) { cp = strsave(s); *(cp+strlen(cp)-4) = '\0'; return cp; } return s; } char * strsave(s) char *s; { char *cp; cp = (char*)malloc(strlen(s)+1); strcpy(cp, s); return cp; } int hash(s) register const char *s; { int i; for (i = 1; *s != '\0'; ++s, i>>=1) i *= *s; return i; } extern char *LowerCase __((const char *s)); char * LowerCase(s) register const char *s; { static char buf[BUFSIZ]; char *cp; for (cp = buf; *s != '\0'; ++s, ++cp) { int c = (*s) & 0xFF; if (isascii(c) && isupper(c)) *cp = tolower(c); else *cp = c; } *cp = '\0'; return buf; } /* This procedure Emits the error message associated with errCode */ void Error(errCode) ErrorCodes errCode; { if (errCode == eNoError) assertionFailure; printf("Line "); if (errCode == eSyntaxError) { /* Syntax errors are in the lookahead token */ printf("%d", nextLineNumber); } else { /* Semantic errors are in the accepted token */ printf("%d", lineNumber); } printf(": "); switch (errCode) { case eSyntaxError: printf("Syntax error at '%s'\n", nextTokenText); break; case ePrematureEndOfFile: printf("Unexpected end of file\n"); break; case eExtraneousProgramText: printf("Extraneous program text\n"); break; case eSymbolTooLong: printf("Symbol too long\n"); break; case eNumberTooLarge: printf("Integer value too large (or small)\n"); break; case eStringTooLong: printf("String too long\n"); break; case eUndefinedSymbol: printf("Symbol '%s' undefined\n", compoundText); break; case eSymbolPreviouslyDefined: printf("Symbol '%s' previously defined\n", compoundText); break; case eWrongSymbolClass: printf("Illegal context for symbol '%s'\n", compoundText); break; case eUnresolvedRule: printf("Rule '%s' undefined\n", compoundText); break; case eValueOutOfRange: printf("Symbol value not in table value range\n"); break; case eJumpOutOfRange: printf("Jump distance exceeds table value range\n"); break; case eIllegalStringSynonym: printf("Illegal string synonym\n"); break; case eTooManyTotalSymbolChars: printf("Too many symbols (chars)\n"); break; case eTooManySymbols: printf("Too many symbols\n"); break; case eTableTooLarge: printf("Table too large\n"); break; case eRuleTooLarge: printf("Rule too large\n"); break; case eTooManyCalls: printf("Too many rule calls\n"); break; case eCyclesTooDeep: printf("Cycles too deep\n"); break; case eChoicesTooDeep: printf("Choices too deep\n"); break; case eTooManyExits: printf("Too many cycle exits\n"); break; case eTooManyLabels: case eTooManyMerges: printf("Too many alternatives\n"); break; case eCycleHasNoExits: printf("(Warning) Cycle does not contain a cycle exit\n"); break; case eExitNotInCycle: printf("Cycle exit not in cycle\n"); break; case eDuplicateLabel: printf("Duplicate alternative label\n"); break; case eIllegalParameterClass: case eIllegalResultClass: printf("Type name required as parameter or result type\n"); break; case eIllegalNonvaluedReturn: printf("Non-valued return in choice rule\n"); break; case eIllegalValuedReturn: printf("Valued return in procedure rule\n"); break; case eWrongLabelClass: printf("Alternative label is wrong type\n"); break; case eWrongParameterClass: printf("Parameter is wrong type\n"); break; case eWrongDeclaredResultClass: printf("Result type does not match previous use\n"); break; case eWrongResultClass: printf("Result value is wrong type\n"); break; default: break; } ++noErrors; if (((int)errCode) >= ((int)firstFatalErrorCode) || noErrors == maxErrors) { printf("*** Processing aborted\n"); abortflag = true; processing = false; } } extern void ReadNextChar __((void)); void ReadNextChar() { if (listfp) { if (firstChar) firstChar = false; else if (nextChar == newline) putc('\n', listfp); else if (nextChar != endfile) putc(nextChar, listfp); if (nextChar == newline) { nextChar = getc(sourcefp); if (nextChar != EOF) fprintf(listfp, "%4d\t", outputPointer); return; } } nextChar = getc(sourcefp); } void EvaluateNumber() { if (nextToken != tInteger || nextTokenText[0] == '\0' || (strlen(nextTokenText) > maxNumberLength && (nextTokenText[0] != '-' || strlen(nextTokenText) > maxNumberLength+1))) assertionFailure; nextTokenValue = atoi(nextTokenText); } void LookupKeyword() { char *nt; u_int i; if (nextToken != tIdent || nextTokenText[0] == '\0') assertionFailure; nt = LowerCase(nextTokenText); /* The keyword table is ordered by length, longest first */ if (strlen(nt) <= strlen(keywordText[0])) /* the longest */ { for (i=0; i < (sizeof keywordText)/(sizeof keywordText[0]); ++i) if (strcmp(nt, keywordText[i]) == 0) { nextToken = keywordToken[i]; return; } } } extern void GetNextInputToken __((void)); void GetNextInputToken() { InputTokens t; ErrorCodes errCode; int i; if (maxInputTokenLength < maxIdentLength || maxInputTokenLength < maxStringLiteralLength || maxInputTokenLength < maxNumberLength) assertionFailure; errCode = eNoError; /* Skip blanks and comments */ while (nextChar == blank || nextChar == tab || nextChar == newpage || nextChar == '%') { if (nextChar == '%') { /* Skip comment */ do ReadNextChar(); while (nextChar != newline && nextChar != endfile); } else ReadNextChar(); } /* Scan and set nextToken */ i = 0; nextTokenText[0] = '\0'; nextTokenValue = 0; if (isascii(nextChar) && isalpha(nextChar)) { /* Scan identifier */ do { if (i < maxIdentLength) nextTokenText[i++] = nextChar; else errCode = eSymbolTooLong; ReadNextChar(); } while (isalpha(nextChar) && isalnum(nextChar)); nextToken = tIdent; /* Test for Keyword */ nextTokenText[i] = '\0'; LookupKeyword(); } else if (nextChar=='-' || (isascii(nextChar) && isdigit(nextChar))) { /* Scan number */ if (nextChar == '-') { nextTokenText[i++] = nextChar; ReadNextChar(); } if (maxInputTokenLength <= maxNumberLength+1) assertionFailure; do { if (i < maxNumberLength+2) nextTokenText[i++] = nextChar; ReadNextChar(); } while (isascii(nextChar) && isdigit(nextChar)); nextToken = tInteger; if (i > maxNumberLength+1 || (nextTokenText[0] != '-' && i > maxNumberLength)) { errCode = eNumberTooLarge; nextTokenValue = 0; } else { nextTokenText[i] = '\0'; EvaluateNumber(); } } else if (nextChar == quote) { /* Scan String */ nextChar = '"'; do { if (i < maxStringLiteralLength-1) nextTokenText[i++] = nextChar; else errCode = eStringTooLong; ReadNextChar(); } while (nextChar != quote && nextChar != newline && nextChar != endfile); nextTokenText[i++] = /*quote*/ '"'; nextTokenText[i] = '\0'; if (nextChar == quote) ReadNextChar(); nextToken = tString; } else { /* Special Symbols */ if (lastInputToken != tIllegal) assertionFailure; for (t = firstInputToken; t != lastInputToken; t = (InputTokens)((int)t + 1)) if (specialChar[(int)t] == nextChar) break; nextToken = t; nextTokenText[0] = nextChar; nextTokenText[1] = '\0'; ReadNextChar(); if (nextToken == tExit && nextChar == '>') { nextToken = tReturn; ReadNextChar(); } else if (nextToken == tIllegal && nextTokenText[0] == '!') { /* Alternate for tOr */ nextToken = tOr; } if (nextToken == tIllegal) /* XX: fix this later */ abort(); } if (errCode != eNoError) Error(errCode); } void InitInputScanner() { InputTokens t; /* Initialize Special Character Table */ for (t = firstInputToken; ((int)t) <= ((int)lastInputToken); t = (InputTokens)((int)t + 1)) specialChar[(int)t] = blank; specialChar[(int)tColon] = ':'; specialChar[(int)tSemicolon] = ';'; specialChar[(int)tEqual] = '='; specialChar[(int)tQuestionMark] = '?'; specialChar[(int)tPeriod] = '.'; specialChar[(int)tErrorSignal] = '#'; specialChar[(int)tCall] = '@'; specialChar[(int)tExit] = '>'; specialChar[(int)tReturn] = blank; /* tReturn handled specially */ specialChar[(int)tLeftParen] = '('; specialChar[(int)tRightParen] = ')'; specialChar[(int)tCycle] = '{'; specialChar[(int)tCycleEnd] = '}'; specialChar[(int)tChoice] = '['; specialChar[(int)tChoiceEnd] = ']'; specialChar[(int)tComma] = ','; specialChar[(int)tOr] = '|'; /* alternate '!' handled specially */ specialChar[(int)tOtherwise] = '*'; specialChar[(int)tNewLine] = newline; specialChar[(int)tEndOfFile] = endfile; specialChar[(int)tIllegal] = blank; /* tIllegal handled specially */ /* Initialize Lookahead */ nextChar = newline; firstChar = true; } void AcceptInputToken() { InputTokens acceptedToken; if (nextToken == tEndOfFile) assertionFailure; /* Accept Token */ acceptedToken = nextToken; if (acceptedToken == tIdent || acceptedToken == tString || acceptedToken == tInteger) { compoundToken = acceptedToken; strcpy(compoundText, nextTokenText); compoundValue = nextTokenValue; } /* Update Line Number */ lineNumber = nextLineNumber; /* Get Next Input Token */ newInputLine = false; do { GetNextInputToken(); if (nextToken == tNewLine) { /* Update Line Counter and Set Flag */ newInputLine = true; if (nextLineNumber < maxLineNumber) ++nextLineNumber; else nextLineNumber = 0; } } while (nextToken == tNewLine); /* Trace input */ if (tracing) printf("Input token accepted %d Line %d Next input token %d\n", acceptedToken, lineNumber, nextToken); } /* Emit an output table element to the assembled table */ static void Emit(value,name) const int value; const char *name; { if (name && *name == '?') name = NULL; if (outputPointer < maxOutputTableSize) { outputTable[outputPointer] = value; outputNameTable[outputPointer] = name; ++outputPointer; /* Trace Table Assembly */ if (tracing) printf("Output emitted at %d: %d (%s)\n", outputPointer-1, value, name); } else Error(eTableTooLarge); } /* Fixup a previously emitted table location to a resolved value */ void EmitFixup(fixupAddress, value, name) OutputAddress fixupAddress; int value; const char *name; { if (fixupAddress >= outputPointer || outputTable[fixupAddress] != nullAddress) assertionFailure; outputTable[fixupAddress] = value; outputNameTable[fixupAddress] = NULL /*name*/; /* Trace Table Assembly */ if (tracing) printf("Output fixup at %d: %d (%s)\n", fixupAddress, value,name); } /* Reserve a table location to be fixed up */ extern void EmitNullAddress __((void)); void EmitNullAddress() { Emit(nullAddress,NULL); } /* Emit a backward jump address. Jump addresses are absolute. */ void EmitJumpAddress(targetAddress) OutputAddress targetAddress; { Emit((int)targetAddress,NULL); } /* Fixup a forward jump address. Jump addresses are absolute. */ void EmitJumpFixup(jumpAddress) OutputAddress jumpAddress; { EmitFixup(jumpAddress, (int)outputPointer, NULL); } void EmitNullCallAddress() { EmitNullAddress(); } /* * The Symbol Table Mechanism * * The Symbol Table is used to keep track of defined symbols * in the S/SL program. It provides facilities to save defined * symbols, resolve referenced symbols, and keep track of symbol * values and parameter and result types. */ void EnterNewSymbol() { if ((compoundToken != tIdent && compoundToken != tString) || strlen(compoundText) == 0) assertionFailure; /* Enter in the Symbol Table */ if (symTop < maxSymbols) { ++symTop; symText[symTop] = strsave(compoundText); symHash[symTop] = hash(LowerCase(compoundText)); symClass[symTop] = symCurrentClass; symValue[symTop] = nullValue; symParmClass[symTop] = cNotFound; symResultClass[symTop] = cNotFound; } else Error(eTooManySymbols); symIndex = symTop; } /* This procedure looks up a symbol (or string) in the symbolTable */ void LookupSymbol() { char ct[BUFSIZ]; int h; if (compoundToken != tIdent && compoundToken != tString) assertionFailure; strcpy(ct, LowerCase(compoundText)); h = hash(ct); symIndex = symTop; while (symIndex != notFound && (h != symHash[symIndex] || strcmp(ct, LowerCase(symText[symIndex])) != 0)) --symIndex; /* * symIndex is now the index in the Symbol Table of the * entry for the symbol if present and notFound otherwise */ } void xEnterNewSymbolValue() { if (symTop < 0) assertionFailure; symValue[symTop] = symNextValue[(int)symCurrentClass]; if (!isalpha(symText[symTop][0])) return; if (symCurrentClass == cUpdateOp && machineOpNames[symNextValue[(int)symCurrentClass]] == NULL) machineOpNames[symNextValue[(int)symCurrentClass]] = symText[symTop]; else if (symCurrentClass == cError && errorCodeNames[symNextValue[(int)symCurrentClass]] == NULL) errorCodeNames[symNextValue[(int)symCurrentClass]] = symText[symTop]; } void EnterSecondNewSymbolValue() { if (symTop < 2) assertionFailure; symValue[symTop-1] = symNextValue[(int)symCurrentClass]; } void EnterSymbolValueFromAddress() { symValue[symIndex] = outputPointer; } void SetCurrentSymbol(newIndex) SymbolIndex newIndex; { symIndex = newIndex; } void xSetCurrentClass(newClass) SymbolClass newClass; { int nextOpValue; /* Synchronize operation values */ if (symCurrentClass == cUpdateOp || symCurrentClass == cParmUpdateOp || symCurrentClass == cChoiceOp || symCurrentClass == cParmChoiceOp) { nextOpValue = symNextValue[(int)symCurrentClass]; symNextValue[(int)cUpdateOp] = nextOpValue; symNextValue[(int)cParmUpdateOp] = nextOpValue; symNextValue[(int)cChoiceOp] = nextOpValue; symNextValue[(int)cParmChoiceOp] = nextOpValue; } /* Synchronize input/output token values */ if ((symCurrentClass == cInput || symCurrentClass == cOutput) && symNextValue[(int)symCurrentClass] >symNextValue[(int)cInputOutput]) symNextValue[(int)cInputOutput] = symNextValue[(int)symCurrentClass]; symCurrentClass = newClass; } void SetNextValueOfCurrentClass(newValue) int newValue; { symNextValue[(int)symCurrentClass] = newValue; } void IncrementCurrentClassValue() { symNextValue[(int)symCurrentClass] += 1; } extern void CopySymbolTextToTokenBuffer __((void)); void CopySymbolTextToTokenBuffer() { strcpy(compoundText, symText[symIndex]); } void ChangeSymbolClass() { if (symIndex == notFound) assertionFailure; symClass[symIndex] = symCurrentClass; } void xEnterSymbolParameterClass() { if (symIndex == notFound) assertionFailure; symParmClass[symIndex] = symCurrentClass; } void yEnterSymbolResultClass() { if (symIndex == notFound) assertionFailure; symResultClass[symIndex] = symCurrentClass; } void SaveCurrentSymbol() { savedSymIndex = symIndex; } void RestoreCurrentSymbol() { symIndex = savedSymIndex; } void SaveEnclosingSymbol() { enclosingSymIndex = symIndex; } void RestoreEnclosingSymbol() { symIndex = enclosingSymIndex; } void InitSymbolTable() { SymbolClass i; const char **cpp; /* Initialize Symbol Table */ if (notFound != 0) assertionFailure; symTop = notFound; symClass[notFound] = cNotFound; symText[notFound] = "?"; compoundToken = tIdent; /* enter the S/SL machine instructions */ symCurrentClass = cUpdateOp; symNextValue[(int)cUpdateOp] = 0; for (cpp = &machineOpNames[0]; *cpp != NULL; ++cpp) { strcpy(compoundText, *cpp); EnterNewSymbol(); xEnterNewSymbolValue(); IncrementCurrentClassValue(); } for (;cpp < &machineOpNames[(sizeof(machineOpNames)/sizeof(char *))]; ++cpp) *cpp = NULL; /* Blank all the rest of that array */ /* enter the S/SL error signal codes */ symCurrentClass = cError; symNextValue[(int)cError] = 0; for (cpp = &errorCodeNames[0]; *cpp != NULL; ++cpp) { strcpy(compoundText, *cpp); EnterNewSymbol(); xEnterNewSymbolValue(); IncrementCurrentClassValue(); } for (; cpp < &errorCodeNames[(sizeof(errorCodeNames)/sizeof(char *))]; ++cpp) *cpp = NULL; /* Blank rest of these also */ symCurrentClass = cNotFound; /* Initialize Next Values */ symNextValue[(int)cNotFound] = nullValue; for (i = (SymbolClass)((int)cNotFound + 1); i != maxClasses; i = (SymbolClass)((int)i + 1)) symNextValue[(int)i] = 0; symNextValue[(int)cError] = (int)firstUserErrorSignalValue; symNextValue[(int)cUpdateOp] = (int)firstUserSemanticOperationValue; symNextValue[(int)cParmUpdateOp] = (int)firstUserSemanticOperationValue; symNextValue[(int)cChoiceOp] = (int)firstUserSemanticOperationValue; symNextValue[(int)cParmChoiceOp] = (int)firstUserSemanticOperationValue; symNextValue[(int)cType] = (int)firstTypeClass; } /* The Call Table Mechanism */ /* * The Call Table is used to keep track of calls to rules * and provides operations to resolve the call addresses. */ void EnterCall() { SymbolIndex s; if (callTop < maxCalls) { ++callTop; callAddress[callTop] = outputPointer - 1; CurrentSymbolIndex(s); callRule[callTop] = s; } else Error(eTooManyCalls); } void ResolveCalls() { u_int i; int v; const char *n; i = 0; while (i != callTop) { ++i; SetCurrentSymbol(callRule[i]); SymbolValue(v); SymbolName(n); if (v != nullValue) EmitFixup(callAddress[i], v, n); else { CopySymbolTextToTokenBuffer(); Error(eUnresolvedRule); } } } void InitCallTable() { callTop = 0; } /* * The Cycle Stack Mechanism * * The Cycle Stack is used to handle the exits and loop * jump of the cycle construct. */ /* This procedure processes the beginning of a cycle */ void PushCycle() { if (cycleTop < maxCycles) { ++cycleTop; cycleExitIndex[cycleTop] = exitTop; cycleAddress[cycleTop] = outputPointer; } else Error(eCyclesTooDeep); } /* This procedure processes cycle exits */ void EnterCycleExit() { if (exitTop < maxExits) exitAddress[++exitTop] = outputPointer - 1; else Error(eTooManyExits); } void ResolveCycleExits() { u_int i; if (cycleTop == 0) assertionFailure; /* Fixup cycle exits */ for (i = exitTop; i != cycleExitIndex[cycleTop]; --i) EmitJumpFixup(exitAddress[i]); } void PopCycle() { if (cycleTop == 0) assertionFailure; exitTop = cycleExitIndex[cycleTop--]; } void EmitCycleAddress() { EmitJumpAddress(cycleAddress[cycleTop]); } void InitCycleStack() { exitTop = 0; cycleTop = 0; } /* * The Choice Stack Mechanism * * The Choice Stack is used to handle the labels, merge branches, * and choice table of the choice construct. */ /* This procedure processes the beginning of a choice */ void PushChoice(pushClass) SymbolClass pushClass; { if (choiceTop < maxChoices) { ++choiceTop; choiceClass[choiceTop] = pushClass; choiceAddress[choiceTop] = outputPointer - 1; choiceMergeIndex[choiceTop] = mergeTop; choiceLabelIndex[choiceTop] = labelTop; } else Error(eChoicesTooDeep); } void EnterChoiceMerge() { if (choiceTop == 0) assertionFailure; if (mergeTop < maxMerges) mergeAddress[++mergeTop] = outputPointer - 1; else Error(eTooManyMerges); } /* Resolve the merge jumps for the current top choice */ void ResolveChoiceMerges() { u_int i; if (choiceTop == 0 || mergeTop == 0) assertionFailure; /* Fix choice merges */ for (i = mergeTop; i != choiceMergeIndex[choiceTop]; --i) EmitJumpFixup(mergeAddress[i]); } void xEnterChoiceLabel(value) int value; { if (choiceTop == 0) assertionFailure; if (labelTop < maxLabels) { ++labelTop; labelValue[labelTop] = value; labelAddress[labelTop] = outputPointer; } else Error(eTooManyLabels); } Validity VerifyChoiceLabel(value) int value; { u_int i; if (choiceTop == 0) assertionFailure; for (i = choiceLabelIndex[choiceTop]; i != labelTop;) { ++i; if (labelValue[i] == value) { /* Duplicate label */ return invalid; } } return valid; } void PopChoice() { if (choiceTop == 0) assertionFailure; mergeTop = choiceMergeIndex[choiceTop]; labelTop = choiceLabelIndex[choiceTop]; --choiceTop; } void xResolveChoiceTableAddress() { if (choiceTop == 0) assertionFailure; EmitJumpFixup(choiceAddress[choiceTop]); } void EmitChoiceTable() { u_int i; if (choiceTop == 0) assertionFailure; /* Emit choice table */ Emit((int)(labelTop - choiceLabelIndex[choiceTop]), NULL); /* Number of entries */ for (i = choiceLabelIndex[choiceTop]; i != labelTop;) { ++i; Emit(labelValue[i],NULL); EmitJumpAddress(labelAddress[i]); } } void EmitFirstChoiceAddress() { if (choiceTop == 0) assertionFailure; EmitJumpAddress(labelAddress[choiceLabelIndex[choiceTop] + 1]); } void xEmitFirstChoiceValue() { if (choiceTop == 0) assertionFailure; Emit(labelValue[choiceLabelIndex[choiceTop] + 1],NULL); } void ChangeChoiceClass(newClass) SymbolClass newClass; { choiceClass[choiceTop] = newClass; } void InitChoiceStack() { mergeTop = 0; labelTop = 0; choiceTop = 0; } /* The Output Definition and S/SL Table Generators */ /* Generates Assembled Constant Definitions for a Class of Symbols */ void GenerateClass(class, name) SymbolClass class; const char *name; { SymbolIndex s; SymbolClass c; int flag, lastvalue; char buf[BUFSIZ]; flag = 1; lastvalue = -945876; for (s = 0; s != symTop;) { ++s; c = symClass[s]; if ((c == class || (class == cUpdateOp && (c == cParmUpdateOp || c == cChoiceOp || c == cParmChoiceOp))) && symText[s][0] != quote) { /* A real external symbol and not * a string synonym, so output it */ if (flag && name != NULL) { fprintf(headerfp, "typedef enum {\n"); flag = 0; } if (!isalpha(symText[s][0])) continue; if (symValue[s] != lastvalue + 1) { sprintf(buf, "%s = %d", symText[s], symValue[s]); } else strcpy(buf, symText[s]); fprintf(headerfp, "\t%s,%s/* %d */\n", buf, "\t\t\t\t\t\t"+(strlen(buf)+1)/8, symValue[s]); lastvalue = symValue[s]; } } if (!flag && name != NULL) fprintf(headerfp, "\tlastOf%s\n} %s;\n", name, name); } /* Generates Assembled Constant Definitions */ void GenerateSymbolDefinitions() { SymbolIndex s; SymbolClass c; fprintf(headerfp, "/* Semantic Operations */\n\n"); GenerateClass(cUpdateOp, "TableOperation"); /* Does all operations */ fprintf(headerfp, "\n/* Input Tokens */\n\n"); GenerateClass(cInput, "InputTokens"); fprintf(headerfp, "\n/* Output Tokens */\n\n"); GenerateClass(cOutput, "OutputTokens"); fprintf(headerfp, "\n/* Input/Output Tokens */\n\n"); GenerateClass(cInputOutput, "InputOutputTokens"); fprintf(headerfp, "\n/* Error Codes */\n\n"); GenerateClass(cError, "ErrorCodes"); fprintf(headerfp, "\n/* Type Values */\n\n"); for (s = 0; s != symTop;) { ++s; c = symClass[s]; if (c == cType) { GenerateClass((SymbolClass)symValue[s], symText[s]); putc('\n', headerfp); } } } /* Generates the Assembled Output Table */ void GenerateOutputTable(typeName) const char *typeName; { OutputAddress i; int col = 16, coladd; /* Generate Syntax/Semantic Table */ fprintf(tablefp, "/* S/SL table (%d entries) */\n", outputPointer); fprintf(tablefp, "\n%s sslTable[] = {\n/* %4d */\t", typeName ? typeName:"int", 0); for (i = 0; i < outputPointer; ++i) { if (outputNameTable[i] && outputNameTable[i][0] == '"') outputNameTable[i] = 0; /*outputNameTable[i] = 0;*/ if (outputNameTable[i] != NULL) coladd = (strlen(outputNameTable[i])+2); else coladd = 7; if (col+coladd > 78) { fprintf(tablefp, "\n/* %4d */\t",i); col = 16; } col += coladd; if (outputNameTable[i] != NULL) fprintf(tablefp, "%s, ", outputNameTable[i]); else fprintf(tablefp, "%5d, ", outputTable[i]); } fprintf(tablefp, "0\n};\n"); } void GenerateEntryPoints(enumName) const char *enumName; { SymbolIndex s; if (entryfp == NULL) return; fprintf(entryfp, "/* Entry points into S/SL Table */\n\n"); if (enumName) fprintf(entryfp, "typedef enum {\n\tnil%s = -1,\n", enumName); for (s = 0; s != symTop;) { if (symClass[++s] == cRule) { if (enumName) fprintf(entryfp, "\t%s = %d,\n", symText[s], symValue[s]); else fprintf(entryfp, "#define\tSSL_%s\t%d\n", symText[s], symValue[s]); } } if (enumName) fprintf(entryfp, "\tlastOf%s\n} %s;\n", enumName, enumName); } /* Syntax Error Handling */ void SslGenerateCompoundInputToken(expectedToken) InputTokens expectedToken; { if (nextToken != tSyntaxError && nextToken != tEndOfFile) assertionFailure; compoundToken = expectedToken; compoundValue = 0; switch (expectedToken) { case tInteger: strcpy(compoundText, "0"); break; case tString: strcpy(compoundText, "'?'"); break; case tIdent: strcpy(compoundText, "$NIL"); break; default: break; } } void SslSyntaxError() { /* * This procedure handles syntax errors in the input * to the Parser pass, for Semantic passes this procedure * will simply assert false since a syntax error in * input would indicate an error in the previous pass. * Syntax error recovery: * When a mismatch occurs between the the next input * token and the syntax table, the following recovery * is employed. * If the expected token is tNewLine then if there * has been no previous syntax error on the line, * ignore the error. (A missing logical new line * is not a real error.) * If the expected token is tNewLine or tSemicolon and * a syntax error has already been detected on the * current logical line (flagged by nextToken = * tSyntaxError), then flush the input exit when a * new line or end of file is found. * Otherwise, if this is the first syntax error * detected on the line (flagged by nextToken * not = tSyntaxError), then if the input token * is tEndOfFile then emit the ePrematureEndOfFile * error code and terminate execution. Otherwise, * emit the eSyntaxError error code and set * the nextToken to tSyntaxError to prevent * further input exit when the expected input is * tSemicolon or tNewLine. * If the expected token is not tSemicolon nor * tNewLine and a syntax error has already been * detected on the current line (flagged by * nextToken = tSyntaxError), then do nothing * and continue as if the expected token had * been matched. */ if (operation != oInput && operation != oInputAny) assertionFailure; if (nextToken == tSyntaxError) { /* Currently recovering from syntax error */ if (sslTable[sslPointer] == (int)tNewLine || sslTable[sslPointer] == (int)tSemicolon) { /* Complete recovery by synchronizing */ /* input to a new line */ nextToken = savedToken; newInputLine = false; while (nextToken != tSemicolon && nextToken != tEndOfFile && newInputLine) AcceptInputToken(); } } else { /* First syntax error on the line */ if (sslTable[sslPointer] == (int)tNewLine) { /* Ignore missing logical newlines */ } else if (nextToken == tEndOfFile) { /* Flag error and terminate processing */ Error(ePrematureEndOfFile); processing = false; } else { /* Flag error and begin recovery */ Error(eSyntaxError); savedToken = nextToken; nextToken = tSyntaxError; lineNumber = nextLineNumber; } } /* If the expected input token is a compound */ /* token, generate a dummy one. */ if (sslTable[sslPointer] >= (int)firstCompoundToken && sslTable[sslPointer] <= (int)lastCompoundToken) SslGenerateCompoundInputToken((InputTokens)sslTable[sslPointer]); } void SslTrace() { printf("Table index %d Operation %d (%s) Argument %d\n", sslPointer-1, operation, machineOpNames[operation], sslTable[sslPointer]); } void SslFailure(failCode) FailureCodes failCode; { printf("### S/SL program failure: "); switch (failCode) { case fSemanticChoiceFailed: printf("Semantic choice failed\n"); break; case fChoiceRuleFailed: printf("Choice rule returned without a value\n"); break; } printf("while processing line %d\n", lineNumber); SslTrace(); abort(); } /* * This procedure performs both input and semantic * choices. It sequentially tests each alternative * value against the tag value, and when a match is * found, performs a branch to the corresponding * alternative path. If none of the alternative * values matches the tag value, sslTable interpretation * proceeds to the operation immediately following * the list of alternatives (normally the otherwise * path). The flag choiceTagMatched is set to true * if a match is found and false otherwise. */ void SslChoice(choiceTag) int choiceTag; { int numberOfChoices; u_int choicePointer; choicePointer = sslTable[sslPointer]; numberOfChoices = sslTable[choicePointer]; ++choicePointer; choiceTagMatched = false; do { if (sslTable[choicePointer] == choiceTag) { choicePointer = sslTable[choicePointer+1]; choiceTagMatched = true; numberOfChoices = 0; } else { choicePointer += 2; --numberOfChoices; } } while (numberOfChoices != 0); sslPointer = choicePointer; }