Sie sind auf Seite 1von 26

Than Lwin Aung PLSims tlaung@gmail.

com

PLSims
Introduction
PLSims (short for programmable logic simulators) is an interpreter which uses “Stack” to
provide a high-level, yet simple instruction set for a simple virtual machine. I previously wrote it
in VB for an educational purpose, and now I am re-writing it in C#. Although I am kind of too
lazy to make a proper documentation for the code, I think I should write some theories I have
used and the problems I have faced.

Stack and Recursive Functions


Nowadays, every computer’s architecture provides a data structure called “Stack” for
programmers. The primary purpose of stack is to maintain the local variables between procedure
calls. However, another advantage of stack is that we can build Stack Machine to execute
instructions by using stack.

Before going into what is Stack Machine, I think we should look into the so-called recursive
functions. The recursive functions are, in fact, widely used in Mathematics, Science and Logic.
We might probably use recursive functions in our everyday language without noticing it much.
Actually, a recursive function follows two simple rules: it must have an initial condition(s) and
its next state(s) depends on its previous state(s). Mathematically:

F (0) = A

F (n) = F (n-1) + G (n), where G (n) is an input function.

Those who are familiar with Calculus will probably notice that the equations are similar to initial
value problems. Yes, you are correct. In fact, recursive functions, which are also known as
recurrence relations, are used to model the linear dynamical systems, which can be modeled with
initial conditions and state equations.

One good thing about recursive functions is as long as we know the initial conditions and state
equations; we can easily calculate and predict the behavior of the system in the future. However,
in order to realize the recursive functions, there must be some kind of memory to store the past
states. Now, we can get some glimpse of recursive functions. Ok. Let’s extend the ideas a little
bit. How about languages? Well, it is also defined recursively? Am I right? The initial conditions
are letters and numbers. We define the rules of combining different letters to form meaningful
words, and meaningful sentences, paragraphs and so on.

What I have said so far is in one direction – the forward direction: from initial state to the final
state. How about the reverse direction - from final state to the initial state? Yes, it is possible, if
we know the initial conditions, the state equations and the final conditions and if we can use the
“Stack”.
1
Than Lwin Aung PLSims tlaung@gmail.com

In fact, we can consider “Stack” as the storage of our past states. Say suppose, you are a college
student, and then your stack would be like: birth, elementary school, secondary school. We just
need to know your initial condition, state transitions and final condition, and we can figure out
the rest. We can also consider stack as an open-top water tank. We fill the water from the top and
use the water from the top as well.

Probably, I think the most widely used recursive functions to give as examples are Factorial and
the Fibonacci functions.

For Factorial function:

F (0) = 1

F (n) = F (n-1) * n

For Fibonacci function:

F (0) = 0

F (1) = 1

F (n) = F (n-1) + F (n-2)

As we can see, both functions must have initial conditions and state equations which define the
change from one state to another. Ok, let’s compute some factorial by using stack and the
recursive function. Say suppose we want to calculate 4!

4! = F (4) = F (3) * 4;

We don’t know F (3), so let’s push F (4) on the stack

3! = F (3) = F (2) * 3;

2! = F (2) = F (1) * 2;

1! = F (1) = F (0) * 1;

0! = F (0) = 1;

Stack
F (1)
F (2)
F( 3)
F (4)

2
Than Lwin Aung PLSims tlaung@gmail.com

Now we know F (0) is 1.

Let’s pop F (1) from the stack and compute F (2). Then compute F (3) and F (4). As from this
example, we can see that we use stack to store the intermediate results before we reach to the
final result. Let us talk about how to evaluate mathematical expressions (formulas) by using
stack.

Expressions
Generally, expressions can be divided into 3 main groups: mathematical, logical and relational
expressions. For example, 4 + 5 is a mathematical expression, and 6 > 5 is a relational
expression.

Mathematical expressions involve mathematical operators such as addition, subtraction,


multiplication and division. Logical expressions use logical operators such as AND, OR, NOT
and relational expressions use relational operators like Greater Than, Less Than, Equal To etc. In
fact, it is quite common to use both logical and relational operators in an expression.

Also operators can be either unary or binary operators. Unary operators are the operators which
require only one operand. For example unary minus and mathematical functions are unary
operators. In – (343) and Sin (3.4), both “-“and “Sin” are unary operators. Binary operators are
the operators which require two operands. For example, plus +, minus - , time * and divide /
operators are the binary operators.

In addition, the order of evaluating the operations (rules of precedence) is also important. In fact,
unary operators have the highest precedence, which means that they have to be calculated first.
For binary operators, the exponent ^ has the highest precedence. Multiplication and Division has
the second highest, and Addition and Subtraction has the lowest precedence. If the two operators
have the same precedence, they will be calculated from left to right.

Statements
Actually, programming languages are made up of statements, such as if-statement, while-
statement and assignment statement. Let us start with the simplest form of statement – an
assignment statement.

X: = 5; It is an assignment statement, which instructs the computer to store integer value 5 in


variable x. More examples:

X: = 4 + 6;

X: = (4 >1) and (3 <2);

X: = 4 > 5;

3
Than Lwin Aung PLSims tlaung@gmail.com

Therefore, assignment statements are the fundamental statements in order for an interpreter to
evaluate and calculate the result.

Prefix, Infix and Postfix


Since elementary school, the notation to represent expressions is known as in-fix notation. For
example:

X: = (3 + 6) * (3 -4);

In the early 1920s, a Polish logician, Jan Lukasiewicz, invented a special notation for
representing the expressions in a different way, known as pre-fix (Polish Notation). For
example, the above expression can be re-written in pre-fix as:

+ 4 6 -3 4 *:= x

In pre-fix notation, operators usually come before the operands.

Also, the expression can be re-written as post-fix notation (Reverse Polish Notation) as follows:

3 6 + 3 4 - * x: =

In post-fix notation, operators usually come after the operands.

The reason why both pre-fix and post-fix notations have become famous is that for computers
(interpreters and virtual machines alike), they are easier to evaluate and calculate the expressions
although it is difficult for humans to understand.

Suppose the computer reads the following expression:

X := Sin (3.4) * 3 + 1.5; from left to right, and parse the expression into appropriate
identifiers and symbols, we will get:

Identifiers and
Symbols
X
:=
Sin
(
3.4
)
*
3
+
1.5
;

4
Than Lwin Aung PLSims tlaung@gmail.com

To make it clear, we can actually build the binary tree called expression tree for our assignment
expression.

:=

X
+

* 1.5

3
Sin

3.4

When we build the expression tree, we first look for the lowest precedence operator. In our case,
it is the “:=”. Then we look for the second lowest precedence operator, and then we look for third
lowest precedence operator and finally the highest precedence operator.

In fact, conversion from infix notation to post-fix notation can be done as follow: First, let us
define the rules of precedence. Then, by using stack, we can transform from Infix Notation to
Postfix Notation.

Private Function PRECEDENCE(Optr As String) As Integer

If IsUnary(Optr) Then
PRECEDENCE = 9
ElseIf (Optr = Chr(DL_PW)) Then
PRECEDENCE = 8
ElseIf ((Optr = Chr(DL_MU)) Or (Optr = Chr(DL_DI))) Then
PRECEDENCE = 7
ElseIf (Optr = Chr(DL_MD)) Then
PRECEDENCE = 6
ElseIf ((Optr = Chr(DL_PL)) Or (Optr = Chr(DL_MI))) Then
PRECEDENCE = 5
ElseIf IsRelational(Optr) Then
PRECEDENCE = 4
ElseIf IsLogical(Optr) Then
PRECEDENCE = 3
ElseIf IsAssignment(Optr) Then
PRECEDENCE = 2
ElseIf IsSeperator(Optr) Then
PRECEDENCE = 1
Else

5
Than Lwin Aung PLSims tlaung@gmail.com

PRECEDENCE = 0
End If

End Function

Public Sub POST_FIX(BEG_LX_INDEX As Integer)

Dim PL_STACK() As String

Dim PTR As Integer


Dim Index As Integer

Dim Opcode As String

POX_END = POX_START - 1

PTR = 1
ReDim Preserve PL_STACK(PTR)

PL_STACK(PTR) = Chr(DL_OB)

LX_INDEX = LX_INDEX + 1
ReDim Preserve LEXICONS(LX_INDEX)

LEXICONS(LX_INDEX) = Chr(DL_CB)

For Index = BEG_LX_INDEX To LX_INDEX


Opcode = LEXICONS(Index)

If IsOBracket(Opcode) Or IsFunction(Opcode) Or _
IsProcedure(Opcode) Or IsUsrDef(Opcode) Or _
IsUnary(Opcode) Then

PTR = PTR + 1

ReDim Preserve PL_STACK(PTR)

PL_STACK(PTR) = Opcode

ElseIf IsOperators(Opcode) Then

Dim PreOpcode As Integer


Dim PreStack As Integer

PreOpcode = PRECEDENCE(Opcode)
PreStack = PRECEDENCE(PL_STACK(PTR))

Do While (PreStack >= PreOpcode)

POX_END = POX_END + 1

ReDim Preserve POX(POX_END)


POX(POX_END) = PL_STACK(PTR)

6
Than Lwin Aung PLSims tlaung@gmail.com

PTR = PTR - 1
ReDim Preserve PL_STACK(PTR)

PreStack = PRECEDENCE(PL_STACK(PTR))

Loop

PTR = PTR + 1

ReDim Preserve PL_STACK(PTR)


PL_STACK(PTR) = Opcode

ElseIf IsCBracket(Opcode) Then

Do While Not (IsOBracket(PL_STACK(PTR)))

POX_END = POX_END + 1
ReDim Preserve POX(POX_END)

POX(POX_END) = PL_STACK(PTR)

PTR = PTR - 1
ReDim Preserve PL_STACK(PTR)

Loop

If (PTR > 1) Then

PTR = PTR - 1
ReDim Preserve PL_STACK(PTR)

End If

If IsFunction(PL_STACK(PTR)) Or _
IsProcedure(PL_STACK(PTR)) Or _
IsUsrDef(PL_STACK(PTR)) Then

POX_END = POX_END + 1
ReDim Preserve POX(POX_END)

POX(POX_END) = PL_STACK(PTR)

PTR = PTR - 1
ReDim Preserve PL_STACK(PTR)

End If

Else
POX_END = POX_END + 1
ReDim Preserve POX(POX_END)

POX(POX_END) = Opcode

End If
Next

End Sub

7
Than Lwin Aung PLSims tlaung@gmail.com

In PLSims, there is a Postfix module which converts the input infix expressions to the postfix
expressions.

The organization of PLSims Simulator


In fact, PLSims provide simple, high-level programming language to be interpreted on the Simulator
(Virtual Machine.) So, I think it is better to start from the organizations of the simulator.

The following diagram will show the organization of PLSims. A set of instructions (program statements)
are first loaded into Program Array. SYS_NEXT_ADDR holds the address of the next program
statement. Actually, the address inside SYS_NEXT_ADDR will change according to branching and
looping. Instruction Register always stores the instruction pointed by SYS_NEXT_ADDR. The
instruction in IR is interpreted and parsed into Lexicons and stored in Lexicons Array. If the current
instruction involves Expressions is then converted to Post-fix notation and stored in Post-fix Array for
further execution. VAR (Global Variable Array) stores the global variables. DEF (Function Address
Array) stores the address of the functions (sub routines), so during the execution, program can jump to
one function to another. OPR stores the actual parameters in the functions so that parameters can be
passed by value between procedure calls. LVR (Local Variable Stack) stores the local variables declared
in the functions (sub routines).

8
Than Lwin Aung PLSims tlaung@gmail.com

Program Array VAR DEF


SYS_NEXT_ADDR
(Global Variable Array) (Function Address
Array)

OPR
Operand Base Pointer
(Operand Array)
Instruction Register
Operand Stack Pointer

Lexicon

(Tokens Array) Operand Pointer


Array
POX POX_Start Pointer

(Postfix Array) POX Pointer

POX_End Pointer

LVR
Control Start Pointer
 Load (Local Variable Stack)
o Load the program to Program Array
 Fetch
Stack Pointer
o Fetch the instruction pointed by
SYS_NEXT_ADDR to IR
 Interpret
End Pointer
o Interpret the instruction in IR, and
determine the instruction type
 Execute
Local Variable Index
o Execute the instruction according the
instruction type Array
 Exit
o Exit the program

9
Than Lwin Aung PLSims tlaung@gmail.com

Scanning, Parsing and Interpreting


Generally, a scanner is a DFA (Deterministic Finite Automaton) which follows a particular RE
(Regular Expression) to read character by character from an input string to form acceptable
words. However, a parser follows a particular CFG (Context Free Grammar) to read word by
word from a statement to determine if the input statement is correct according to the pre-defined
grammar.

In PLSims, the scanning and parsing are performed by the Interpretation module. The current
instruction (programming statement) is fed into Interpretation Module, and then it outputs the
type of instruction and parsed instruction to be executed.

The following procedure acts as a scanner to form acceptable tokens.

Private Sub TOKENIZE(ByVal EXP As String)

Dim Index As Integer


Dim POS As Integer
Dim chr As String
Dim ST As String

TK_INDEX = 0

For Index = 1 To Len(EXP)

chr = Mid(EXP, Index, 1)

If IsWhiteSpace(chr) Then

If (ST <> vbNullString) Then

TK_INDEX = TK_INDEX + 1
ReDim Preserve TOKENS(TK_INDEX)

TOKENS(TK_INDEX) = ST
End If

ST = vbNullString

ElseIf IsDelimiter(chr) Then

If (ST <> vbNullString) Then

TK_INDEX = TK_INDEX + 1
ReDim Preserve TOKENS(TK_INDEX)

TOKENS(TK_INDEX) = ST

End If

TK_INDEX = TK_INDEX + 1
ReDim Preserve TOKENS(TK_INDEX)

TOKENS(TK_INDEX) = chr

10
Than Lwin Aung PLSims tlaung@gmail.com

ST = vbNullString

ElseIf IsString(chr) Then

If (ST <> vbNullString) Then

TK_INDEX = TK_INDEX + 1
ReDim Preserve TOKENS(TK_INDEX)

TOKENS(TK_INDEX) = ST

End If

POS = InStr(Index + 1, EXP, chr(DL_ST))


ST = chr + Mid$(EXP, Index + 1, POS - Index)

TK_INDEX = TK_INDEX + 1
ReDim Preserve TOKENS(TK_INDEX)

TOKENS(TK_INDEX) = ST

ST = vbNullString

Index = POS

ElseIf IsComment(chr) Then

If (ST <> vbNullString) Then

TK_INDEX = TK_INDEX + 1
ReDim Preserve TOKENS(TK_INDEX)

TOKENS(TK_INDEX) = ST

End If

POS = InStr(Index + 1, EXP, chr(DL_CM))

ST = vbNullString

Index = POS + 1
Else
ST = ST + chr
End If

Next Index

If (ST <> vbNullString) Then

TK_INDEX = TK_INDEX + 1
ReDim Preserve TOKENS(TK_INDEX)

TOKENS(TK_INDEX) = ST
End If

End Sub

11
Than Lwin Aung PLSims tlaung@gmail.com

The following procedure further check and parsed to form acceptable lexicons, the fundamental
keywords, identifiers, symbols and operators.

Private Sub LEXICAL_ANALYSIS()

Dim Index As Long


Dim Lexicon As String
Dim Prev_Lexicon As String
Dim Next_Lexicon As String

LX_INDEX = 0

For Index = 1 To TK_INDEX


Lexicon = TOKENS(Index)

If (Index < TK_INDEX) Then


Next_Lexicon = TOKENS(Index + 1)
End If

If (Index > 1) Then


Prev_Lexicon = TOKENS(Index - 1)
End If

If (IsOperators(Lexicon + Next_Lexicon)) Then


Lexicon = Lexicon + Next_Lexicon

Index = Index + 1

ElseIf (Lexicon = Chr(DL_MI)) Then

If (IsArithmetic(Prev_Lexicon) Or _
IsRelational(Prev_Lexicon) Or _
IsOBracket(Prev_Lexicon)) Then

Lexicon = Chr(DL_UM)
End If

ElseIf (IsEquStr(Lexicon, KW_END)) Then

If (IsEquStr(Next_Lexicon, KW_PROC) Or _
IsEquStr(Next_Lexicon, KW_FUNC) Or _
IsEquStr(Next_Lexicon, KW_IF) Or _
IsEquStr(Next_Lexicon, KW_PROG) Or _
IsEquStr(Next_Lexicon, KW_WHILE)) Then

Lexicon = Lexicon + Next_Lexicon

Index = Index + 1

End If

ElseIf (IsEquStr(Lexicon, KW_PROC)) Then

If (IsEquStr(Next_Lexicon, KW_MAIN)) Then


Lexicon = Lexicon + Next_Lexicon

12
Than Lwin Aung PLSims tlaung@gmail.com

Index = Index + 1
End If

End If

LX_INDEX = LX_INDEX + 1
ReDim Preserve LEXICONS(LX_INDEX)

LEXICONS(LX_INDEX) = Lexicon

Next Index

TK_INDEX = 0

ReDim TOKENS(1)

End Sub

Finally, the following procedure determines the type of instructions by analyzing the keywords,
identifiers and symbols.

Private Function SEMANTIC_ANALYSIS() As Integer

Dim Index As Long


Dim Lexicon As String
Dim Next_Lexicon As String
Dim Prev_Lexicon As String

For Index = 1 To LX_INDEX


Lexicon = LEXICONS(Index)

If (Index < LX_INDEX) Then


Next_Lexicon = LEXICONS(Index + 1)
End If

If (Index > 1) Then


Prev_Lexicon = LEXICONS(Index - 1)
End If

If (SYS_SCOPE = -2) Then

If (IsEquStr(Lexicon, KW_PROG)) Then


SEMANTIC_ANALYSIS = INSTR_PROG
Else
SEMANTIC_ANALYSIS = INSTR_NOP
End If

Exit Function

ElseIf (SYS_SCOPE = -1) Then

If (IsEquStr(Lexicon, KW_NUMBER) Or _
IsEquStr(Lexicon, KW_BOOLEAN) Or _
IsEquStr(Lexicon, KW_STRING)) Then

13
Than Lwin Aung PLSims tlaung@gmail.com

If (IsEquStr(Next_Lexicon, KW_FUNC)) Then


SEMANTIC_ANALYSIS = INSTR_FUNC_DEF
Else
SEMANTIC_ANALYSIS = INSTR_GLOBAL_DEF
End If

Exit Function

ElseIf (IsEquStr(Lexicon, KW_PROC)) Then


SEMANTIC_ANALYSIS = INSTR_PROC_DEF

Exit Function
ElseIf (IsEquStr(Lexicon, KW_PROC_MAIN)) Then
SEMANTIC_ANALYSIS = INSTR_PROC_MAIN

Exit Function
ElseIf (IsEquStr(Lexicon, KW_END_PROC)) Then
SEMANTIC_ANALYSIS = INSTR_END_PROC

Exit Function
ElseIf (IsEquStr(Lexicon, KW_END_FUNC)) Then
SEMANTIC_ANALYSIS = INSTR_END_FUNC

Exit Function

ElseIf (IsEquStr(Lexicon, KW_END_PROG)) Then


SEMANTIC_ANALYSIS = INSTR_END_PROG

Exit Function
Else
SEMANTIC_ANALYSIS = INSTR_NOP

Exit Function
End If

ElseIf (SYS_SCOPE > -1) Then

If (IsEquStr(Lexicon, KW_NUMBER) Or _
IsEquStr(Lexicon, KW_BOOLEAN) Or _
IsEquStr(Lexicon, KW_STRING)) Then

If (IsEquStr(Next_Lexicon, KW_FUNC)) Then


SEMANTIC_ANALYSIS = INSTR_FUNC_CALL
Else
SEMANTIC_ANALYSIS = INSTR_LOCAL_DEF
End If

Exit Function

ElseIf (IsEquStr(Lexicon, KW_PROC)) Then


SEMANTIC_ANALYSIS = INSTR_PROC_CALL

Exit Function
ElseIf (IsEquStr(Lexicon, KW_END_PROC)) Then
SEMANTIC_ANALYSIS = INSTR_END_PROC_CALL

Exit Function

14
Than Lwin Aung PLSims tlaung@gmail.com

ElseIf (IsEquStr(Lexicon, KW_END_FUNC)) Then


SEMANTIC_ANALYSIS = INSTR_END_FUNC_CALL

Exit Function
ElseIf (IsEquStr(Lexicon, KW_IF)) Then
SEMANTIC_ANALYSIS = INSTR_IF

Exit Function
ElseIf (IsEquStr(Lexicon, KW_THEN)) Then
SEMANTIC_ANALYSIS = INSTR_THEN

Exit Function
ElseIf (IsEquStr(Lexicon, KW_ELSE)) Then
SEMANTIC_ANALYSIS = INSTR_ELSE

Exit Function
ElseIf (IsEquStr(Lexicon, KW_END_IF)) Then
SEMANTIC_ANALYSIS = INSTR_END_IF

Exit Function
ElseIf (IsEquStr(Lexicon, KW_WHILE)) Then
SEMANTIC_ANALYSIS = INSTR_WHILE

Exit Function
ElseIf (IsEquStr(Lexicon, KW_END_WHILE)) Then
SEMANTIC_ANALYSIS = INSTR_END_WHILE

Exit Function
ElseIf (IsEquStr(Lexicon, KW_REPEAT)) Then
SEMANTIC_ANALYSIS = INSTR_REPEAT

Exit Function
ElseIf (IsEquStr(Lexicon, KW_UNTIL)) Then
SEMANTIC_ANALYSIS = INSTR_UNTIL

Exit Function
ElseIf (IsEquStr(Lexicon, KW_RETURN)) Then
SEMANTIC_ANALYSIS = INSTR_FUNC_RTR

Exit Function
Else
SEMANTIC_ANALYSIS = INSTR_EXP

Exit Function
End If
End If

Next Index

SEMANTIC_ANALYSIS = INSTR_NOP

End Function

15
Than Lwin Aung PLSims tlaung@gmail.com

The followings define the types of instruction and keywords:

'Instruction Type Constants


Public Const INSTR_PROG = 0
Public Const INSTR_END_PROG = 1
Public Const INSTR_GLOBAL_DEF = 2
Public Const INSTR_LOCAL_DEF = 3
Public Const INSTR_PROC_DEF = 4
Public Const INSTR_FUNC_DEF = 5
Public Const INSTR_PROC_CALL = 6
Public Const INSTR_FUNC_CALL = 7
Public Const INSTR_END_PROC_CALL = 8
Public Const INSTR_END_FUNC_CALL = 9
Public Const INSTR_END_PROC = 10
Public Const INSTR_END_FUNC = 11
Public Const INSTR_FUNC_RTR = 12
Public Const INSTR_PROC_MAIN = 13
Public Const INSTR_IF = 14
Public Const INSTR_THEN = 15
Public Const INSTR_ELSE = 16
Public Const INSTR_END_IF = 17
Public Const INSTR_WHILE = 18
Public Const INSTR_END_WHILE = 19
Public Const INSTR_REPEAT = 20
Public Const INSTR_UNTIL = 21
Public Const INSTR_EXP = 22
Public Const INSTR_NOP = 23

'Data Type Constants


Public Const KW_NUMBER = "NUMBER"
Public Const KW_BOOLEAN = "BOOLEAN"
Public Const KW_STRING = "STRING"

'Logical Constants
Public Const KW_AND = "AND"
Public Const KW_OR = "OR"
Public Const KW_NOT = "NOT"
Public Const KW_XOR = "XOR"

'Boolean Constants
Public Const KW_TRUE = "TRUE"
Public Const KW_FALSE = "FALSE"

'Procedure Constants
Public Const KW_PROC = "PROCEDURE"
Public Const KW_FUNC = "FUNCTION"
Public Const KW_PROC_MAIN = "PROCEDUREMAIN"
Public Const KW_RETURN = "RETURN"
Public Const KW_END_PROC = "ENDPROCEDURE"
Public Const KW_END_FUNC = "ENDFUNCTION"

'Sequence Control Constants


Public Const KW_IF = "IF"
Public Const KW_THEN = "THEN"
Public Const KW_ELSE = "ELSE"
Public Const KW_END_IF = "ENDIF"

16
Than Lwin Aung PLSims tlaung@gmail.com

'Iteration Control Constants


Public Const KW_WHILE = "WHILE"
Public Const KW_END_WHILE = "ENDWHILE"
Public Const KW_REPEAT = "REPEAT"
Public Const KW_UNTIL = "UNTIL"

'Termination Constants
Public Const KW_END = "END"

'Program Constants
Public Const KW_PROG = "PROGRAM"
Public Const KW_END_PROG = "ENDPROGRAM"

'Primary Procedure Constants


Public Const KW_MAIN = "MAIN"

Executing
The following will show the sample program instructions to be executed on PLSims:

Program Test

Number Function Add (Number A, Number B)


Return (A + B)
End Function

Procedure Main()

Number A,B

A := 10

B:= Add(A, 34)

End Procedure

End Program

The program instructions are made up of different statements. During fetch, interpret and execute
cycle, each statement is analyzed, interpreted and executed.

Once the instruction type is determined, the instruction is then fed into the Execution Module to
be executed. Actually, executing the instruction is pretty tricky and I had to come up with
different solutions.

17
Than Lwin Aung PLSims tlaung@gmail.com

Executing an instruction, in fact, has to be linked with Memory Management and Program
Address Control as there are instructions for branching, procedure calls, and variable
declarations in addition to simple statements which only involve mathematical, logical and
relational expressions.

In fact, memory management is achieved by building the memory organizations as described in


the organizations of PLSims.

For procedure calls, SYS_NEXT_ADDR has to change accordingly. Therefore, DEF stores the
addresses of all functions in the program. When a particular function or procedure is called from
another function, the simulator looks for the address of the called procedure in DEF and change
the SYS_NEXT_ADD to the address of the called procedure. Also, when parameters are
necessary to pass between procedures calls, the simulator looks for right parameters in the
parameter array to be passed to the called procedure or function.

For variable declaration, there is a global system variable called SYS_SCOPE, which defines the
current scope of the block of instructions. First, SYS_SCOP is initialized as -2. Then, whenever
the current execution enters a new block of instructions, such as procedure, function, while loop,
for loop, repeat-until loop, it is incremented by one. Also, when the current execution leaves the
current block of instruction, it is decremented by one.

Also, when the current instruction involves an expression, it is then converted to Postfix notation
and evaluated the result.

The following code segment is the Execution Procedure, which accepts the current instruction
type and address of the instruction, and executes the instruction and changes the address of the
instruction when necessary.
Public Sub EXECUTE(ByVal INSTR_TYPE As Integer, ByVal CUR_ADDR As Long)

Dim NX_ADDR As Long

Dim N As Integer
Dim Index As Integer

Dim Result As String


Dim EXP As String

Select Case INSTR_TYPE

Case INSTR_PROG

SYS_SCOPE = -1

SYS_ARG_INDEX = 0
SYS_NX_ADDR = 0

SYS_RETURN = False

18
Than Lwin Aung PLSims tlaung@gmail.com

SYS_EXECUTABLE = True

Case INSTR_END_PROG

SYS_SCOPE = -2

Case INSTR_GLOBAL_DEF

If (SYS_EXECUTABLE) Then

If (IsEquStr(LEXICONS(1), KW_NUMBER)) Then


Result = 0
ElseIf (IsEquStr(LEXICONS(1), KW_BOOLEAN)) Then
Result = KW_FALSE
ElseIf (IsEquStr(LEXICONS(1), KW_STRING)) Then
Result = Chr(DL_ST) + Chr(DL_ST)
End If

For Index = 2 To LX_INDEX Step 2

V_ADD(LEXICONS(Index), Result)

Next Index

End If

Case INSTR_LOCAL_DEF

If (SYS_EXECUTABLE) Then

If (IsEquStr(LEXICONS(1), KW_NUMBER)) Then


Result = 0
ElseIf (IsEquStr(LEXICONS(1), KW_BOOLEAN)) Then
Result = KW_FALSE
ElseIf (IsEquStr(LEXICONS(1), KW_STRING)) Then
Result = Chr(DL_ST) + Chr(DL_ST)
End If

For Index = 2 To LX_INDEX Step 2

LV_ADD(LEXICONS(Index), Result)

Next Index

End If

Case INSTR_PROC_DEF

SYS_EXECUTABLE = False

N = 0

For Index = 3 To LX_INDEX

If (IsEquStr(LEXICONS(Index), KW_NUMBER) Or _
IsEquStr(LEXICONS(Index), KW_BOOLEAN) Or _
IsEquStr(LEXICONS(Index), KW_STRING)) Then

19
Than Lwin Aung PLSims tlaung@gmail.com

N = N + 1
End If

Next Index

DF_WRITE(SYS_NULL, LEXICONS(2), N, CUR_ADDR)

Case INSTR_FUNC_DEF

SYS_EXECUTABLE = False

N = 0

For Index = 4 To LX_INDEX

If (IsEquStr(LEXICONS(Index), KW_NUMBER) Or _
IsEquStr(LEXICONS(Index), KW_BOOLEAN) Or _
IsEquStr(LEXICONS(Index), KW_STRING)) Then
N = N + 1
End If

Next Index

DF_WRITE(LEXICONS(1), LEXICONS(3), N, CUR_ADDR)

Case INSTR_PROC_CALL

INC_LC_SCP()

If (SYS_ARG_INDEX > 0) Then

N = 1

For Index = 4 To LX_INDEX Step 3

If (IsEquStr(LEXICONS(Index), KW_NUMBER) And


IsNumeric(SYS_ARGS(N))) Or _
IsEquStr(LEXICONS(Index), KW_BOOLEAN) And
(IsBoolean(SYS_ARGS(N))) Or _
IsEquStr(LEXICONS(Index), KW_STRING) And
(IsString(SYS_ARGS(N)))) Then

LV_ADD(LEXICONS(Index + 1), SYS_ARGS(N))

N = N + 1
End If

Next Index

SYS_ARG_INDEX = 0

End If

Case INSTR_FUNC_CALL

INC_LC_SCP()

20
Than Lwin Aung PLSims tlaung@gmail.com

If (SYS_ARG_INDEX > 0) Then

N = 1

For Index = 5 To LX_INDEX Step 3

If (IsEquStr(LEXICONS(Index), KW_NUMBER) And


(IsNumeric(SYS_ARGS(N))) Or _
IsEquStr(LEXICONS(Index), KW_BOOLEAN) And
(IsBoolean(SYS_ARGS(N))) Or _
IsEquStr(LEXICONS(Index), KW_STRING) And
(IsString(SYS_ARGS(N)))) Then

LV_ADD(LEXICONS(Index + 1), SYS_ARGS(N))

N = N + 1
End If

Next Index

SYS_ARG_INDEX = 0
End If

LV_ADD(SYS_NULL + KW_FUNC + SYS_NULL + CStr(SYS_SCOPE), LEXICONS(1))

Case INSTR_END_PROC_CALL

If (SYS_SCOPE > 0) Then

DEC_LC_SCP()

Result = LV_READ(SYS_NULL + KW_RETURN + SYS_NULL + CStr(SYS_SCOPE))

If (Result <> SYS_NULL) Then

LV_END = LV_END - 1
ReDim Preserve LVR(LV_END)

NX_ADDR = CLng(Result)

SYS_NX_ADDR = NX_ADDR + 1
End If

End If

Case INSTR_END_FUNC_CALL

If (SYS_SCOPE > 0) Then

If (OPR(OPR_BASE - 1) = SYS_NULL) Then


OPR(OPR_BASE - 1) = OPR(OPR_PTR)
End If

DEC_LC_SCP()

Result = LV_READ(SYS_NULL + KW_RETURN + SYS_NULL + CStr(SYS_SCOPE))

21
Than Lwin Aung PLSims tlaung@gmail.com

If (Result <> SYS_NULL) Then

LV_END = LV_END - 1
ReDim Preserve LVR(LV_END)

NX_ADDR = CLng(Result)

SYS_NX_ADDR = NX_ADDR

SYS_RETURN = True
End If

End If

Case INSTR_END_PROC
SYS_EXECUTABLE = True

Case INSTR_END_FUNC
SYS_EXECUTABLE = True

Case INSTR_FUNC_RTR

If (SYS_RETURN) Then
EVALUATE(Result, NX_ADDR, POX_PTR)
SYS_RETURN = False
Else
POST_FIX(2)
EVALUATE(Result, NX_ADDR)
End If

If ((Result = SYS_NULL) And (NX_ADDR <> 0)) Then


SYS_NX_ADDR = NX_ADDR
LV_ADD(SYS_NULL + KW_RETURN + SYS_NULL + CStr(SYS_SCOPE), CStr(CUR_ADDR))

ElseIf (Result <> SYS_NULL) Then

EXP = LV_READ(SYS_NULL + KW_FUNC + SYS_NULL + CStr(SYS_SCOPE))

If ((IsEquStr(EXP, KW_NUMBER) And IsNumeric(Result)) Or _


(IsEquStr(EXP, KW_BOOLEAN) And IsBoolean(Result)) Or _
(IsEquStr(EXP, KW_STRING) And IsString(Result))) Then

OPR_PTR = OPR_PTR + 1
ReDim Preserve OPR(OPR_PTR)

OPR(OPR_PTR) = Result
Else
'Error
End If

End If

Case INSTR_PROC_MAIN

SYS_SCOPE = 0
LV_PTR = 1
LV_END = 1

22
Than Lwin Aung PLSims tlaung@gmail.com

LV_START = 1

POX_START = 1
OPR_BASE = 1

Case INSTR_IF

If (SYS_EXECUTABLE) Then

If (SYS_RETURN) Then
EVALUATE(Result, NX_ADDR, POX_PTR)
SYS_RETURN = False
Else
POST_FIX(2)
EVALUATE(Result, NX_ADDR)
End If

If ((Result = SYS_NULL) And (NX_ADDR <> 0)) Then


SYS_NX_ADDR = NX_ADDR
LV_ADD(SYS_NULL + KW_RETURN + SYS_NULL + CStr(SYS_SCOPE), CStr(CUR_ADDR))

ElseIf (IsBoolean(Result)) Then

INC_BL_SCP()
LV_ADD(SYS_NULL + KW_IF + SYS_NULL + CStr(SYS_SCOPE), Result)

End If
Else
SYS_SCOPE = SYS_SCOPE + 1
End If

Case INSTR_THEN

Result = LV_READ(SYS_NULL + KW_IF + SYS_NULL + CStr(SYS_SCOPE))

If (Result <> SYS_NULL) Then


SYS_EXECUTABLE = CBool(Result)
Else
SYS_EXECUTABLE = False
End If

Case INSTR_ELSE

Result = LV_READ(SYS_NULL + KW_IF + SYS_NULL + CStr(SYS_SCOPE))

If (Result <> SYS_NULL) Then


SYS_EXECUTABLE = Not (CBool(Result))
Else
SYS_EXECUTABLE = False
End If

Case INSTR_END_IF

Result = LV_READ(SYS_NULL + KW_IF + SYS_NULL + CStr(SYS_SCOPE))

If (Result <> SYS_NULL) Then


SYS_EXECUTABLE = True

23
Than Lwin Aung PLSims tlaung@gmail.com

DEC_BL_SCP()
Else
SYS_SCOPE = SYS_SCOPE - 1
End If

Case INSTR_WHILE

If (SYS_EXECUTABLE) Then

If (SYS_RETURN) Then
EVALUATE(Result, NX_ADDR, POX_PTR)
SYS_RETURN = False
Else
POST_FIX(2)
EVALUATE(Result, NX_ADDR)
End If

If ((Result = SYS_NULL) And (NX_ADDR <> 0)) Then


SYS_NX_ADDR = NX_ADDR
LV_ADD(SYS_NULL + KW_RETURN + SYS_NULL + CStr(SYS_SCOPE), CStr(CUR_ADDR))

ElseIf (IsBoolean(Result)) Then

INC_BL_SCP()

If (CBool(Result)) Then

LV_ADD(SYS_NULL + KW_WHILE + SYS_NULL + CStr(SYS_SCOPE), CStr(CUR_ADDR))


SYS_EXECUTABLE = True
Else

LV_ADD(SYS_NULL + KW_WHILE + SYS_NULL + CStr(SYS_SCOPE), 0)


SYS_EXECUTABLE = False
End If
End If
Else
SYS_SCOPE = SYS_SCOPE + 1
End If

Case INSTR_END_WHILE

Result = LV_READ(SYS_NULL + KW_WHILE + SYS_NULL + CStr(SYS_SCOPE))

If (Result <> SYS_NULL) Then

SYS_EXECUTABLE = True
SYS_NX_ADDR = CLng(Result)
DEC_BL_SCP()
Else
SYS_SCOPE = SYS_SCOPE - 1
End If

Case INSTR_REPEAT

If (SYS_EXECUTABLE) Then

INC_BL_SCP()

24
Than Lwin Aung PLSims tlaung@gmail.com

LV_ADD(SYS_NULL + KW_REPEAT + SYS_NULL + CStr(SYS_SCOPE), CStr(CUR_ADDR))


Else
SYS_SCOPE = SYS_SCOPE + 1
End If

Case INSTR_UNTIL

Result = LV_READ(SYS_NULL + KW_REPEAT + SYS_NULL + CStr(SYS_SCOPE))

If (Result <> SYS_NULL) Then

If (SYS_RETURN) Then
EVALUATE(EXP, NX_ADDR, POX_PTR)
SYS_RETURN = False
Else
POST_FIX(2)
EVALUATE(EXP, NX_ADDR)
End If

If ((EXP = SYS_NULL) And (NX_ADDR <> 0)) Then


SYS_NX_ADDR = NX_ADDR
LV_ADD(SYS_NULL + KW_RETURN + SYS_NULL + CStr(SYS_SCOPE), CStr(CUR_ADDR))

ElseIf (Not (CBool(EXP))) Then


SYS_NX_ADDR = CLng(Result)
Else
SYS_NX_ADDR = 0
End If

SYS_EXECUTABLE = True
DEC_BL_SCP()
Else
SYS_SCOPE = SYS_SCOPE - 1
End If

Case INSTR_EXP

If (SYS_EXECUTABLE) Then

If (SYS_RETURN) Then
EVALUATE(Result, NX_ADDR, POX_PTR)
SYS_RETURN = False
Else
POST_FIX(1)
EVALUATE(Result, NX_ADDR)
End If

If ((Result = SYS_NULL) And (NX_ADDR <> 0)) Then


SYS_NX_ADDR = NX_ADDR

LV_ADD(SYS_NULL + KW_RETURN + SYS_NULL + CStr(SYS_SCOPE), CStr(CUR_ADDR))

End If

End If

Case Else

25
Than Lwin Aung PLSims tlaung@gmail.com

SYS_NX_ADDR = 0

End Select

End Sub

Fetch- Interpret-Execute Cycle


After the program is loaded, the simulator fetches, interprets and executes the instructions until
the program is complete.

The following code segment shows the FIE Cycle of PLSims.

Private Sub INSTR_CYCLE()

Dim IR As String 'Instruction Register


Dim PAR As Long 'Program Address Register
Dim INST As Integer

PAR = 1
SYS_SCOPE = -2

While (PAR <= PR_INDEX)

IR = PRO(PAR)

INST = INTERPRET(IR)

EXECUTE(INST, PAR)

If (SYS_NX_ADDR = 0) Then
PAR = PAR + 1
Else
PAR = SYS_NX_ADDR
SYS_NX_ADDR = 0
End If
End While

End Sub

Further Extensions and Problems


First of all, PLSims does explicitly not use the CFG (Context Free Grammar) instead it exploits
the power of Stack and Postfix Notation to interpret and execute the instructions. So, it would be
a nice idea to re-implement PLSims with CFG and then compare the performance and
throughput.

Secondly, PLSims does not have a debugger and it cannot be used for debugging purpose. And
finally, PLSims only provides 3 intrinsic data types: Number, Boolean and String. So, it will be a
good idea to add ADT (Abstract Data Types) and other data structures, such as Array, Record
etc.

26

Das könnte Ihnen auch gefallen