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   w
   
We 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!
This is not good. Now the ALTO backend needs to do too many things. There must be a better way. And of course there was. And a simple one too! First I changed 'getLocals':
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.
This, of course, also requires the modification of ProcedureDeclaration:
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-1
   
Now, 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.

We do have a lookahead of one token so we DO know what the first token after the 'action' is. Based on this we can change the isIF procedure to act intelligently:
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