Plov017 : Almost done

A few additions and one of the additions of Plov016 turned back again... The new version of 'Condition' resulted in too many false error messages. For the time being the improvements were turned back again. The additions for today were:

Plov017 : IRQ

A microcontroller lives by the grace of interrupt service routines. For example, the AVR's code space starts with 15 IRQ vectors. Therefore, sooner or later a mechanism will be required to define these IRQ vectors. For this, the IRQ keyword was defined. See how it's implemented. First of all, IRQ is part of BLOCK:

PROCEDURE Block;

BEGIN
   GetSymbol;
   IF	  Strings.StrEq (token, "CONSTANTS")  THEN  ConstantDeclaration	 	   END;
   IF	  Strings.StrEq (token, "VARIABLES")  THEN  VariableDeclaration;  CG ("")  END;
   WHILE  Strings.StrEq (token, "PROCEDURE")  DO    ProcedureDeclaration; CG ("")  END;
   WHILE  Strings.StrEq (token, "IRQ")	      DO    isIRQ;			   END;
   BlockBody;
END Block;
   
IRQ needs to be defined before the main loop starts and after all procedures have been defined. IRQ procedures need to exist and the parser must have scanned them.
PROCEDURE isIRQ;

VAR	irq		: CARDINAL;
	irqN		: Identifier;

BEGIN
   GetSymbol;
   irqN := token;
   IF  NOT isNumber (token)  THEN  ErrorMessage (1)  END;
   GetSymbol;
   IF  NOT Strings.StrEq (token, '=')  THEN  ErrorMessage (7)  END;
   GetSymbol;
   IF  findType (token) # Proctype  THEN  ErrorMessage (26)  END;
   IF  thisSymbol^.value > 0  THEN  ErrorMessage (27)  END;
   CG ("VECTOR ");	CG (irqN);	CG ("  ");
   CG (token);		CG ("");
   GetSymbol
END isIRQ;
   
It's all rather straightforward. When the IRQ Procedure is defined, the parser looks if the procedure needs function parameters. If so, an error message is given. IRQ routines run unattended, so if you need to supply extra data, the bomb may already have exploded. Now, that would not put some smile on your face!

For this to work, the PALO code 'VECTOR' was introduced.

PLOV PALO
PROGRAM testIRQ

VARIABLES  a x y z END

PROCEDURE OpenGate

BEGIN
   a := x + y
END OpenGate

PROCEDURE CloseGate

BEGIN
   x := y - a
END CloseGate

IRQ 0 = OpenGate
IRQ 1 = CloseGate

BEGIN
   OpenGate
END testIRQ

No errors found.
      
# PROGRAM testIRQ

VARIABLE	a
VARIABLE	x
VARIABLE	y
VARIABLE	z

# PROCEDURE DECLARATION OF OpenGate
LABEL OpenGate

ADDRESS a
FETCH x
FETCH y
ADD
SAVE

# END OF PROCEDURE OpenGate


# PROCEDURE DECLARATION OF CloseGate
LABEL CloseGate

ADDRESS x
FETCH y
FETCH a
SUBTRACT
SAVE

# END OF PROCEDURE CloseGate


VECTOR 0  OpenGate
VECTOR 1  CloseGate

LABEL MAINLOOP

CALL OpenGate

LABEL EXITMAINLOOP
# Done #
      

Plov017 : INC and DEC

Among the most common functions in small processors are INCREMENT and DECREMENT. Increase (or decrease) a register or a variable by 1. It is worthwhile to have such a function in PLOV as well. Here's how it's done. First we implement it in StatementSequence:

PROCEDURE StatementSequence;

BEGIN
   GetSymbol;
   LOOP
      CG ("");
      IF     findType (token) = Vartype 	THEN  Assignment
      ELSIF  findType (token) = Proctype	THEN  Procedurecall
      ELSIF  Strings.StrEq (token, "IF")  	THEN  isIF
      ELSIF  Strings.StrEq (token, "LOOP")	THEN  isLOOP
      ELSIF  Strings.StrEq (token, "INC")	THEN  isINC
      ELSIF  Strings.StrEq (token, "DEC")	THEN  isDEC
      ELSIF  Strings.StrEq (token, "RETURN")	THEN  isRETURN
      ELSIF  Strings.StrEq (token, "ELSE")	THEN  RETURN
      END
   END
END StatementSequence;
   
The functions are coded as follows:
PROCEDURE isINC;

BEGIN
   GetSymbol;
   IF  findType (token) # Vartype  THEN  ErrorMessage (28)  END;
   CG ("INCREMENT  ");
   IF  weHaveLocals AND (FindLocal (token) = TRUE)  THEN  CG ("LOCAL  ")  END;
   CG (token);		CG ("");
   GetSymbol
END isINC;


PROCEDURE isDEC;

BEGIN
   GetSymbol;
   IF  findType (token) # Vartype  THEN  ErrorMessage (28)  END;
   CG ("DECREMENT  ");
   IF  weHaveLocals AND (FindLocal (token) = TRUE)  THEN  CG ("LOCAL  ")  END;
   CG (token);		CG ("");
   GetSymbol
END isDEC;
   
And it runs like this:

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 SHL 1
    q := q SHR 1
  END
END MULTIPLY


PROCEDURE DIVIDE t n

LOCAL 	w	END

BEGIN
  t := x
  q := 0
  n := y
  WHILE n <= t DO n := n SHL 1 END
  WHILE n > y DO 
    q := q SHL 1
    n := n SHR 1
    IF n <= t THEN 
      t := t - n
      INC q
    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

IRQ 1 = Gcd

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

No errors found.
      
# PROGRAM test26

VARIABLE	x
VARIABLE	y
VARIABLE	z
VARIABLE	q
VARIABLE	r

# PROCEDURE DECLARATION OF MULTIPLY
LABEL MULTIPLY
PARAMETER p
PARAMETER q

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

LABEL IF-00
LABEL XIF-0

ADDRESS LOCAL p
FETCH LOCAL p
STORE	1
LEFTSHIFT
SAVE

ADDRESS LOCAL q
FETCH LOCAL q
STORE	1
RIGHTSHIFT
SAVE

GOTO WHILE-0
LABEL XWHILE-0

RELEASE 2
# END OF PROCEDURE MULTIPLY


# PROCEDURE DECLARATION OF DIVIDE
LABEL DIVIDE
PARAMETER t
PARAMETER n
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
STORE	1
LEFTSHIFT
SAVE

GOTO WHILE-1
LABEL XWHILE-1

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

ADDRESS q
FETCH q
STORE	1
LEFTSHIFT
SAVE

ADDRESS LOCAL n
FETCH LOCAL n
STORE	1
RIGHTSHIFT
SAVE

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

ADDRESS LOCAL t
FETCH LOCAL t
FETCH LOCAL n
SUBTRACT
SAVE

INCREMENT  q

LABEL IF-10
LABEL XIF-1

GOTO WHILE-2
LABEL XWHILE-2

RELEASE 3
# END OF PROCEDURE DIVIDE


# PROCEDURE DECLARATION OF Gcd
LABEL Gcd
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

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

LABEL IF-30
LABEL XIF-3

GOTO WHILE-3
LABEL XWHILE-3

ADDRESS z
FETCH LOCAL f
SAVE

RELEASE 2
# END OF PROCEDURE Gcd


VECTOR 1  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 #
      

Plov017 : PORT

Microcontrollers need to control ports. They have lots of them. 32 I/O pins for a simple microcontroller are definitely no exception. So it is good to have a command for reading and writing to/from these pins. So I invented the PORT command. PORT is also part of StatementSequence.

PROCEDURE isPORT;

BEGIN
   GetSymbol;
   IF  Strings.StrEq (token, "WRITE")  THEN
      GetSymbol;
      Expression;
      IF  NOT Strings.StrEq (token, "TO")  THEN  ErrorMessage (30)  END;
      GetSymbol;
      Expression;
      CG ("OUTPORT");		CG ("")
   ELSIF  Strings.StrEq (token, "READ")   THEN
      GetSymbol;
      IF  findType (token) # Vartype  THEN
	 ErrorMessage (32)
      ELSE
	 CG ("ADDRESS ");	CG (token);	CG ("")
      END;
      GetSymbol;
      IF  NOT Strings.StrEq (token, "FROM")	THEN  ErrorMessage (31)  END;
      GetSymbol;
      Expression;
      CG ("INPORT");		CG ("")
   ELSE
      ErrorMessage (29);
      Skip2LF
   END
END isPORT;
   
The syntax is such that you need not remember which value is first: the port address or the variable.

No errors Two errors
PROGRAM test30

CONSTANTS  Ser0 = 101
	   Ser1 = 105
	   DTR0 = 102
	   DTR1 = 118
END

VARIABLES  a b cc ddd  END

BEGIN
   PORT READ a FROM Ser0
   PORT READ a FROM 1
   PORT READ a FROM ddd
   PORT WRITE 21 TO Ser1
   PORT WRITE ddd TO 200 . 7
   PORT WRITE DTR0 TO b
END test30

No errors found.
      
PROGRAM test30

CONSTANTS  Ser0 = 101
           Ser1 = 105
	   DTR0 = 102
	   DTR1 = 118
END
				 
VARIABLES  a b cc ddd  END
				 
BEGIN
   PORT READ a FROM Ser0
   PORT WRITE 21 TO Ser1
   PORT READ DTR0
@@  -- Only variable allowed in line    14
	FROM ddd

   PORT WRITE ddd TO 200 . 7
   PORT READ 1
@@  -- Only variable allowed in line    16
	FROM 1200 + 1
   PORT WRITE DTR0 TO b
END test30
						   
2 errors found.
      

Page created on 21 September 2008 and

Page equipped with FroogleBuster technology