--File ParserMain.Mesa
--
November 8, 1980 2:47 PM

DIRECTORY

ParserTypeDefs: FROM "ParserTypeDefs" USING
[InitTypes, FinishTypes, Path, Point, AllocatePath, FreePath,
TList, AllocateTList, FreeTList, AppendTList, TEntry],

SystemDefs: FROM "SystemDefs" USING
[AllocateHeapString, FreeHeapString],

ParserDefs: FROM "ParserDefs",

ParserUtilityDefs: FROM "ParserUtilityDefs",

IntDefs: FROM "IntDefs" USING
[IWire, IDefineStart, IDefineEnd,
IDeleteDef, ICallSymbol, ILayer, IFlash, IPolygon, IBox, IComment,
IUserCommand, IEnd, SemanticError],

ParserErrorDefs: FROM "ParserErrorDefs" USING [InitError, FinishError, Report],

StringDefs: FROM "StringDefs" USING
[AppendChar, StringBoundsFault, AppendString],

ParserInputDefs: FROM "ParserInputDefs" USING[InitInput, FinishInput, GetChar, Peek, EndOfFile, Flush,
EOF];

ParserMain: PROGRAM

IMPORTS ParserInputDefs, ParserErrorDefs, IntDefs, ParserUtilityDefs, ParserTypeDefs, StringDefs, SystemDefs
EXPORTS ParserDefs =
BEGIN

defInProg: BOOLEAN;

--For debugging space leaks:
NStrings: INTEGER ← 0;

InitParser: PUBLIC PROCEDURE RETURNS [BOOLEAN] =
BEGIN
defInProg ← FALSE;
NStrings ← 0;
IF ~ParserInputDefs.InitInput[] OR ~ParserErrorDefs.InitError[] OR ~ParserTypeDefs.InitTypes[] THEN
RETURN[FALSE]
ELSE
RETURN[ParserUtilityDefs.InitUtilities[]];
END;

FinishParser: PUBLIC PROCEDURE RETURNS [BOOLEAN] =
BEGIN
IF ~ParserInputDefs.FinishInput[] OR ~ParserErrorDefs.FinishError[] OR ~ParserTypeDefs.FinishTypes[] THEN
RETURN[FALSE]
ELSE
RETURN[ParserUtilityDefs.FinishUtilities[]];
END;

ParseStatement: PUBLIC PROCEDURE RETURNS [ParserDefs.CommandType] =
BEGIN OPEN ParserUtilityDefs;

Command: ParserDefs.CommandType;
Diameter: LONG CARDINAL;
Center: ParserTypeDefs.Point;
CurPath: ParserTypeDefs.Path;
Length, Width: LONG CARDINAL;
XRotation, YRotation: LONG INTEGER;
SymbolNumber: LONG CARDINAL;
LayerName: STRING ← [4];
CurChar: CHARACTER;
UserCommand: [0..9];
CommentText, UserText: STRING;
Multiplier, Divisor: LONG CARDINAL;
XTrans, YTrans: LONG INTEGER;
CurTList: ParserTypeDefs.TList;

BEGIN
ENABLE RecoverFromError =>
BEGIN OPEN ParserErrorDefs;

SELECT errorCode FROM

NullPath => Report["No Points in Path", FatalSyntax];
MissingLayer => Report["Layer Name Expected", FatalSyntax];
NumberTooBig => Report["Number Out Of Range", FatalSemantic];
MissingUnsigned => Report["Unsigned Integer Expected", FatalSyntax];
MissingSigned => Report["Signed Integer Expected", FatalSyntax];
MissingSemiColon => Report["Missing Semicolon, Inserted", FatalSyntax];
BadCommand => Report["Unknown Command Encountered", FatalSyntax];
BadComment =>
BEGIN
FreeString[CommentText];
Report["End Of File Inside a Comment", FatalSyntax];
END;
BadDefineCommand => Report["No Such Define Command", FatalSyntax];
BadUserCommand =>
BEGIN
FreeString[UserText];
Report["End Of File Inside a User Command", FatalSyntax];
END;
IllegalAxis => Report["No Such Axis in Mirror Command", FatalSyntax];
NestDef => Report["Symbol Definitions Can’t Nest", FatalSyntax];
NestDD => Report["DD Not Allowed Inside Symbol Definition", FatalSyntax];
NestEnd => Report["End Command Inside Symbol Definition", FatalSyntax];
NoDS => Report["DF Without DS", FatalSyntax];
BadTransCommand => Report["No Such Transformation Command", FatalSyntax];
InternalError => Report["Parser Internal Error", FatalInternal];
ENDCASE => Report["Uncaught PossibleError", Fatal];

IF errorCode # MissingSemiColon AND errorCode # InternalError AND ParserInputDefs.Flush[’;] = ParserInputDefs.EOF THEN
Report["Unexpected End of Input File",FatalSyntax]
ELSE Blank[];

Command ← SyntaxError;
CONTINUE;
END;

CurPath ← ParserTypeDefs.AllocatePath[];
CurTList ← ParserTypeDefs.AllocateTList[];

-- flush all junk, sometimes redundant, but necessary for require files
Blank[];
SELECT (CurChar ← ParserInputDefs.GetChar[]) FROM

’P =>
BEGIN
GetPath[CurPath];
Command ← Polygon;
END;

’B =>
BEGIN
XRotation ← 1; YRotation ← 0;
Length ← UnsignedLong[]; Width ← UnsignedLong[];
Center ← GetPoint[]; Sep[];
IF (CurChar←ParserInputDefs.Peek[]) IN [’0..’9] OR CurChar = ’- THEN
BEGIN
XRotation ← SignedLong[];
YRotation ← SignedLong[];
END;
Command ← Box;
END;

’R =>
BEGIN
Diameter ← UnsignedLong[];
Center ← GetPoint[];
Command ← Flash;
END;

’W =>
BEGIN
Width ← UnsignedLong[];
GetPath[CurPath];
Command ← Wire;
END;

’L =>
BEGIN
Blank[];
LayerName.length ← 0;
THROUGH [1..4] WHILE (CurChar ← ParserInputDefs.Peek[]) IN [’0..’9] OR CurChar IN [’A..’Z] DO
LayerName[LayerName.length] ← ParserInputDefs.GetChar[];
LayerName.length ← LayerName.length + 1;
ENDLOOP;
IF LayerName.length = 0 THEN ERROR RecoverFromError[MissingLayer];
Command ← Layer;
END;

’D =>
BEGIN
Blank[];
SELECT ParserInputDefs.GetChar[] FROM
’S =>
BEGIN
IF defInProg THEN ERROR RecoverFromError[NestDef];
SymbolNumber ← UnsignedLong[];
Sep[];
Multiplier ← Divisor ← 1;
IF ParserInputDefs.Peek[] IN [’0..’9] THEN
BEGIN
Multiplier ← UnsignedLong[];
Divisor ← UnsignedLong[];
END;
defInProg ← TRUE;
Command ← DefineStart;
END;
’F =>
BEGIN
IF ~defInProg THEN ERROR RecoverFromError[NoDS];
defInProg ← FALSE;
Command ← DefineEnd;
END;
’D =>
BEGIN
IF defInProg THEN ERROR RecoverFromError[NestDD];
SymbolNumber ← UnsignedLong[];
Command ← DeleteDef;
END;
ENDCASE => ERROR RecoverFromError[BadDefineCommand];
END;

’C =>
BEGIN OPEN ParserTypeDefs;
SymbolNumber ← UnsignedLong[];
Blank[];
WHILE TRUE DO
SELECT ParserInputDefs.Peek[] FROM
’T =>BEGIN
[] ← ParserInputDefs.GetChar[];
XTrans ← SignedLong[];
YTrans ← SignedLong[];
AppendTList[CurTList,TEntry[Translate[
x: XTrans,y: YTrans]]];
END;
’M =>BEGIN
[] ← ParserInputDefs.GetChar[];
Blank[];
SELECT ParserInputDefs.GetChar[] FROM
’X => AppendTList[CurTList,TEntry[Mirror[coords: X]]];
’Y => AppendTList[CurTList,TEntry[Mirror[coords: Y]]];
ENDCASE => ERROR RecoverFromError[IllegalAxis];
END;
’R =>BEGIN
[] ← ParserInputDefs.GetChar[];
XRotation ← SignedLong[];
YRotation ← SignedLong[];
AppendTList[CurTList,TEntry[Rotate[
xRot: XRotation,yRot: YRotation]]];
END;
’; =>EXIT;
ENDCASE => ERROR RecoverFromError[BadTransCommand];
Blank[];
ENDLOOP;
Command ← CallSymbol;
END;

’( =>
BEGIN
ENABLE StringDefs.StringBoundsFault =>
BEGIN New: STRING;
New ← AllocateString[s.length+50];
StringDefs.AppendString[New,s];
FreeString[s];
RESUME[CommentText←New];
END;

Level: CARDINAL ← 1;
CommentText ← AllocateString[50];
WHILE Level > 0 DO
SELECT (CurChar←ParserInputDefs.GetChar[]) FROM
’( => BEGIN
Level ← Level+1;
StringDefs.AppendChar[CommentText,’(];
END;
’) => BEGIN
Level ← Level-1;
IF Level > 0 THEN StringDefs.AppendChar[CommentText,’)];
END;
ParserInputDefs.EOF => ERROR RecoverFromError[BadComment];
ENDCASE => StringDefs.AppendChar[CommentText,CurChar];
ENDLOOP;
Command ← Comment;
END;

’E =>
BEGIN
IF defInProg THEN ERROR RecoverFromError[NestEnd];
Blank[];
IF NOT ParserInputDefs.EndOfFile[] THEN
ParserErrorDefs.Report["More Text Follows End Command", Advisory];
Command ← End;
IntDefs.IEnd[
! IntDefs.SemanticError =>
BEGIN
Command ← SemanticError;
CONTINUE;
END];
ParserTypeDefs.FreePath[CurPath];
ParserTypeDefs.FreeTList[CurTList];
RETURN[Command];
END;

’; =>
BEGIN
Blank[];
ParserTypeDefs.FreePath[CurPath];
ParserTypeDefs.FreeTList[CurTList];
RETURN[NullCommand];
END;

IN [’0..’9] =>
BEGIN
UserCommand ← CurChar - ’0;
UserText ← AllocateString[50];
WHILE NOT ParserInputDefs.EndOfFile[] AND ParserInputDefs.Peek[] # ’; DO
StringDefs.AppendChar[UserText,ParserInputDefs.GetChar[] !
StringDefs.StringBoundsFault =>
BEGIN New: STRING;
New ← AllocateString[s.length+50];
StringDefs.AppendString[New,s];
FreeString[s];
RESUME[UserText←New];
END];
ENDLOOP;
IF ParserInputDefs.EndOfFile[] THEN ERROR RecoverFromError[BadUserCommand];
Command ← UserCommand;
END;

ENDCASE => ERROR RecoverFromError[BadCommand];

IF Semi[] THEN
BEGIN OPEN IntDefs;
-- By now we have parsed a syntactically valid command

ENABLE IntDefs.SemanticError =>
BEGIN
Command ← SemanticError;
CONTINUE;
END;

SELECT Command FROM
Wire => IWire[Width, CurPath];
DefineStart => IDefineStart[SymbolNumber,Multiplier,Divisor];
DefineEnd => IDefineEnd[];
DeleteDef => IDeleteDef[SymbolNumber];
CallSymbol => ICallSymbol[SymbolNumber,CurTList];
Layer => ILayer[LayerName];
Flash => IFlash[Diameter, Center];
Polygon => IPolygon[CurPath];
Box => IBox[Length, Width, Center, XRotation, YRotation];
Comment =>
BEGIN
IComment[CommentText ! IntDefs.SemanticError => CONTINUE];
FreeString[CommentText];
END;
UserCommand =>
BEGIN
IUserCommand[UserCommand,UserText ! IntDefs.SemanticError => CONTINUE];
FreeString[UserText];
END;
ENDCASE => ERROR RecoverFromError[InternalError];
END

ELSE ERROR RecoverFromError[MissingSemiColon];

END;

ParserTypeDefs.FreePath[CurPath];
ParserTypeDefs.FreeTList[CurTList];
RETURN[Command];

END;

AllocateString: PROCEDURE[length: CARDINAL] RETURNS [STRING] =
BEGIN
NStrings ← NStrings + 1;
RETURN[SystemDefs.AllocateHeapString[length]];
END;

FreeString: PROCEDURE[s: STRING] =
BEGIN
NStrings ← NStrings - 1;
SystemDefs.FreeHeapString[s];
END;

END.