language-Modula2-0.1: examples/Dipl/M2/DECODER.MOD
IMPLEMENTATION MODULE Decoder;
FROM SYSTEM IMPORT TSIZE;
FROM Lib IMPORT IncAddr;
FROM Memory IMPORT ALLOCATE, AddMarker, MarkNeeded;
FROM FIO IMPORT File, Create, Close, Seek, GetPos, WrChar, WrStr, WrLn, WrInt, WrLngHex, IOresult;
FROM Buffers IMPORT output, FlushOut, WriteChars, CharPtr, CharSet;
FROM Machine IMPORT EmptyClosure, link, HandlePackage, Reduce, Envelope, Root, result;
FROM Machine IMPORT wPackage, tempDef, MakePrimitive, MakeDef, MakePacked, ExtractPacked;
FROM Machine IMPORT ChangeDefinition, NewLayer, StartLayer, PopLayer, Equal;
FROM Machine IMPORT Copy, RemoveEnv, MarkLink, Join;
FROM Library IMPORT wChar, wCharSet, wString, wNumber, wError, errorCodes;
FROM Library IMPORT wStruct, wProperty, wValue, wFile, wDescription;
FROM Library IMPORT wAddProp, wAddValProp;
FROM Grammars IMPORT wSequence, wLexSequence, wValSequence, wLexValSequence;
FROM Grammars IMPORT wEndSeq, wChoice, wOption;
FROM Grammars IMPORT wDummy, wFail, wDone, wDiscard, wRaise, wGrammar, wNext;
FROM Grammars IMPORT wSeparator, wFrameGrammar, wCustomGrammar;
FROM Grammars IMPORT wFirst, wTail, wIdentGrammar, wIdentifier, wCharSetGrammar;
FROM Grammars IMPORT wCharGrammar, wStrGrammar, wNumGrammar, wErrorGrammar, wPackageGrammar;
FROM Grammars IMPORT Failure, Confirmation, HoldDummy;
FROM Names IMPORT DefName, DefEntry, wName, wMeaning;
FROM Names IMPORT AddPrimWord;
TYPE
PassPtr=POINTER TO PassPoint;
PassPoint=RECORD
grammar,statement:closure;
next:PassPtr
END;
VAR
wStatement:link;
oldChar, oldString, oldNumber, oldError, oldRoute:closure;
separated:BOOLEAN;
path:PassPtr;
PROCEDURE PopPath;
BEGIN
Discard(path);
path:=path^.next
END PopPath;
PROCEDURE PathClosed():BOOLEAN;
VAR
follow:PassPtr;
BEGIN
follow:=path;
WHILE (follow#NIL) AND
((follow^.grammar#wGrammar^) OR (follow^.statement#wStatement^)) DO
follow:=follow^.next
END;
IF follow=NIL THEN
NEW(follow);
Use(wGrammar^);
Use(wStatement^);
follow^.grammar:=wGrammar^;
follow^.statement:=wStatement^;
follow^.next:=path;
path:=follow;
RETURN FALSE
ELSE
RETURN TRUE
END
END PathClosed;
PROCEDURE PhraseTheLetter;
VAR
chExpect,chIs:CHAR;
BEGIN
ExtractPacked(wPackage^,chExpect);
IF wStatement^#EmptyClosure THEN
ChangeDefinition(wChar,HandlePackage);
Reduce(wStatement^);
ExtractPacked(result,chIs);
IF chExpect#chIs THEN
Discard(result^);
result:=Failure;
RETURN
END
END;
WrChar(output,chExpect);
Discard(result^);
result:=Confirmation
END PhraseTheLetter;
PROCEDURE PhraseTheString;
VAR
str:CharPtr;
BEGIN
IF wStatement^#EmptyClosure THEN
ChangeDefinition(wString,HandlePackage);
Reduce(wStatement^);
IF NOT Equal(wPackage^,result) THEN
Discard(result^);
result:=Failure;
RETURN
END
END;
ExtractPacked(wPackage^,str);
WriteChars(str);
Discard(result^);
result:=Confirmation
END PhraseTheString;
PROCEDURE PhraseTheCharSet;
VAR
s:POINTER TO CharSet;
ch:CHAR;
BEGIN
ChangeDefinition(wChar,HandlePackage);
Reduce(wStatement^);
Discard(result^);
IF Root(result)=wChar THEN
ExtractPacked(result,ch);
ExtractPacked(wPackage^,s);
IF ch IN s^ THEN
WrChar(output,ch);
result:=Confirmation
ELSE
result:=Failure
END
ELSE
result:=Failure
END
END PhraseTheCharSet;
PROCEDURE PhraseChoice;
BEGIN
Reduce(wGrammar^);
IF Root(result)=wFail THEN
Reduce(wNext^)
END
END PhraseChoice;
PROCEDURE PhraseOption;
BEGIN
Reduce(wGrammar^);
IF Root(result)=wFail THEN
Discard(result^);
result:=HoldDummy
END
END PhraseOption;
PROCEDURE PhraseSeqPrimitive(separate:BOOLEAN);
VAR
down:closure;
downPtr:link;
oldPos:LONGCARD;
BEGIN
downPtr:=Root(wProperty^);
Use(downPtr);
oldPos:=GetPos(output);
StartLayer;
IF downPtr#wDiscard THEN
IF (downPtr#wRaise) THEN
StartLayer;
ChangeDefinition(downPtr,EmptyClosure);
NewLayer(wStatement^);
down:=downPtr^;
Use(down);
PopLayer;
IF down=EmptyClosure THEN
Discard(result);
result:=Failure;
PopLayer;
RETURN
END;
ChangeDefinition(wStatement,down)
END
ELSE
ChangeDefinition(wStatement,EmptyClosure);
END;
IF PathClosed() THEN
Discard(result);
result:=Failure;
RETURN
END;
separated:=FALSE;
Reduce(wGrammar^);
PopPath;
PopLayer;
IF Root(result)#wFail THEN
IF separate AND (GetPos(output)>oldPos) AND NOT separated THEN
StartLayer;
LinkPrimitive(wChar,PhraseTheLetter);
LinkPrimitive(wString,PhraseTheString);
ChangeDefinition(wStatement,EmptyClosure);
Reduce(wSeparator^);
PopLayer;
separated:=TRUE
END;
Reduce(wNext^);
IF Root(result)=wFail THEN
Seek(output,oldPos)
END
END
END PhraseSeqPrimitive;
PROCEDURE PhraseSequence;
BEGIN
PhraseSeqPrimitive(TRUE)
END PhraseSequence;
PROCEDURE PhraseLexSequence;
BEGIN
PhraseSeqPrimitive(FALSE)
END PhraseLexSequence;
PROCEDURE PhraseEndSequence;
BEGIN
Discard(result);
IF (Root(wStruct^)=wDummy) OR (Root(wStatement^)=Root(wStruct^)) THEN
result:=Confirmation
ELSE
result:=Failure
END
END PhraseEndSequence;
PROCEDURE PhraseNumber;
VAR
num:INTEGER;
BEGIN
IF Root(wStatement^)#wNumber THEN
Discard(result);
result:=Failure;
RETURN
END;
ChangeDefinition(wNumber,HandlePackage);
Reduce(wStatement^);
ExtractPacked(result,num);
WrInt(output,num,0);
Discard(result);
result:=Confirmation
END PhraseNumber;
PROCEDURE PhrasePackage;
VAR
contents:LONGCARD;
BEGIN
WrChar(output,'[');
ExtractPacked(wStatement^,contents);
WrLngHex(output,contents,0);
WrChar(output,']')
END PhrasePackage;
PROCEDURE PhraseChar;
VAR
ch:CHAR;
BEGIN
IF Root(wStatement^)#wChar THEN
Discard(result);
result:=Failure;
RETURN
END;
ChangeDefinition(wChar,HandlePackage);
Reduce(wStatement^);
ExtractPacked(result,ch);
WrChar(output, "'");
WrChar(output,ch);
WrChar(output, "'");
END PhraseChar;
PROCEDURE PhraseCharSET;
VAR
s:SET OF CHAR;
ch:CHAR;
first:BOOLEAN;
BEGIN
IF Root(wStatement^)=wCharSet THEN
ChangeDefinition(wCharSet,HandlePackage);
Reduce(wStatement^);
ExtractPacked(result,s);
ch:=MIN(CHAR);
WrChar(output,'{');
first:=TRUE;
LOOP
IF ch IN s THEN
IF first THEN
first:=FALSE
ELSE
WrChar(output,',')
END;
IF (ch=' ') OR (ch='}') OR (ch='{') OR (ch='\') THEN
WrChar(output,'\')
END;
WrChar(output,ch);
INC(ch);
IF ch IN s THEN
REPEAT
INC(ch)
UNTIL NOT (ch IN s);
DEC(ch);
WrChar(output,'-');
IF (ch=' ') OR (ch='}') OR (ch='{') OR (ch='\') THEN
WrChar(output,'\')
END;
WrChar(output,ch);
INC(ch)
END
ELSIF ch<MAX(CHAR) THEN
INC(ch)
ELSE
EXIT
END
END;
WrChar(output,'}')
ELSE
Discard(result);
result:=Failure
END
END PhraseCharSET;
PROCEDURE PhraseIdent;
VAR
string:POINTER TO CHAR;
s:POINTER TO SET OF CHAR;
BEGIN
IF Root(wStatement^)=wIdentifier THEN
NewLayer(wStatement^);
ChangeDefinition(wString,HandlePackage);
Reduce(wDescription^);
ExtractPacked(result,string)
ELSE
string:=DefName(Root(wStatement^));
Use(string)
END;
ChangeDefinition(wCharSet,HandlePackage);
Reduce(wFirst^);
ExtractPacked(result,s);
IF string^ IN s^ THEN
Reduce(wTail^);
ExtractPacked(result,s);
REPEAT
WrChar(output,string^);
IncAddr(string,1)
UNTIL NOT (string^ IN s^) OR (string^=0C);
IF string^=0C THEN
Discard(result);
result:=Confirmation;
RETURN
END
END;
Discard(result);
result:=Failure
END PhraseIdent;
PROCEDURE PhraseString;
VAR
string:ADDRESS;
BEGIN
IF Root(wStatement^)#wString THEN
Discard(result);
result:=Failure;
RETURN
END;
ChangeDefinition(wString,HandlePackage);
Reduce(wStatement^);
ExtractPacked(result,string);
WrChar(output,'"');
WriteChars(string);
WrChar(output,'"');
Discard(result);
result:=Confirmation
END PhraseString;
PROCEDURE PhraseError;
VAR
err:errorCodes;
BEGIN
IF Root(wStatement^)#wError THEN
Discard(result);
result:=Failure;
RETURN
END;
ChangeDefinition(wError,HandlePackage);
Reduce(wStatement^);
ExtractPacked(result,err);
CASE err OF
NotLogicalType:WrStr(output,'Not the logical type!')
|NotNumberType:WrStr(output,'Not the number type!')
|NotStringType:WrStr(output,'Not the string type!')
|IOError:WrStr(output,'(R) Tape loading error!')
|SyntaxError:WrStr(output,'Syntax error!')
|NotFound:WrStr(output,'Undefined word meaning!')
END;
WrLn(output);
Discard(result);
result:=Confirmation
END PhraseError;
PROCEDURE PhraseCustom;
FORWARD;
PROCEDURE PhraseStd;
VAR
oldPos:LONGCARD;
BEGIN
oldPos:=GetPos(output);
WriteChars(DefName(Root(wStatement^)));
Envelope(result,wStatement^,wAddProp,wAddValProp,wDone,wProperty,wValue,wStruct);
WrChar(output,'(');
LOOP
IF Root(result)=wDone THEN
EXIT
END;
StartLayer;
NewLayer(result);
WriteChars(DefName(Root(wProperty^)));
IF Root(result)=wAddValProp THEN
WrChar(output,':')
END;
WrChar(output,'=');
ChangeDefinition(wStatement,wValue^);
PhraseCustom;
IF Root(result)=wFail THEN
PopLayer;
EXIT
END;
Discard(result);
result:=wStruct^;
Use(result);
PopLayer;
IF Root(result)#wDone THEN
WrChar(output,',')
END
END;
IF Root(result)=wFail THEN
Seek(output,oldPos)
ELSE
WrChar(output,')')
END
END PhraseStd;
PROCEDURE PhraseCustom;
VAR
prop:closure;
BEGIN
LinkPrimitive(wCustomGrammar,PhraseStd);
ChangeDefinition(wFrameGrammar,Failure);
prop:=DefEntry(Root(wStatement^));
Use(prop);
StartLayer;
NewLayer(prop);
Discard(result);
result:=wCustomGrammar^;
Use(result);
PopLayer;
ChangeDefinition(wGrammar,result);
Reduce(result)
END PhraseCustom;
PROCEDURE PhraseGrammar;
BEGIN
LinkPrimitive(wSequence,PhraseSequence);
LinkPrimitive(wValSequence,PhraseSequence);
LinkPrimitive(wLexSequence,PhraseSequence);
LinkPrimitive(wLexValSequence,PhraseSequence);
LinkPrimitive(wEndSeq,PhraseEndSequence);
LinkPrimitive(wChoice,PhraseChoice);
LinkPrimitive(wOption,PhraseOption);
LinkPrimitive(wChar,PhraseTheLetter);
LinkPrimitive(wString,PhraseTheString);
LinkPrimitive(wCharSet,PhraseTheCharSet);
LinkPrimitive(wPackageGrammar,PhrasePackage);
LinkPrimitive(wCharGrammar,PhraseChar);
LinkPrimitive(wCharSetGrammar,PhraseCharSET);
LinkPrimitive(wIdentGrammar,PhraseIdent);
LinkPrimitive(wStrGrammar,PhraseString);
LinkPrimitive(wNumGrammar,PhraseNumber);
LinkPrimitive(wErrorGrammar,PhraseError);
LinkPrimitive(wCustomGrammar,PhraseCustom);
ChangeDefinition(wStatement,wStruct^);
Reduce(wGrammar^);
path:=NIL
END PhraseGrammar;
PROCEDURE WriteGrammar;
CONST
FormalLength=1000;
VAR
filename:POINTER TO ARRAY [0..FormalLength] OF CHAR;
oldHandle:File;
BEGIN
Reduce(wFile^);
oldHandle:=output;
IF Root(result)=wString THEN
ExtractPacked(result,filename);
IF filename^[0]#0C THEN
output:=Create(filename^);
IF IOresult()#0 THEN
MakePacked(result,wError,IOError);
output:=oldHandle;
RETURN
END
END
END;
Seek(output,0);
PhraseGrammar;
IF Root(result)#wFail THEN
FlushOut
END;
IF output#oldHandle THEN
Close(output);
output:=oldHandle
END
END WriteGrammar;
PROCEDURE Write;
BEGIN
LinkPrimitive(wGrammar,PhraseCustom);
WriteGrammar
END Write;
PROCEDURE MarkPath;
VAR
follow:PassPtr;
fresh:BOOLEAN;
BEGIN
MarkLink(wStatement);
follow:=path;
WHILE follow#NIL DO
MarkNeeded(follow,TSIZE(PassPoint),fresh);
follow:=follow^.next
END
END MarkPath;
BEGIN
path:=NIL;
NEW(wStatement);
wStatement^:=EmptyClosure;
AddMarker(MarkPath);
AddPrimWord(wWrite,'Write',Write);
AddPrimWord(wWriteGrammar,'WriteGrammar',WriteGrammar)
END Decoder.