Plov015 : Fix the IF and function parameters
Still not satisfied with how I solved the matters around the function parameters, I took one more look at the
source, the EBNF and how I would like to have things. To start with the latter: Plov must take care of as much
as is possible with a one symbol lookahead. The ALTO backends should not need any significant intelligence. So
whatever Plov can do, it also SHOULD do.
In Plov014, some dependeces are left open, for ALTO to fill in, when it came to function parameters. OK, I
introduced the keyword PARAMETERS, but that was mustard after the meal. Let's have a look:
# PROCEDURE DECLARATION OF DIVIDE LABEL DIVIDE LOCAL t LOCAL n PARAMETERS 2 LOCAL wWe tell ALTO that a label is present. Then I tell ALTO twice that there is a local variable. Then, after the food is eaten, I present the mustard and tell the backend: the previous two locals were in fact function parameters! Nah nah na nah nahhh!
PROCEDURE getLocals (VAR count : CARDINAL; param : BOOLEAN);
VAR thisLocal : SymbolPtr;
BEGIN
thisLocal := firstLocal;
WHILE thisLocal^.next # NIL DO thisLocal := thisLocal^.next END;
REPEAT
currentType := Vartype;
IF isIdentifier (token) THEN
IF StoreLocal (token) = FALSE THEN
ErrorMessage (6) (* Duplicate identifier *)
END
ELSE
ErrorMessage (5) (* Illegal Identifier *)
END;
INC (count);
IF param THEN CG ("PARAMETER ") ELSE CG ("LOCAL ") END;
CG (token); CG ("");
GetSymbol
UNTIL Strings.StrEq (token, "END") OR Strings.StrEq (token, "LOCAL") OR Strings.StrEq (token, "BEGIN")
END getLocals;
getLocals now accepts two function parameters: the LoCo count and a status variable called 'param' for
uncertain reasons. After the variable has been accepted and stored in the local symbol table, getLocals tests
'param' and if TRUE generates other code than when FALSE.
PROCEDURE ProcedureDeclaration;
VAR thisProc : SymbolPtr;
name : Identifier;
LoCo : CARDINAL;
BEGIN
MemPools.NewPool (Locals);
MemPools.PoolAllocate (Locals, firstLocal, SYSTEM.TSIZE (SymbolNode));
firstLocal^.next := NIL;
LoCo := 0;
GetSymbol;
IF isIdentifier (token) = FALSE THEN ErrorMessage (5) END; (* Illegal identifier *)
currentType := Proctype;
name := token;
CG ("# PROCEDURE DECLARATION OF "); CG (name); CG ("");
CG ("LABEL ");
CG (name); CG ("");
IF StoreSymbol (token) = FALSE THEN ErrorMessage (6) END; (* Duplicate identifier *)
thisProc := thisSymbol;
INC (PROCdepth);
GetSymbol;
IF (Strings.StrEq (token, "BEGIN") = FALSE) AND (Strings.StrEq (token, "LOCAL") = FALSE) THEN
IF isIdentifier (token) THEN
weHaveLocals := TRUE;
getLocals (LoCo, TRUE)
ELSE
ErrorMessage (22)
END
END;
thisProc^.value := LoCo; (* Store number of arguments *)
IF Strings.StrEq (token, "LOCAL") THEN
weHaveLocals := TRUE;
GetSymbol;
getLocals (LoCo, FALSE);
GetSymbol
END;
BlockBody;
DEC (PROCdepth);
IF Strings.StrEq (thisProc^.Name, token) = FALSE THEN
ErrorMessage (19) (* Names do not match *)
END;
GetSymbol;
IF LoCo > 0 THEN
CG ("RELEASE ");
CGn (LoCo);
CG ("");
weHaveLocals := FALSE
END;
MemPools.KillPool (Locals);
CG ("# END OF PROCEDURE ");
CG (name); CG (""); CG ("");
END ProcedureDeclaration;
Plov015 : the IF problem
The following is a typical result of an IF code production:
GOTO XIF-1 LABEL IF-10 LABEL XIF-1Now, if you ever programmed in assembly, it will be clear that is not a too bright construct. Unless you're one of us and have also programmed the 386 is asssembly. Then this kind of sequence was typical for ISA and VLB I/O streamlining. Still, those processors and busstandards have long disappeared from the market. So, looking at it with modern eyes, it doesn't look particularly smart And it's a waste of processor time and onchip program memory.
Also here: there must be a better way. Let's take a look at the IF loop graph on the right.
PROCEDURE isIF;
VAR IFc, lbnr : CARDINAL;
BEGIN
IFc := IFcount; INC (IFcount);
lbnr := 0;
Condition;
CG ("IF "); CG (op); CG (" GOTO IF-");
CGn (IFc); CGn (lbnr); CG ("");
IF Strings.StrEq (token, "THEN") THEN
StatementSequence;
ELSE
ErrorMessage (12) (* THEN expected *)
END;
IF Strings.StrEq (token, "END") = FALSE THEN
CG ("GOTO XIF-"); CGn (IFc);
CG ("")
END;
CG ("LABEL IF-");
CGn (IFc); CGn (lbnr);
CG (""); INC (lbnr);
WHILE Strings.StrEq (token, "ELSIF") DO
Condition;
CG ("IF "); CG (op); CG (" GOTO IF-");
CGn (IFc); CGn (lbnr); CG ("");
IF Strings.StrEq (token, "THEN") THEN
StatementSequence;
CG ("GOTO XIF-"); CGn (IFc); CG ("");
ELSE
ErrorMessage (12) (* THEN expected *)
END;
CG ("LABEL IF-");
CGn (IFc); CGn (lbnr);
CG (""); INC (lbnr);
END;
IF Strings.StrEq (token, "ELSE") THEN
StatementSequence;
(* CG ("LABEL IF-");
CGn (IFc); CGn (lbnr); CG ("");
INC (lbnr) *)
END;
IF Strings.StrEq (token, "END") = FALSE THEN
ErrorMessage (8) (* END expected *)
END;
CG ("LABEL XIF-"); CGn (IFc); CG ("");
GetSymbol
END isIF;
The section in red was added. The section in green was commented out. No need to generate a label after the
ELSE clause. At that point, only the matching END can follow. So this label is one that was never to be used.
Plov015 : see it run
I made a new testprogram: test27. See below how Plov015 fares.
| PROGRAM test27 | # PROGRAM test27 |
| VARIABLES a b c d e f g h i j k END |
VARIABLE a VARIABLE b VARIABLE c VARIABLE d VARIABLE e VARIABLE f VARIABLE g VARIABLE h VARIABLE i VARIABLE j VARIABLE k |
| PROCEDURE gobble a b c |
# PROCEDURE DECLARATION OF gobble LABEL gobble PARAMETER a PARAMETER b PARAMETER c |
| BEGIN | |
| IF a < b THEN |
FETCH LOCAL a FETCH LOCAL b IF GREQ GOTO IF-00 |
| c := d |
ADDRESS LOCAL c FETCH d SAVE |
| e := f . g |
ADDRESS e FETCH f FETCH g MULTIPLY SAVE |
| i := 1 |
ADDRESS i STORE 1 SAVE GOTO XIF-0 |
| ELSIF a = b THEN |
LABEL IF-00 FETCH LOCAL a FETCH LOCAL b IF DIFFERENT GOTO IF-01 |
| d := c |
ADDRESS d FETCH LOCAL c SAVE |
| g := f . i |
ADDRESS g FETCH f FETCH i MULTIPLY SAVE |
| k := j % d |
ADDRESS k FETCH j FETCH d MODULO SAVE GOTO XIF-0 |
| ELSIF b > a THEN |
LABEL IF-01 FETCH LOCAL b FETCH LOCAL a IF LEQ GOTO IF-02 |
| h := 2 |
ADDRESS h STORE 2 SAVE |
| k := i - 1 |
ADDRESS k FETCH i STORE 1 SUBTRACT SAVE GOTO XIF-0 |
| ELSE | LABEL IF-02 |
| d := 0 |
ADDRESS d STORE 0 SAVE |
| END | LABEL XIF-0 |
| END gobble |
RELEASE 3 # END OF PROCEDURE gobble |
| BEGIN | LABEL MAINLOOP |
| gobble 1 2 k |
STORE 1 STORE 2 FETCH k CALL gobble |
| END test27 |
LABEL EXITMAINLOOP # Done # |
| No errors found. |
Let us conclude that the progress is steady.
Page created on 17 September 2008 and
Page equipped with FroogleBuster technology