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