language-Modula2-0.1: examples/Dipl/M2/PARSER.MOD
IMPLEMENTATION MODULE Parser;
FROM Memory IMPORT ALLOCATE, AddMarker;
FROM Lib IMPORT IncAddr;
IMPORT Str;
FROM FIO IMPORT File, Open, IOresult, Close;
FROM Buffers IMPORT ReadChar, ReadWord, Rewind, CharSet;
FROM Buffers IMPORT position, OpenInput, CloseInput, ReportError;
FROM Machine IMPORT EmptyClosure, tempDef, wPackage, link, HandlePackage, Reduce;
FROM Machine IMPORT Join, AddEnv, AddValuedEnv, Root, Copy, result;
FROM Machine IMPORT ChangeDefinition, NewLayer, StartLayer, PopLayer;
FROM Machine IMPORT MakeDef, MakePrimitive, MakeString, MakePacked, ExtractPacked;
FROM Machine IMPORT MarkString, MarkClosure;
FROM Library IMPORT wChar, wString, wCharSet, wNumber, wError, errorCodes;
FROM Library IMPORT wType, wStruct, wFile, wUndefined, wDescription;
FROM Names IMPORT FindWord, DefEntry, AddPrimWord, DefineWord, wMeaning;
FROM Names IMPORT NewDictionary, OldDictionary;
FROM Grammars IMPORT wSequence, wLexSequence, wValSequence, wLexValSequence;
FROM Grammars IMPORT wEndSeq, wChoice, wOption;
FROM Grammars IMPORT wDummy, wFail, wDone, wRaise, wDiscard, wGrammar, wNext;
FROM Grammars IMPORT wSpaceChars, wSpaces, wComment, wFrameGrammar, wCustomGrammar;
FROM Grammars IMPORT wCharGrammar, wCharSetGrammar, wStrGrammar, wNumGrammar;
FROM Grammars IMPORT wIdentifier, wIdentGrammar, wFirst, wTail;
FROM Grammars IMPORT wStructGrammar;
FROM Grammars IMPORT Failure, Confirmation;
FROM ParseLow IMPORT ParsePrimitive, buildTree;
FROM ParseLow IMPORT ParseSequencePrimitive, ParseEndSequence, ParseChoice, ParseOption;
CONST
MaxStrLength=200;
all=CharSet{0C..377C};
TYPE
CharPtr=POINTER TO CHAR;
string=ARRAY [0..MaxStrLength] OF CHAR;
VAR
firstSet,tailSet:CharSet;
originalFirst,originalTail:closure;
strPtr:POINTER TO string;
PROCEDURE pSpaces;
VAR
prevPos:LONGCARD;
spaces:POINTER TO CharSet;
str:ARRAY [0..1] OF CHAR;
BEGIN
StartLayer;
ChangeDefinition(wCharSet,HandlePackage);
Reduce(wSpaceChars^);
PopLayer;
ExtractPacked(result,spaces);
IF Root(wComment^)=wFail THEN
ReadWord(str,spaces^,spaces^)
ELSE
REPEAT
ReadWord(str,spaces^,spaces^);
prevPos:=position;
StartLayer;
ChangeDefinition(wGrammar,wComment^);
ParsePrimitive;
PopLayer;
UNTIL Root(result)=wFail;
Rewind(prevPos)
END;
result:=Confirmation
END pSpaces;
PROCEDURE ParseLexValSequence;
BEGIN
ParseSequencePrimitive(TRUE)
END ParseLexValSequence;
PROCEDURE ParseLexSequence;
BEGIN
ParseSequencePrimitive(FALSE)
END ParseLexSequence;
PROCEDURE ParseValSequence;
BEGIN
Reduce(wSpaces^);
ParseSequencePrimitive(TRUE)
END ParseValSequence;
PROCEDURE ParseSequence;
BEGIN
Reduce(wSpaces^);
ParseSequencePrimitive(FALSE)
END ParseSequence;
PROCEDURE ParseTheLetter;
VAR
chExpect,chRead:CHAR;
BEGIN
ExtractPacked(wPackage^,chExpect);
ReadChar(chRead);
IF chRead=chExpect THEN
IF buildTree THEN
MakePacked(result,wChar,chRead)
ELSE
result:=Confirmation
END
ELSE
result:=Failure
END
END ParseTheLetter;
VAR
strRest:CharPtr;
PROCEDURE ParseTheString;
VAR
ch:CHAR;
strExpect:CharPtr;
BEGIN
ExtractPacked(wPackage^,strExpect);
strRest:=strExpect;
LOOP
IF strRest^=0C THEN
EXIT
END;
ReadChar(ch);
IF strRest^#ch THEN
EXIT
END;
IncAddr(strRest,1)
END;
IF strRest^=0C THEN
IF buildTree THEN
MakeString(result,wString,strExpect)
ELSE
result:=Confirmation
END
ELSE
result:=Failure
END
END ParseTheString;
PROCEDURE ParseTheCharSet;
VAR
ch:CHAR;
s:POINTER TO CharSet;
BEGIN
ExtractPacked(wPackage^,s);
ReadChar(ch);
IF ch IN s^ THEN
IF buildTree THEN
MakePacked(result,wChar,ch)
ELSE
result:=Confirmation
END
ELSE
result:=Failure
END
END ParseTheCharSet;
PROCEDURE ParseNumber;
VAR
ch:CHAR;
minus:BOOLEAN;
x:CARDINAL;
BEGIN
ReadChar(ch);
IF ch='-' THEN
minus:=TRUE;
ReadChar(ch)
ELSE
minus:=FALSE;
IF ch='+' THEN
ReadChar(ch)
END
END;
x:=0;
IF ch IN CharSet{'0'..'9'} THEN
REPEAT
IF x <= (MAX(INTEGER)-ORD(ch)+ORD('0')) DIV 10 THEN
x:=10*x+ORD(ch)-ORD('0')
END;
ReadChar(ch)
UNTIL NOT (ch IN CharSet{'0'..'9'});
Rewind(position-1);
IF minus THEN
MakePacked(result,wNumber,-INTEGER(x))
ELSE
MakePacked(result,wNumber,x)
END
ELSE
result:=Failure
END
END ParseNumber;
PROCEDURE ParseChar;
VAR
delimiter,chRead:CHAR;
BEGIN
ReadChar(delimiter);
IF delimiter="'" THEN
ReadChar(chRead);
ReadChar(delimiter);
IF delimiter="'" THEN
MakePacked(result,wChar,chRead)
ELSE
result:=Failure
END
ELSE
result:=Failure
END
END ParseChar;
PROCEDURE ParseCharSET;
VAR
ch,second,i:CHAR;
s:CharSet;
complement:BOOLEAN;
BEGIN
ReadChar(ch);
IF ch='{' THEN
s:=CharSet{};
ReadChar(ch);
IF ch='~' THEN
complement:=TRUE;
ELSE
complement:=FALSE;
Rewind(position-1)
END;
LOOP
pSpaces;
ReadChar(ch);
IF ch='}' THEN
EXIT
ELSIF ch='\' THEN
ReadChar(ch);
END;
pSpaces;
ReadChar(second);
IF second='-' THEN
pSpaces;
ReadChar(second);
IF second<ch THEN
ch:=0C;
EXIT
END;
FOR i:=ch TO second DO
INCL(s,i)
END;
ReadChar(second)
ELSE
INCL(s,ch)
END;
IF second#',' THEN
IF second#'}' THEN
ch:=0C
END;
EXIT
END
END;
IF ch#0C THEN
IF buildTree THEN
IF complement THEN
s:=all-s;
END;
MakePacked(result,wCharSet,s)
ELSE
result:=Confirmation
END;
RETURN
END
END;
result:=Failure
END ParseCharSET;
PROCEDURE ParseIdentifier;
VAR
first,tail:POINTER TO CharSet;
wd:link;
str:string;
BEGIN
IF (wFirst^=originalFirst) AND (wTail^=originalTail) THEN
ReadWord(str,firstSet,tailSet)
ELSE
ChangeDefinition(wCharSet,HandlePackage);
Reduce(wFirst^);
ExtractPacked(result,first);
Reduce(wTail^);
ExtractPacked(result,tail);
ReadWord(str,first^,tail^)
END;
IF str[0]=0C THEN
result:=Failure
ELSE
wd:=FindWord(str);
IF wd=NIL THEN
ALLOCATE(strPtr,Str.Length(str)+1);
Str.Copy(strPtr^,str);
MakeDef(result,wIdentifier);
DefineWord(wd,strPtr^,result);
AddEnv(wd^,wDescription,DefEntry(wd));
strPtr:=NIL
END;
NewLayer(DefEntry(wd));
result:=wMeaning^
END
END ParseIdentifier;
PROCEDURE ParseString;
VAR
ch,between:CHAR;
str:string;
length:CARDINAL;
BEGIN
ReadChar(between);
IF (between="'") OR (between='"') THEN
length:=0;
ReadChar(ch);
WHILE (ch#between) AND (ch#CHR(13)) AND (length<MaxStrLength) DO
str[length]:=ch;
INC(length);
ReadChar(ch)
END;
IF ch=between THEN
str[length]:=0C;
ALLOCATE(strPtr,length+1);
Str.Copy(strPtr^,str);
MakeString(result,wString,strPtr);
strPtr:=NIL;
RETURN
END
END;
result:=Failure
END ParseString;
PROCEDURE ParseCustom;
VAR
wprop:closure;
BEGIN
ParseIdentifier;
IF Root(result)#wFail THEN
wprop:=DefEntry(Root(result));
ChangeDefinition(wFrameGrammar,wStructGrammar^);
NewLayer(wprop);
ChangeDefinition(wType,result);
Reduce(wFrameGrammar^)
END
END ParseCustom;
PROCEDURE Parse;
VAR
saveFirstSet,saveTailSet:CharSet;
BEGIN
StartLayer;
LinkPrimitive(wSpaces,pSpaces);
LinkPrimitive(wSequence,ParseSequence);
LinkPrimitive(wLexSequence,ParseLexSequence);
LinkPrimitive(wValSequence,ParseValSequence);
LinkPrimitive(wLexValSequence,ParseLexValSequence);
LinkPrimitive(wEndSeq,ParseEndSequence);
LinkPrimitive(wChoice,ParseChoice);
LinkPrimitive(wOption,ParseOption);
LinkPrimitive(wChar,ParseTheLetter);
LinkPrimitive(wString,ParseTheString);
originalFirst:=wFirst^;
originalTail:=wTail^;
Reduce(wFirst^);
saveFirstSet:=firstSet;
ExtractPacked(result,firstSet);
IF Root(result)#wCharSet THEN
originalFirst:=NIL
END;
Reduce(wTail^);
saveTailSet:=tailSet;
ExtractPacked(result,tailSet);
IF Root(result)#wCharSet THEN
originalTail:=NIL
END;
LinkPrimitive(wCharSet,ParseTheCharSet);
LinkPrimitive(wNumGrammar,ParseNumber);
LinkPrimitive(wCharGrammar,ParseChar);
LinkPrimitive(wStrGrammar,ParseString);
LinkPrimitive(wCharSetGrammar,ParseCharSET);
LinkPrimitive(wIdentGrammar,ParseIdentifier);
LinkPrimitive(wCustomGrammar,ParseCustom);
ChangeDefinition(wFrameGrammar,Failure);
pSpaces;
ParsePrimitive;
PopLayer;
originalFirst:=EmptyClosure;
originalTail:=EmptyClosure;
IF Root(result)=wFail THEN
ReportError;
MakePacked(result,wError,SyntaxError)
ELSE
ChangeDefinition(wStruct,result);
Reduce(result)
END;
END Parse;
PROCEDURE pParse;
VAR
filename:POINTER TO string;
newFile:BOOLEAN;
BEGIN
Reduce(wFile^);
newFile:=(Root(result)=wString);
IF newFile THEN
ExtractPacked(result,filename);
IF NOT OpenInput(filename^) THEN
MakePacked(result,wError,IOError);
RETURN
END;
LinkDef(wFile,wUndefined)
END;
NewDictionary;
Parse;
OldDictionary;
IF newFile THEN
CloseInput
END
END pParse;
PROCEDURE MarkInternals;
BEGIN
MarkString(strPtr);
MarkClosure(originalFirst);
MarkClosure(originalTail)
END MarkInternals;
BEGIN
strPtr:=NIL;
originalFirst:=EmptyClosure;
originalTail:=EmptyClosure;
AddMarker(MarkInternals);
AddPrimWord(wParse,'Parse',pParse)
END Parser.