Plov014 : Procedure arguments

Although the original specification of PLOV does not offer function parameters, I think this is a too severe omission. And the official EBNF of PLOV also didn't list any other loop than LOOP/EXIT/END. So I make another gesture and want to introduce function parameters as well.
Most of the work needs to be done in the procedure 'ProcedureDeclaration' and this is not up to date. It was one of the very first well running parts of Plov. And it is starting to show.... Literally. Look at the indents. It's one major triangle. IF one, THEN IF 2 THEN IF 3 etcetera. It's how a human sees the procedure description. But a parser??

      
PROCEDURE ProcedureDeclaration;

VAR	thisP	: SymbolPtr;
	name	: Identifier;
	LoCo	: CARDINAL;

BEGIN
   LoCo := 0;
   GetSymbol;
   IF  isIdentifier (token)  THEN
      currentType := Proctype;
      name := token;
      CG ("# PROCEDURE DECLARATION OF ");	CG (name);	CG ("");
      CG ("LABEL ");
      CG (name);		CG ("");
      IF  StoreSymbol (token) = TRUE  THEN
	 thisP := thisSymbol;
	 INC (PROCdepth);
	 GetSymbol;
	 IF  Strings.StrEq (token, "LOCAL")  THEN
	    MemPools.NewPool (Locals);
	    MemPools.PoolAllocate (Locals, firstLocal, SYSTEM.TSIZE (SymbolNode));
	    firstLocal^.next := NIL;
	    weHaveLocals := TRUE;
	    getLocals (LoCo)
	 END;
	 BlockBody;
	 DEC (PROCdepth);
	 IF  Strings.StrEq (thisP^.Name, token) = FALSE  THEN
	    ErrorMessage (19)		(* Names do not match	*)
	 END;
	 GetSymbol
      ELSE
	 ErrorMessage (6)		(* Duplicate identifier	*)
      END
   ELSE
      ErrorMessage (5)			(* Illegal identifier 	*)
   END;
   IF  LoCo > 0  THEN
      CG ("RELEASE ");
      CGn (LoCo);
      CG ("");
(*      PrintLocals;		*)
      MemPools.KillPool (Locals);
      weHaveLocals := FALSE
   END;
   CG ("# END OF PROCEDURE ");
   CG (name);			CG ("");	CG ("");
END ProcedureDeclaration;
   

Plov014 : the new ProcedureDeclaration

The brainwave that made me realize function parameters are in fact just local variables that are initialized by the caller, made implementing them rather easy. Still, the full ProcedureDeclaration routine needs to be rewritten as well. So let's start out ith that one:

PROCEDURE ProcedureDeclaration;

VAR	thisP	: SymbolPtr;
	name	: Identifier;
	LoCo	: CARDINAL;

BEGIN
   MemPools.NewPool (Locals);
   MemPools.PoolAllocate (Locals, firstLocal, SYSTEM.TSIZE (SymbolNode));
   firstLocal^.next := NIL;
   
No matter if I have local variables or not, I will create the memorypool.
   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	*)
   thisP := thisSymbol;
   INC (PROCdepth);
   GetSymbol;
   IF  Strings.StrEq (token, "(")  THEN  
      weHaveLocals := TRUE;
      getLocals (LoCo)
   END;
   thisP^.value := LoCo;			(* Store number of arguments	*)
   IF  Strings.StrEq (token, "LOCAL")  THEN
      weHaveLocals := TRUE;
      getLocals (LoCo)
   END;
   BlockBody;
   DEC (PROCdepth);
   IF  Strings.StrEq (thisP^.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;
   
Look at the indentation. It's no triangle anymore. And it shows! If you run this program with an error in the PROCEDURE definition in your PLOV source, the error is flagged but the compiler does not loose state!

The interested reader will have noticed that this does not comply with the current version of getLocals. So I have rewritten that as well. It now has a multiple exit strategy and does not initialize LoCo to zero. And it searches the local label table.

PROCEDURE getLocals (VAR  count	  : CARDINAL);

VAR	thisLocal	: SymbolPtr;

BEGIN
   thisLocal := firstLocal;
   WHILE  thisLocal^.next # NIL  DO  thisLocal := thisLocal^.next  END;
   GetSymbol;
   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);
      CG ("LOCAL   ");		CG (token);		CG ("");
      GetSymbol
   UNTIL Strings.StrEq (token, "END") OR  Strings.StrEq (token, ')');
   GetSymbol
END getLocals;
   
In order to see on screen if we have an error (the infinite loop, flooding the screen, is gone now) I added a few lines of code to the ShutDown section:
      
PROCEDURE ShutDown;

BEGIN
   TextIO.Close (inFile);
   TextIO.Close (outFile);
   InOut.WriteLn;
   MemPools.KillPool (Symbols);
   IF  ErrCount = 0  THEN
      InOut.WriteString ("No errors found.")
   ELSE
      InOut.WriteCard (ErrCount, 1);
      InOut.WriteString (" errors found.")
   END;
   InOut.WriteLn;
   InOut.WriteLn;
END ShutDown;
   

Plov014 : see it run

Here is a small test source:

PROGRAM test23

CONSTANTS	m =  7
		n = 85
END

VARIABLES	x 
		y 
		z 
		q
		r
END


PROCEDURE 1MULTIPLY

LOCAL 	a b	END

BEGIN
  a := x
  b := y
  z := 0
  WHILE b MOD 2 = 1 DO 
    IF b = 1 THEN 
      z := z + a 
      a := a - n
    END
    a := a + a
    b := b / 2
  END
END MULTIPLY


PROCEDURE DIVIDE

LOCAL 	w	END

BEGIN
  r := x
  q := 0
  w := y
  WHILE w <= r DO 
    w := w + w
    z := y + 1
  END
  WHILE w > y DO 
    q := q + q
    w := w / 2
    IF w <= r THEN 
      r := r - w
      q := q + 1
    END
  END
END DIVIDE


PROCEDURE Gcd

LOCAL	 f g	END

BEGIN
  f := x
  g := y
  WHILE f # g DO 
    IF f < g THEN 
      g := g - f
      q := f + g
    END
    IF g < f THEN
      f := f - g
      r := m . x
    END
  END
  z := f
END Gcd

BEGIN
  x := m
  y := n
  MULTIPLY
  x := 25
  y :=  3
  DIVIDE
  x := 84
  y := 36
  Gcd
END test23
      
PROGRAM test23

CONSTANTS	m =  7
		n = 85
END

VARIABLES	x 
		y 
		z 
		q
		r
END


PROCEDURE 1MULTIPLY

@@  -- Illegal identifier name : 1MULTIPLY in line    16

LOCAL 	a b	END

BEGIN
  a := x
  b := y
  z := 0
  WHILE b MOD 2 = 1 DO 
    IF b = 1 THEN 
      z := z + a 
      a := a - n
    END
    a := a + a
    b := b / 2
  END
END MULTIPLY

@@  -- Procedure names do not match. in line    32


PROCEDURE DIVIDE

LOCAL 	w	END

BEGIN
  r := x
  q := 0
  w := y
  WHILE w <= r DO 
    w := w + w
    z := y + 1
  END
  WHILE w > y DO 
    q := q + q
    w := w / 2
    IF w <= r THEN 
      r := r - w
      q := q + 1
    END
  END
END DIVIDE


PROCEDURE Gcd

LOCAL	 f g	END

BEGIN
  f := x
  g := y
  WHILE f # g DO 
    IF f < g THEN 
      g := g - f
      q := f + g
    END
    IF g < f THEN
      f := f - g
      r := m . x
    END
  END
  z := f
END Gcd

BEGIN
  x := m
  y := n
  MULTIPLY
  x := 25

@@  -- Undefined symbol or keyword in line    82
  y :=  3
  DIVIDE
  x := 84
  y := 36
  Gcd
END test23

3 errors found.
      

Not bad, if I say it myself! The third error is one line too low, for some silly reason. This will neeed some more attention. But that's what tests are for.

It's good that the errorchecker works as it should. It's also good that the new proceduredeclaration section does not loose state when an error is encountered. But the issue of Plov014 was function parameters as local variables... Let's see how good it is with that. Below is the source of test25 (left) accompanied by it's PALO output (on the right, of course).

PROGRAM test25

CONSTANTS a = 1 END

VARIABLES  ab END

PROCEDURE hhhhhhh ( var1 var2 )

LOCAL aa ss END

BEGIN
  aa := ss + 22
  ss := var1 * var2
END hhhhhhh

BEGIN
  ab := a + 1
END test25
      
# PROGRAM test25

VARIABLE	ab

# PROCEDURE DECLARATION OF hhhhhhh
LABEL hhhhhhh
LOCAL   var1
LOCAL   var2
LOCAL   aa
LOCAL   ss

ADDRESS LOCAL aa
FETCH LOCAL ss
STORE	22
ADD
SAVE

ADDRESS LOCAL ss
FETCH LOCAL var1
FETCH LOCAL var2
MULTIPLY
SAVE

RELEASE 4
# END OF PROCEDURE hhhhhhh


LABEL MAINLOOP

ADDRESS ab
STORE	1
STORE	1
ADD
SAVE

LABEL EXITMAINLOOP
# Done #
      

For some reason I feel a little proud..... We've come a long way! Thanks to the Mad Swiss. At least, that's how they like to refer to these geniuses in some American textbooks. For me, Nic and Jürg are just heroes.

Plov014 : rethinking my sins

So it was kind of late. But the function parameters worked. I used a dirty trick: parenthesis. In any other language, parenthesis are omni present. In PLOV they only exist in mathematical expressions. And in function declarations. This detonates. There should be a better way. Let's look at a few examples for PROCEDURE declarations:

PROCEDURE routine2

LOCAL  a b  END

BEGIN .. END routine2


PROCEDURE routine1 var1 var2

LOCAL  a b  END

BEGIN .. END routine1


PROCEDURE routine3 var1 var2

BEGIN .. END routine3
   
We're in 'StatementSequence' and the token has been identified as an Identifier: the name of the procedure. We get the next symbol. This can be any of three (but no more than that) things:
  1. 'LOCAL', a keyword
  2. 'BEGIN' when we have neither LOCALs nor parameters
  3. an Identifier
This is a rather promising situation. We don't need parenthesis for embracing the function parameters. When we've found the name of the PROCEDURE, we just get the next symbol (token) and see if it is either 'BEGIN' or 'LOCAL'. If it is not, it MUST be an Identifier and if it is, it is a parameter. So we start 'getLocals' to get the job done. The procedure getLocals has been changed a bit to handle the new stop-condition.
When getLocals is done, the next token must be either LOCAL or BEGIN. Either way is perfectly handled by the existing PLOV Procedure. Time to get some code online:
PROCEDURE getLocals (VAR  count	  : CARDINAL);

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);
      CG ("LOCAL   ");		CG (token);		CG ("");
      GetSymbol
   UNTIL Strings.StrEq (token, "END") OR  Strings.StrEq (token, "LOCAL") OR Strings.StrEq (token, "BEGIN")
END getLocals;
   
getLocals will keep on enclosing local variables in its memory pool until it encounters either of the reserved words "LOCAL" or "BEGIN" (in case it was called for collecting the parameter list) or the word "END" (in case it was called by the LOCAL keyword).
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);
   
This is where the new section is inserted. If the token is not 'LOCAL' and is not 'BEGIN' then the current token must be an identifier and if so, it is the first (and possibly only) entry in the parameter list. See how it continues:
   GetSymbol;
   IF  (Strings.StrEq (token, "BEGIN") = FALSE) AND (Strings.StrEq (token, "LOCAL") = FALSE)  THEN
      IF  isIdentifier (token)  THEN
	 weHaveLocals := TRUE;
	 getLocals (LoCo)
      ELSE
	 ErrorMessage (22)
      END
   END;
   
Here we're back in the normal flow. We've dealt with the optional parameter list and now it's either a LOCAL or a BEGIN coming our way.
   thisProc^.value := LoCo;			(* Store number of arguments	*)
   IF  Strings.StrEq (token, "LOCAL")  THEN
      weHaveLocals := TRUE;
      GetSymbol;
      getLocals (LoCo)
   END;
   GetSymbol;
   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;
   

Plov014 : see it run (once more)

Of course I tested this and by now it should be running stable. Still, I don't want to spoil things and here's the proof to the pudding:

PLOV PALO
PROGRAM test25

CONSTANTS a = 1 END

VARIABLES  ab END

PROCEDURE hhhhhhh var1 var2

LOCAL aa ss END

BEGIN
  aa := ss + 22
  ss := var1 * var2
END hhhhhhh

BEGIN
  ab := a + 1
END test25

No errors found.
      
# PROGRAM test25

VARIABLE	ab

# PROCEDURE DECLARATION OF hhhhhhh
LABEL hhhhhhh
LOCAL   var1
LOCAL   var2
LOCAL   aa
LOCAL   ss

ADDRESS LOCAL aa
FETCH LOCAL ss
STORE	22
ADD
SAVE

ADDRESS LOCAL ss
FETCH LOCAL var1
FETCH LOCAL var2
MULTIPLY
SAVE

RELEASE 4
# END OF PROCEDURE hhhhhhh


LABEL MAINLOOP

ADDRESS ab
STORE	1
STORE	1
ADD
SAVE

LABEL EXITMAINLOOP
# Done #
      

Last night I was feeling kind of proud. Now I AM proud. Period!

Plov014 : one refinement further

If the program runs and it does so in a controlled way, it gives a boost to loose thinking. What if I? Can I make it simpler? Is this really necessary? This brought me to one addition to ProcedureDeclaration: a new PALO keyword called PARAMETERS. It tells PALO that the local variables until now were in fact parameters.
And I needed to make the ProcedureCall section. And it works! Below are the sources.

Plov014 : modifications to ProcedureDeclaration

The changes are in RED.

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)
      ELSE
	 ErrorMessage (22)
      END
   END;
   CG ("PARAMETERS ");		CGn (LoCo);		CG ("");
   thisProc^.value := LoCo;				(* Store number of arguments	*)
   IF  Strings.StrEq (token, "LOCAL")  THEN
      weHaveLocals := TRUE;
      GetSymbol;
      getLocals (LoCo);
      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;
   
Not much changed but it was a decisive change... On to the ProcedureCall function:
PROCEDURE Procedurecall;

VAR	args, n		: CARDINAL;
	name		: Identifier;

BEGIN
   args := thisSymbol^.value;	n := args;
   name := token;
   WHILE  n > 0  DO
      GetSymbol;
      IF  findType (token) = Constype	THEN	CG ("STORE ");	  CGn (thisSymbol^.value)
      ELSIF  isNumber (token)		THEN	CG ("STORE ");	  CG  (token)
      ELSIF  findType (token) = Vartype  THEN
	 CG ("FETCH ");
	 IF  FindLocal (token) = TRUE  THEN  CG ("LOCAL ")  END;
	 CG (token)
      ELSE
	 ErrorMessage (24)
      END;
      CG ("");
      DEC (n)
   END;
   CG ("CALL ");		CG (name);		CG ("");
   GetSymbol
END Procedurecall;
   
The procedure collects the number of arguments and tries to get them. No check so far for the presence of the arguments but you cannot do it all at once. A token is collected and some code is generated, depending on the type of the argument (numer, constant or variable). The calling is by value. So far.
The numbers are stored on the stack. In the wrong order, so far. But this is a working concept. And now I want to see it run again. For this, I made a new testprogram, based on the wikitest.

PLOV PALO
PROGRAM test26

CONSTANTS	m =  7
		n = 85
END

VARIABLES	x 
		y 
		z 
		q
		r
END


PROCEDURE MULTIPLY p q

BEGIN
  z := 0
  WHILE q MOD 2 = 1 DO 
    IF q = 1 THEN z := z + p END
    p := p + p
    q := q / 2
  END
END MULTIPLY


































PROCEDURE DIVIDE t n

LOCAL 	w	END

BEGIN
  t := x
  q := 0
  n := y
  WHILE n <= t DO n := n + n END
  WHILE n > y DO 
    q := q + q
    n := n / 2
    IF n <= t THEN 
      t := t - n
      q := q + 1
    END
  END
END DIVIDE


























































PROCEDURE Gcd

LOCAL	 f g	END

BEGIN
  f := x
  g := y
  WHILE f # g DO 
    IF f < g THEN 
      g := g - f
      q := f + g
    END
    IF g < f THEN
      f := f - g
      r := m . x
    END
  END
  z := f
END Gcd





















































BEGIN
  MULTIPLY m n
  DIVIDE x y
  x := 84
  y := 36
  Gcd
END test26
      
# PROGRAM test26

VARIABLE	x
VARIABLE	y
VARIABLE	z
VARIABLE	q
VARIABLE	r

# PROCEDURE DECLARATION OF MULTIPLY
LABEL MULTIPLY
LOCAL   p
LOCAL   q
PARAMETERS 2

ADDRESS z
STORE	0
SAVE

LABEL WHILE-0
FETCH LOCAL q
STORE	2
MODULO
STORE	1
IF DIFFERENT GOTO XWHILE-0

FETCH LOCAL q
STORE	1
IF DIFFERENT GOTO IF-00

ADDRESS z
FETCH z
FETCH LOCAL p
ADD
SAVE

GOTO XIF-0
LABEL IF-00
LABEL XIF-0

ADDRESS LOCAL p
FETCH LOCAL p
FETCH LOCAL p
ADD
SAVE

ADDRESS LOCAL q
FETCH LOCAL q
STORE	2
DIVIDE
SAVE

GOTO WHILE-0
LABEL XWHILE-0

RELEASE 2
# END OF PROCEDURE MULTIPLY


# PROCEDURE DECLARATION OF DIVIDE
LABEL DIVIDE
LOCAL   t
LOCAL   n
PARAMETERS 2
LOCAL   w

ADDRESS LOCAL t
FETCH x
SAVE

ADDRESS q
STORE	0
SAVE

ADDRESS LOCAL n
FETCH y
SAVE

LABEL WHILE-1
FETCH LOCAL n
FETCH LOCAL t
IF GREATER GOTO XWHILE-1

ADDRESS LOCAL n
FETCH LOCAL n
FETCH LOCAL n
ADD
SAVE

GOTO WHILE-1
LABEL XWHILE-1

LABEL WHILE-2
FETCH LOCAL n
FETCH y
IF LEQ GOTO XWHILE-2

ADDRESS q
FETCH q
FETCH q
ADD
SAVE

ADDRESS LOCAL n
FETCH LOCAL n
STORE	2
DIVIDE
SAVE

FETCH LOCAL n
FETCH LOCAL t
IF GREATER GOTO IF-10

ADDRESS LOCAL t
FETCH LOCAL t
FETCH LOCAL n
SUBTRACT
SAVE

ADDRESS q
FETCH q
STORE	1
ADD
SAVE

GOTO XIF-1
LABEL IF-10
LABEL XIF-1

GOTO WHILE-2
LABEL XWHILE-2

RELEASE 3
# END OF PROCEDURE DIVIDE


# PROCEDURE DECLARATION OF Gcd
LABEL Gcd
PARAMETERS 0
LOCAL   f
LOCAL   g

ADDRESS LOCAL f
FETCH x
SAVE

ADDRESS LOCAL g
FETCH y
SAVE

LABEL WHILE-3
FETCH LOCAL f
FETCH LOCAL g
IF EQUAL GOTO XWHILE-3

FETCH LOCAL f
FETCH LOCAL g
IF GREQ GOTO IF-20

ADDRESS LOCAL g
FETCH LOCAL g
FETCH LOCAL f
SUBTRACT
SAVE

ADDRESS q
FETCH LOCAL f
FETCH LOCAL g
ADD
SAVE

GOTO XIF-2
LABEL IF-20
LABEL XIF-2

FETCH LOCAL g
FETCH LOCAL f
IF GREQ GOTO IF-30

ADDRESS LOCAL f
FETCH LOCAL f
FETCH LOCAL g
SUBTRACT
SAVE

ADDRESS r
STORE	7
FETCH x
MULTIPLY
SAVE

GOTO XIF-3
LABEL IF-30
LABEL XIF-3

GOTO WHILE-3
LABEL XWHILE-3

ADDRESS z
FETCH LOCAL f
SAVE

RELEASE 2
# END OF PROCEDURE Gcd


LABEL MAINLOOP

STORE 7
STORE 85
CALL MULTIPLY

FETCH x
FETCH y
CALL DIVIDE

ADDRESS x
STORE	84
SAVE

ADDRESS y
STORE	36
SAVE

CALL Gcd

LABEL EXITMAINLOOP
# Done #
      

Let's call it 'Assuring'.

Page created on 15 September 2008 and

Page equipped with FroogleBuster technology