home *** CD-ROM | disk | FTP | other *** search
Modula Implementation | 1991-08-10 | 15.5 KB | 721 lines |
- (*======================================================================*)
- (* Modula-2 Preprocessor Parser *)
- (*======================================================================*)
- (* Version: 1.00 Author: Dennis Brueni *)
- (* Date: 07-10-91 Changes: Original *)
- (*======================================================================*)
-
- IMPLEMENTATION MODULE Parser;
-
- IMPORT
- FIO,Strings,Env;
- IMPORT
- SymTab,SymLists,MacLists;
- IMPORT
- Err,FSM,LexAn;
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- (*----------------------------------------------------------------------*)
-
-
- PROCEDURE SkipSpace;
- BEGIN
- WITH FSM.Token DO
- WHILE (Class = FSM.M2ch) AND (String[0] = ' ') DO
- LexAn.GetToken;
- END;
- END;
- END SkipSpace;
-
- PROCEDURE GetTokenThenSkipSpace;
- BEGIN
- LexAn.GetToken;
- SkipSpace;
- END GetTokenThenSkipSpace;
-
- (*----------------------------------------------------------------------*)
-
-
-
-
-
-
-
- (*----------------------------------------------------------------------*)
- (* Factor --> ( Expr ) | NOT ID | ID *)
- (*----------------------------------------------------------------------*)
-
-
- PROCEDURE Factor():BOOLEAN;
- VAR
- temp: BOOLEAN;
- symb: SymTab.SymRecPtr;
- BEGIN
-
- WITH FSM.Token DO
- CASE Class OF
- FSM.M2LParen:
- GetTokenThenSkipSpace;
- temp:=Expr();
- IF Class # FSM.M2RParen THEN
- Err.Message(Err.UnBalParens);
- ELSE
- GetTokenThenSkipSpace;
- END;
- |FSM.M2NOT:
- GetTokenThenSkipSpace;
- temp:=NOT Factor();
- |FSM.M2ID:
- symb:=SymTab.LookUp(String);
- temp:=symb#NIL;
- GetTokenThenSkipSpace;
- ELSE
- Err.Message(Err.IllFactor);
- temp:=TRUE;
- END;
- END;
-
- RETURN temp;
- END Factor;
-
- (*----------------------------------------------------------------------*)
- (* Term2 --> & <Factor> <Term2> | e *)
- (*----------------------------------------------------------------------*)
-
- PROCEDURE Term2():BOOLEAN;
- VAR
- temp: BOOLEAN;
- BEGIN
-
- WITH FSM.Token DO
- IF Class=FSM.M2AND THEN
- GetTokenThenSkipSpace;
- temp:= Factor();
- temp:= Term2() AND temp;
- ELSE
- temp:= TRUE;
- END;
- END;
-
- RETURN temp;
- END Term2;
-
- (*----------------------------------------------------------------------*)
- (* Term --> <Factor> <Term2> *)
- (*----------------------------------------------------------------------*)
-
- PROCEDURE Term():BOOLEAN;
- VAR
- temp: BOOLEAN;
- BEGIN
-
- temp:= Factor();
- temp:= Term2() AND temp;
-
- RETURN temp;
- END Term;
-
- (*----------------------------------------------------------------------*)
- (* Expr2 --> | <Term> <Expr2> | e *)
- (*----------------------------------------------------------------------*)
-
- PROCEDURE Expr2():BOOLEAN;
- VAR
- temp: BOOLEAN;
- BEGIN
-
- WITH FSM.Token DO
- IF Class=FSM.M2OR THEN
- GetTokenThenSkipSpace;
- temp:= Term(); (* avoid short circuit *)
- temp:= Expr2() OR temp;
- ELSE
- temp:= FALSE;
- END;
- END;
-
- RETURN temp;
- END Expr2;
-
- (*----------------------------------------------------------------------*)
- (* Expr --> <Term> <Expr2> *)
- (*----------------------------------------------------------------------*)
-
- PROCEDURE Expr():BOOLEAN;
- VAR
- temp: BOOLEAN;
- BEGIN
-
- temp:=Term();
- temp:=Expr2() OR temp;
-
- RETURN temp;
- END Expr;
-
- (*----------------------------------------------------------------------*)
- (* PPStmt --> IF <Expr> @THEN <S> { @ELSIF <S> } *)
- (* [@ELSE <S>] @END *)
- (*----------------------------------------------------------------------*)
-
-
- PROCEDURE IfStmt(Echo: BOOLEAN);
-
- VAR
- TrueFalse: BOOLEAN;
- BEGIN
-
- TrueFalse:=Expr();
- WITH FSM.Token DO
- IF Class = FSM.M2AtSign THEN
- GetTokenThenSkipSpace;
- END;
- IF Class = FSM.M2THEN THEN
- LexAn.GetToken;
- ELSE
- Err.Message(Err.MissThen);
- END;
- LOOP
- Stmt(Echo AND TrueFalse);
- (* THEN clause *)
- IF Class # FSM.M2AtSign THEN
- Err.Message(Err.MissAtElse);
- EXIT;
- END;
- GetTokenThenSkipSpace;
-
- IF (Class=FSM.M2ELSIF) THEN
- (* ELSIF clause, just *)
- GetTokenThenSkipSpace;
- (* like a real IF, sort *)
- IfStmt(Echo AND NOT TrueFalse);
- (* of, so have some *)
- EXIT;
- (* Tail recursion fun *)
- END;
-
- IF Class=FSM.M2ELSE THEN
- (* ELSE clause, ends *)
- LexAn.GetToken;
- (* entire IF statement *)
- LOOP
- Stmt(NOT TrueFalse AND Echo);
- IF Class # FSM.M2AtSign THEN
- Err.Message(Err.MissAtEnd);
-
- RETURN;
- END;
- GetTokenThenSkipSpace;
- IF Class=FSM.M2END THEN
-
- RETURN;
- END;
- PPStmt(NOT TrueFalse AND Echo);
- END;
- END;
-
- IF Class=FSM.M2END THEN
- EXIT;
- END; (* Found the @END? *)
- PPStmt(Echo AND TrueFalse);
- (* NO, preprocessor job *)
- END;
- END;
-
- END IfStmt;
-
- (*----------------------------------------------------------------------*)
- (* PPStmt --> DEFINE ID *)
- (*----------------------------------------------------------------------*)
-
-
- PROCEDURE DefStmt;
-
- VAR
- temp: SymTab.SymRecPtr;
- list: SymLists.SymList;
- BEGIN
-
- WITH FSM.Token DO
- IF Class = FSM.M2ID THEN
- temp:=SymTab.LookUp(String);
- IF temp # NIL THEN
- Err.Message(Err.FlagReDefined);
- END;
- SymLists.Create(list);
- SymTab.Insert(String,FALSE,list,list);
- ELSE
- Err.Message(Err.DefXPctdID);
- END;
- END;
-
- END DefStmt;
-
- (*----------------------------------------------------------------------*)
- (* PPStmt --> UNDEF ID *)
- (*----------------------------------------------------------------------*)
-
- PROCEDURE UnDefStmt;
-
- VAR
- temp: SymTab.SymRecPtr;
-
- BEGIN
-
- WITH FSM.Token DO
- IF Class = FSM.M2ID THEN
- temp:=SymTab.LookUp(String);
- IF temp = NIL THEN
- Err.Message(Err.FlagUnDefined);
- ELSE
- SymTab.Delete(String);
- END;
- ELSE
- Err.Message(Err.UnDefXPctdID);
- END;
- END;
-
- END UnDefStmt;
-
- (*----------------------------------------------------------------------*)
- (* PPStmt --> MACRO ID[(ID {,ID} ) ] <S> @END *)
- (*----------------------------------------------------------------------*)
-
- PROCEDURE MacroStmt;
-
- VAR
- temp: SymTab.SymRecPtr;
- args: SymLists.SymList;
- list: SymLists.SymList;
- name: Strings.BigString;
- MacNest: CARDINAL;
- atsign: ARRAY [0..1] OF CHAR;
- OldStrip: BOOLEAN;
-
- BEGIN
-
- OldStrip:=FSM.StripFlag;
- FSM.StripFlag:=TRUE;
- atsign[0]:='@';
- atsign[1]:=0C;
- MacNest:=0;
- WITH FSM.Token DO
- IF Class = FSM.M2ID THEN
- Strings.Assign(String,name);
- temp:=SymTab.LookUp(String);
- IF temp # NIL THEN
- Err.Message(Err.FlagReDefined);
- END;
- SymLists.Create(list);
- SymLists.Create(args);
- LexAn.GetToken;
- IF Class = FSM.M2LParen THEN
- (* argument list *)
- GetTokenThenSkipSpace;
- IF Class = FSM.M2ID THEN
- MacLists.Insert(args,String,Class);
- GetTokenThenSkipSpace;
- END;
- WHILE Class = FSM.M2Comma DO
- GetTokenThenSkipSpace;
- IF Class = FSM.M2ID THEN
- MacLists.Insert(args,String,Class);
- GetTokenThenSkipSpace;
- ELSE
- Err.Message(Err.MissMacArg);
- END;
- END;
- IF Class = FSM.M2RParen THEN
- GetTokenThenSkipSpace;
- ELSE
- Err.Message(Err.MissMacRP);
- END;
- END;
- LOOP
- WHILE NOT (Class IN FSM.LexSet{FSM.M2AtSign,FSM.M2EOF}) DO
- MacLists.Insert(list,String,Class);
- LexAn.GetToken;
- END;
- IF Class=FSM.M2EOF THEN
- Err.Message(Err.MacNotEnded);
- EXIT;
- END;
- GetTokenThenSkipSpace;
- CASE Class OF
- FSM.M2ENDM :
- IF MacNest=0 THEN
- EXIT;
- ELSE
- DEC(MacNest);
- END;
- |FSM.M2MACRO:
- INC(MacNest);
- ELSE
- END;
- MacLists.Insert(list,atsign,FSM.M2AtSign);
- END;
- SymLists.Reverse(list);
- SymLists.Reverse(args);
- SymTab.Insert(name,TRUE,list,args);
- ELSE
- Err.Message(Err.MacXPctdID);
- END;
- END;
-
- FSM.StripFlag:=OldStrip;
- END MacroStmt;
-
- (*----------------------------------------------------------------------*)
- (* PPStmt --> ID[(<S> {,<S>} ) ] *)
- (*----------------------------------------------------------------------*)
-
- PROCEDURE MacroExpand;
-
- VAR
- macro : SymTab.SymRecPtr;
- argnam: MacLists.TokRecPtr;
- parens: CARDINAL; (* for balancing parens *)
- args,newarg,arglst,null: SymLists.SymList;
- exclam, atsign : ARRAY [0..1] OF CHAR;
-
- PROCEDURE AddMacro;
- BEGIN
- SymLists.Reverse(newarg);
- IF SymLists.Empty(args) THEN (* stick it on symtab *)
- Err.Message(Err.TooMany);
- ELSE
- argnam:=SymLists.First(args);
- args:=SymLists.Next(args);
- SymTab.Insert(argnam^.sym^,TRUE,newarg,null);
- SymLists.Insert(arglst,argnam);
- MacLists.Insert(arglst,exclam,FSM.M2KillArg);
- END;
- END AddMacro;
-
- BEGIN
-
- atsign[0]:='@';
- atsign[1]:=0C;
- exclam[0]:='!';
- exclam[1]:=0C;
- WITH FSM.Token DO
- macro:=SymTab.LookUp(String);
- IF macro = NIL THEN
- Err.Message(Err.FlagUnDefined);
- ELSE
- WITH macro^ DO
- IF NOT mac THEN
- Err.Message(Err.IDNotMacro);
- ELSE
- LexAn.GetToken;
- SymLists.Create(arglst);
- IF Class # FSM.M2LParen THEN
- (* argument list *)
- MacLists.Insert(arglst,String,Class);
- ELSE
- args:=mca;
- SymLists.Create(null);
- (* empty param list for args *)
- LOOP
- LexAn.GetToken;
- SymLists.Create(newarg);
- (* get an argument *)
- parens:=0;
- WHILE Class # FSM.M2Comma DO
- CASE Class OF
- FSM.M2AtSign:
- GetTokenThenSkipSpace;
- IF NOT (Class IN FSM.LexSet{FSM.M2Comma, FSM.M2RParen,
- FSM.M2LParen}) THEN
- MacLists.Insert(newarg,atsign,FSM.M2AtSign);
- END;
- |FSM.M2LParen:
- INC(parens);
- |FSM.M2RParen:
- IF parens > 0 THEN
- DEC(parens);
- ELSE
- EXIT;
- END;
- |FSM.M2EOF:
- Err.Message(Err.ArgNotEnded);
- EXIT;
- ELSE
- END;
- MacLists.Insert(newarg,String,Class);
- LexAn.GetToken;
- END;
- AddMacro;
- END;
- AddMacro;
- END;
- (* loop *)
- LexAn.FeedMacro(arglst);
- (* reminder TO remove bindings *)
- LexAn.FeedMacro(mcl);
- END;
- (* IF *)
- END;
- (* WITH macro^ *)
- END;
- (* IF *)
- END;
- (* WITH FSM.Token *)
-
- END MacroExpand;
-
- (*----------------------------------------------------------------------*)
- (* PPStmt --> INCLUDE String | INCLUDE Str *)
- (*----------------------------------------------------------------------*)
-
-
- PROCEDURE IncStmt;
-
- VAR
- oldsrc: FIO.FILE;
- list: SymLists.SymList;
- LPtr: MacLists.TokRecPtr;
- FPath: Strings.BigString;
-
- BEGIN
-
- oldsrc:=FSM.SourceFile;
- INC(FSM.IncludeLevel);
- list:=IncludeList;
- WITH FSM.Token DO
- IF Class IN FSM.LexSet{FSM.M2Str,FSM.M2String} THEN
- LOOP
- IF SymLists.Empty(list) THEN
- FIO.WriteString(FIO.OUTPUT,'Could not find include file: ');
- FIO.WriteString(FIO.OUTPUT,String);
- FIO.WriteLn(FIO.OUTPUT);
- EXIT;
- END;
- LPtr:=SymLists.First(list);
- Strings.Assign(LPtr^.sym^,FPath);
- Strings.Append(String,FPath);
- IF LexAn.SetSourceFile(FPath) THEN
- Parse;
- FIO.Close(FSM.SourceFile);
- EXIT;
- END;
- list:=SymLists.Next(list);
- END;
- ELSE
- Err.Message(Err.MissStr);
- END;
- END;
- DEC(FSM.IncludeLevel);
- FSM.SourceFile:=oldsrc;
-
- END IncStmt;
-
- (*----------------------------------------------------------------------*)
- (* PPStmt --> IF <Expr> @THEN <S> { @ELSIF <S> } *)
- (* [@ELSE <S>] @END *)
- (* PPStmt --> DEFINE ID | UNDEF ID *)
- (* PPStmt --> INCLUDE String | INCLUDE Str *)
- (* PPStmt --> MACRO ID[(ID {,ID} ) ] <S> @END *)
- (* PPStmt --> ID[(<S> {,<S>} ) ] *)
- (* PPStmt --> LINE | SPACE | STRIP | NOSTRIP *)
- (* PPStmt --> ',' | '@' | '(' | ')' *)
- (*----------------------------------------------------------------------*)
-
-
- PROCEDURE PPStmt(Echo: BOOLEAN);
- BEGIN
-
- WITH FSM.Token DO
- IF Echo THEN
- CASE Class OF
- FSM.M2IF :
- GetTokenThenSkipSpace;
- IfStmt(Echo);
- |FSM.M2DEFINE :
- GetTokenThenSkipSpace;
- DefStmt;
- |FSM.M2UNDEF :
- GetTokenThenSkipSpace;
- UnDefStmt;
- |FSM.M2INCLUDE:
- GetTokenThenSkipSpace;
- IncStmt;
- |FSM.M2MACRO :
- GetTokenThenSkipSpace;
- MacroStmt;
- |FSM.M2ID :
- MacroExpand;
- |FSM.M2STRIP :
- FSM.StripFlag:=TRUE;
- |FSM.M2NOSTRIP:
- FSM.StripFlag:=FALSE;
- |FSM.M2LINE :
- FIO.WriteLn(FSM.DestFile);
- |FSM.M2SPACE :
- FIO.WriteChar(FSM.DestFile,' ');
- |FSM.M2Comma, FSM.M2AtSign, FSM.M2LParen, FSM.M2RParen :
- FIO.WriteChar(FSM.DestFile,String[0]);
- ELSE
- Err.Message(Err.BadPPStmt);
- FIO.WriteString(FSM.DestFile,String);
- END;
- ELSE
- IF Class=FSM.M2IF THEN
- (* have to parse IF's *)
- GetTokenThenSkipSpace;
- (* if if not echoing *)
- IfStmt(FALSE);
- END;
- END;
- END;
- LexAn.GetToken;
-
- END PPStmt;
-
- (*----------------------------------------------------------------------*)
- (* Stmt --> IF | THEN | ELSE ELSIF | END | DEFINE | UNDEF *)
- (* Stmt --> INCLUDE | MACRO | ENDM | AND | OR | NOT | ID *)
- (* Stmt --> STRIP | NOSTRIP | LINE | SPACE *)
- (* Stmt --> ',' | '(' | ')' | String | ch | Str | Block *)
- (* Stmt --> @ <PPStmt> *)
- (*----------------------------------------------------------------------*)
-
- PROCEDURE Stmt(Echo: BOOLEAN);
-
- PROCEDURE StringOut(delim: CHAR);
- BEGIN
- FIO.WriteChar(FSM.DestFile,delim);
- FIO.WriteString(FSM.DestFile,FSM.Token.String);
- FIO.WriteChar(FSM.DestFile,delim);
- END StringOut;
-
- BEGIN
-
- WITH FSM.Token DO
- WHILE NOT (Class IN FSM.LexSet{FSM.M2EOF,FSM.M2AtSign}) DO
- IF Echo THEN
- CASE Class OF
- FSM.M2String:
- StringOut('"');
- |FSM.M2Str:
- StringOut(47C);
- ELSE
- FIO.WriteString(FSM.DestFile,String);
- END;
- END;
- LexAn.GetToken;
- END;
- (* POSTCONDITION: When Stmt exits, *)
- END;
- (* the current token is either EOF or @ *)
-
- END Stmt;
-
- (*----------------------------------------------------------------------*)
- (* S --> { <Stmt> } EOF *)
- (*----------------------------------------------------------------------*)
-
- PROCEDURE Parse;
-
- BEGIN
-
- LexAn.GetToken;
- WITH FSM.Token DO
- WHILE Class # FSM.M2EOF DO
- Stmt(TRUE);
- IF Class = FSM.M2AtSign THEN
- GetTokenThenSkipSpace;
- PPStmt(TRUE);
- END;
- END;
- (* POSTCONDITION: When Parse exits, *)
- END;
- (* the current token is EOF *)
-
- END Parse;
-
- (************************************************************************)
-
-
- PROCEDURE GetIncludeEnv;
-
- VAR
- IncEnv: ARRAY [0..1023] OF CHAR;
- String: ARRAY [0.. 255] OF CHAR;
-
- BEGIN
- SymLists.Create(IncludeList);
- MacLists.Insert(IncludeList,
- (* !!! error, final ' on line expected !!! *)
- (* !!! error, "END" expected, NOT "'',FSM.M2ID); (" !!! *)
- (* !!! error, "identifier" expected, NOT "'',FSM.M2ID); (" !!! *)
- (* !!! error, ";" expected, NOT "'',FSM.M2ID); (" !!! *)
- (* !!! error, "END" expected, NOT "'',FSM.M2ID); (" !!! *)
- (* !!! error, "identifier" expected, NOT "'',FSM.M2ID); (" !!! *)
- (* !!! error, "." expected, NOT "'',FSM.M2ID); (" !!! *)
- (* !!! error, END OF file expected, NOT "'',FSM.M2ID); (", FORMATTING STOPS !!! *)
- '',FSM.M2ID); (* current directory *)
- Env.GetEnv('M2PInclude',IncEnv);
- WHILE Env.ParseEnv(IncEnv,String) DO
- MacLists.Insert(IncludeList,String,FSM.M2ID);
- END;
- SymLists.Reverse(IncludeList);
- END GetIncludeEnv;
-
-
- BEGIN
-
- PrintTrace := FALSE;
- GetIncludeEnv;
- END Parser.
-