/*
* 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 <stdio.h>
#include <sys/types.h>
#include <ctype.h>
#include "hostenv.h"
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#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;
}
syntax highlighted by Code2HTML, v. 0.9.1