home *** CD-ROM | disk | FTP | other *** search
- External;
-
- {
- Statements.p (of PCQ Pascal)
- Copyright (c) 1989 Patrick Quaid
-
- This module handles normal statements, including the
- standard statements like if, while, case, etc.
- }
-
- {$O-}
- {$I "Pascal.i"}
-
- Function Match(s : Symbols) : Boolean;
- external;
- Function Expression() : TypePtr;
- external;
- Procedure Error(s : string);
- external;
- Function TypeCheck(t1, t2 : TypePtr): Boolean;
- external;
- Procedure SaveStack(t : TypePtr);
- external;
- Procedure SaveVal(v : IDPtr);
- external;
- Procedure ns;
- external;
- Procedure NextSymbol;
- external;
- Function GetLabel(): Integer;
- external;
- Procedure PrintLabel(l : integer);
- external;
- Function Suffix(s : Integer) : Char;
- external;
- Procedure Mismatch;
- external;
- Function LoadAddress() : TypePtr;
- external;
- Procedure CallProc(ProcID : IDPtr);
- external;
- procedure StdProc(ID : IDPtr);
- external;
- Function EndOfFile() : Boolean;
- external;
- Procedure ReadChar;
- external;
- Function FindID(s : string): IDPtr;
- external;
- Function IsVariable(i : IDPtr) : Boolean;
- external;
- Function ConExpr(var t : TypePtr) : integer;
- external;
- function BaseType(t : TypePtr) : TypePtr;
- external;
- Procedure PromoteType(var f : TypePtr; o : TypePtr; r : Short);
- external;
- Function NumberType(t : TypePtr): Boolean;
- external;
- Procedure PushLongD0;
- external;
- Procedure PushLongA0;
- External;
- Procedure PopStackSpace(amount : Integer);
- External;
- Function Selector(ID : IDPtr) : TypePtr;
- external;
- Function FindWithField(s : String) : IDPtr;
- External;
- Function CheckBreak : Boolean;
- External;
- Procedure Abort;
- External;
-
- Procedure Statement;
- forward;
-
- Procedure Assignment(ID : IDPtr);
-
- {
- Not surprisingly, this routine handles assignments.
- }
-
- var
- StackedType,
- VarType,
- ExprType : TypePtr;
-
- begin
- NextSymbol;
- StackedType := Selector(ID);
- if StackedType <> Nil then begin
- PushLongA0;
- VarType := StackedType;
- end else
- VarType := ID^.VType;
- if not match(becomes1) then
- error("expecting :=");
- ExprType := Expression();
- if TypeCheck(VarType, ExprType) then begin
- PromoteType(ExprType, VarType, 0);
- if StackedType <> Nil then
- SaveStack(VarType)
- else
- SaveVal(ID);
- end else
- Mismatch;
- end;
-
- Procedure ReturnVal;
-
- {
- This is similar to the above, but the value is left in d0.
- }
-
- var
- ExprType : TypePtr;
- begin
- nextsymbol;
- if not Match(becomes1) then
- error("expecting :=");
- ExprType := Expression();
- if not TypeCheck(CurrFn^.VType, ExprType) then
- Mismatch;
- if NumberType(ExprType) then
- PromoteType(ExprType, CurrFn^.VType, 0);
- writeln(OutFile, "\tunlk\ta5");
- writeln(OutFile, "\trts");
- end;
-
- Procedure DoWhile;
-
- {
- Handles the while statement.
- }
-
- var
- LoopLabel,
- ExitLabel : Integer;
- begin
- LoopLabel := GetLabel();
- ExitLabel := GetLabel();
- PrintLabel(LoopLabel);
- writeln(OutFile);
- if not TypeCheck(Expression(), BoolType) then
- error("Expecting boolean expression");
- writeln(OutFile, "\ttst.b\td0");
- write(OutFile, "\tbeq\t");
- PrintLabel(ExitLabel);
- writeln(OutFile);
- if not Match(Do1) then
- error("Missing DO");
- Statement;
- write(OutFile, "\tbra\t");
- PrintLabel(LoopLabel);
- writeln(OutFile);
- PrintLabel(ExitLabel);
- writeln(OutFile);
- end;
-
- Procedure DoRepeat;
-
- {
- Handles the repeat statement.
- }
-
- var
- RepLabel : Integer;
- begin
- RepLabel := GetLabel();
- PrintLabel(RepLabel);
- writeln(OutFile);
- while not Match(until1) do begin
- Statement;
- ns;
- end;
- if not TypeCheck(Expression(), Booltype) then
- error("Expecting a Boolean expression.");
- writeln(OutFile, "\ttst.b\td0");
- write(OutFile, "\tbeq\t");
- PrintLabel(RepLabel);
- writeln(OutFile);
- end;
-
- Procedure SaveFor(VarType : TypePtr; off : integer);
-
- {
- This routine saves the new value of the index variable for
- for statements.
- }
-
- begin
- write(OutFile, "\tmove.l\t");
- if off <> 0 then
- write(OutFile, off);
- writeln(OutFile, '(sp),a0');
- writeln(OutFile, "\tmove.", Suffix(VarType^.Size), "\td0,(a0)");
- end;
-
- Procedure IncFor(VarType : TypePtr; Value : Integer);
-
- {
- This routine adjusts the index for increments of 1 or -1.
- }
-
- begin
- writeln(OutFile, "\tmove.l\t4(sp),a0");
- writeln(OutFile, "\tadd.", Suffix(VarType^.Size), "\t#", Value,',(a0)');
- writeln(OutFile, "\tmove.", Suffix(VarType^.Size), "\t(a0),d0");
- end;
-
- Procedure StackInc(VarType : TypePtr);
-
- {
- This handles non-standard increments.
- }
-
- begin
- writeln(OutFile, "\tmove.l\t8(sp),a0");
- writeln(OutFile, "\tmove.l\t(sp),d0");
- writeln(OutFile, "\tadd.", Suffix(VarType^.Size), "\td0,(a0)");
- writeln(OutFile, "\tmove.", suffix(VarType^.Size), "\t(a0),d0");
- end;
-
- Procedure DoFor;
-
- {
- handles the for statement.
- }
-
- var
- looplabel : integer;
- varindex : integer;
- ByType,
- VarType,
- BoundType : TypePtr;
- increment : Short;
- default : Boolean;
- begin
- VarType := LoadAddress();
- if VarType^.Object <> ob_ordinal then
- error("expecting an ordinal type");
- PushLongA0;
- if not Match(becomes1) then
- error("missing :=");
- BoundType := Expression();
- if not TypeCheck(VarType, BoundType) then
- Mismatch;
- PromoteType(BoundType, VarType, 0);
- SaveFor(VarType, 0);
- if Match(to1) then
- increment := 1
- else if Match(downto1) then
- increment := -1
- else
- error("Expecting TO or DOWNTO");
- BoundType := Expression();
- if not TypeCheck(BoundType, VarType) then
- Mismatch;
- PromoteType(BoundType, VarType, 0);
- PushLongD0;
-
- if Match(by1) then begin
- default := false;
- ByType := Expression();
- if not TypeCheck(ByType, VarType) then
- Mismatch;
- PromoteType(ByType, VarType, 0);
- PushLongD0;
- end else
- default := true;
-
- if not Match(do1) then
- error("missing DO");
- looplabel := GetLabel();
- PrintLabel(looplabel);
- writeln(OutFile);
- Statement;
- if default then begin
- IncFor(VarType, increment);
- writeln(OutFile, "\tmove.l\t(sp),d1");
- end else begin
- StackInc(VarType);
- writeln(OutFile, "\tmove.l\t4(sp),d1");
- end;
- writeln(OutFile, "\tcmp.", Suffix(VarType^.Size), "\td1,d0");
- if increment > 0 then
- write(OutFile, "\tble\t")
- else
- write(OutFile, "\tbge\t");
- PrintLabel(LoopLabel);
- writeln(OutFile);
- if default then
- PopStackSpace(8)
- else
- PopStackSpace(12);
- end;
-
- Procedure DoReturn;
-
- {
- This just takes care of return.
- }
-
- begin
- if CurrFn <> Nil then begin
- if CurrFn^.Object = proc then begin
- writeln(OutFile, "\tunlk\ta5");
- writeln(OutFile, "\trts");
- end else
- error("return only allowed in procedures.");
- end else
- error("No return from the main procedure");
- end;
-
- Procedure Compound;
-
- {
- This takes care of the begin...end syntax.
- }
-
- begin
- while not Match(end1) do begin
- Statement;
- if (CurrSym = Else1) or (CurrSym = Until1) then begin
- Error("Expecting a statement");
- NextSymbol;
- end;
- if CurrSym <> End1 then
- ns;
- end;
- end;
-
- procedure DoIf;
-
- {
- This handles the if statement. Eventually it should handle
- elsif.
- }
-
- var
- flab1, flab2 : integer;
- begin
- flab1 := GetLabel();
- if not TypeCheck(Expression(), BoolType) then
- error("Expecting a Boolean type");
- writeln(OutFile, "\ttst.b\td0");
- write(OutFile, "\tbeq\t");
- PrintLabel(flab1);
- writeln(OutFile);
- if not Match(then1) then
- error("Missing THEN");
- Statement;
- if Match(else1) then begin
- flab2 := getlabel();
- write(OutFile, "\tbra\t");
- PrintLabel(flab2);
- writeln(OutFile);
- PrintLabel(flab1);
- writeln(OutFile);
- Statement;
- PrintLabel(flab2);
- writeln(OutFile);
- end else begin
- PrintLabel(flab1);
- writeln(OutFile);
- end;
- end;
-
- procedure DoCase;
-
- procedure DoRange(first, second, lab, typesize : Integer);
- var
- otherlabel : Integer;
- begin
- otherlabel := GetLabel();
- writeln(OutFile, "\tcmp.", Suffix(typesize), "\t#", first, ',d0');
- write(OutFile, "\tblt.s\t");
- printlabel(otherlabel);
- writeln(OutFile, "\n\tcmp.", Suffix(typesize), "\t#", second, ',d0');
- write(OutFile, "\tble\t");
- printlabel(lab);
- writeln(OutFile);
- printlabel(otherlabel);
- writeln(OutFile);
- end;
-
- procedure DoSingle(number, lab, typesize : Integer);
- begin
- writeln(OutFile, "\tcmp.", Suffix(TypeSize), "\t#", number, ',d0');
- write(OutFile, "\tbeq\t");
- PrintLabel(lab);
- writeln(OutFile);
- end;
-
- Procedure DoCases(ctype : TypePtr; codelabel : Integer);
- var
- firstnumber, secondnumber : Integer;
- contype : TypePtr;
- begin
- while not match(colon1) do begin
- firstnumber := ConExpr(ConType);
- if not TypeCheck(ConType, ctype) then
- Mismatch;
- if Match(dotdot1) then begin
- secondnumber := conexpr(contype);
- if not typecheck(ctype, contype) then
- mismatch;
- dorange(firstnumber, secondnumber, codelabel,ctype^.Size);
- end else
- dosingle(firstnumber, codelabel, ctype^.size);
- if currsym <> colon1 then
- if not match(comma1) then
- error("Expecting : or ,");
- end;
- end;
-
- var
- casetype : TypePtr;
- outofcases, nextsetlabel, codelabel : Integer;
- begin
- CaseType := Expression();
- if CaseType^.Object <> ob_ordinal then
- error("Expecting an ordinal type");
- if not match(of1) then
- error("Missing 'of'");
- outofcases := GetLabel();
- while (currsym <> end1) and (currsym <> else1) and (not endoffile()) do begin
- NextSetLabel := GetLabel();
- CodeLabel := GetLabel();
- DoCases(CaseType, CodeLabel);
- write(OutFile, "\tbra\t");
- PrintLabel(NextSetLabel);
- writeln(OutFile);
- PrintLabel(CodeLabel);
- writeln(OutFile);
- Statement;
- if (CurrSym <> Else1) and (CurrSym <> End1) then
- ns;
- write(OutFile, "\tbra\t");
- PrintLabel(OutOfCases);
- writeln(OutFile);
- PrintLabel(NextSetLabel);
- writeln(OutFile);
- end;
- if Match(else1) then
- if CurrSym <> end1 then begin
- Statement;
- ns;
- end;
- if not Match(end1) then
- Error("Expecting 'end'");
- PrintLabel(outofcases);
- writeln(OutFile);
- end;
-
- Procedure DoWith;
- var
- TempRec,
- FirstRec : WithRecPtr;
- Stay : Boolean;
- begin
- FirstRec := Nil;
- repeat
- New(TempRec);
- if FirstRec = Nil then
- FirstRec := TempRec;
- TempRec^.Previous := FirstWith;
- TempRec^.RecType := LoadAddress;
- FirstWith := TempRec;
- if FirstWith^.RecType^.Object <> ob_record then
- Error("Expecting a record type");
- PushLongA0;
- FirstWith^.Offset := StackLoad;
- Stay := Match(Comma1);
- until not Stay;
- if not Match(Do1) then
- Error("Missing DO");
- Statement;
- repeat
- Stay := FirstWith <> FirstRec;
- TempRec := FirstWith^.Previous;
- Dispose(FirstWith);
- FirstWith := TempRec;
- PopStackSpace(4);
- until not Stay;
- end;
-
- Procedure DoGoto;
- var
- ID : IDPtr;
- begin
- if CurrSym = Ident1 then begin
- ID := FindID(SymText);
- if ID <> Nil then begin
- if ID^.Object = lab then begin
- if ID^.Level = CurrentBlock^.Level then begin
- Write(OutFile, '\tbra\t');
- PrintLabel(ID^.Unique);
- Writeln(OutFile);
- NextSymbol;
- end else
- Error("You cannot jump out of scopes");
- end else
- Error("Expecting a label");
- end else
- Error("Unknown ID");
- end else
- Error("Expecting a comment");
- end;
-
- Procedure Statement;
-
- {
- This is the main routine for handling statements of all
- sorts. It distributes the work as necessary.
- }
-
- var
- VarIndex : IDPtr;
- begin
- if EndOfFile() then
- return;
- VarIndex := Nil;
- if CurrSym = Ident1 then begin { Handle label prefix }
- VarIndex := FindWithField(SymText);
- if VarIndex = Nil then
- VarIndex := FindID(SymText);
- if VarIndex <> Nil then begin
- if VarIndex^.Object = lab then begin
- PrintLabel(VarIndex^.Unique);
- Writeln(OutFile);
- NextSymbol;
- if not Match(Colon1) then
- Error("Missing colon");
- VarIndex := Nil;
- end;
- end else
- Error("Unknown ID");
- end;
- if CurrSym = Ident1 then begin
- if VarIndex = Nil then begin { if not Nil, we found it above }
- VarIndex := FindWithField(SymText);
- if VarIndex = Nil then
- VarIndex := FindID(symtext);
- end;
- if varindex = nil then begin
- error("unknown ID");
- while (currsym <> semicolon1) and
- (currsym <> end1) and
- (currentchar <> chr(10)) do
- nextsymbol;
- end else if (varindex = currfn) and (currfn^.Object = func) then
- returnval
- else if IsVariable(VarIndex) then
- assignment(varindex)
- else if VarIndex^.Object = proc then
- callproc(varindex)
- else if VarIndex^.Object = stanproc then
- stdproc(varindex)
- else begin
- error("expecting a variable or procedure.");
- while (currsym <> semicolon1) and
- (currsym <> end1) and
- (currentchar <> chr(10)) do
- nextsymbol;
- if currsym = semicolon1 then
- nextsymbol;
- end;
- end else if match(begin1) then begin
- Compound;
- end else if match(if1) then begin
- DoIf;
- end else if match(while1) then begin
- DoWhile;
- end else if match(repeat1) then begin
- DoRepeat;
- end else if match(for1) then begin
- DoFor;
- end else if match(case1) then begin
- DoCase;
- end else if match(return1) then begin
- DoReturn;
- end else if Match(With1) then begin
- DoWith;
- end else if Match(Goto1) then begin
- DoGoto;
- end else if (CurrSym <> SemiColon1) and (CurrSym <> End1) and
- (CurrSym <> Else1) and (CurrSym <> Until1) then begin
- Error("Expecting a statement");
- while (CurrSym <> SemiColon1) and
- (CurrSym <> End1) and
- (CurrSym <> Else1) and
- (CurrSym <> Until1) and
- (currentchar <> chr(10)) do
- NextSymbol;
- end else
- if CheckBreak then
- Abort;
- end;
-