Examples of parsing  Nut program to N-code


First, the parser converts the input source program into an intermediate form, called intermediate code.  In our language, Nut, its intermediate code is N-code.  This N-code follows closely to the source.  What that can be done at compile time will be done to save the effort at the run-time.  This is a reasonable "strategy" because some program, after it has been compiled, will be used many many times.  

N-code is explained in details in my textbook chapter 2, pages 41-45.  Here is the summary of its instruction set:
-----------------------
2.11 N-code instruction set

N-code instruction set is a definition for the internal representation of Nut language. The instruction follows from the Nut language pluses some extra
instructions to implement precise operational semantic of Nut language. The instruction set is divided into four groups: control, value, arithmetic and system. Each instruction has the form of an atom with 7-bit opcode and 24-bit argument.

opcode encoding

xIF 1   xWHILE 2  xDO 3     --       xNEW 5
xADD 6  xSUB 7    xMUL 8    xDIV 9   xEQ 10
xLT 11  xGT 12    xCALL 13  xGET 14  xPUT 15
xLIT 16 xLDX 17   xSTX 18   xFUN 19  xSYS 20
--      --        --        --       xLD 25
xST 26  xLDY 27   xSTY 28   --       --
--      xSTR 32   xBAND 33  xSHR 34  xSHL 35

Totally there are 27 instructions in N-code instruction set. Only valueinstructions have arguments, denoted by “op.arg”. “fun” has special arguments (to be explained later). “call” has a pointer to its body of a function (the N-code) as its argument.
-----------------------

Note:  Please note that N-code don't have <= >= and or not.  To use these operators, they must be defined:
(def != (a b) () (if (= a b) 0 1))
(def >= (a b) () (if (< a b) 0 1))
(def <= (a b) () (if (> a b) 0 1))
(def and (a b) ()(if a b 0))
(def or (a b) () (if a 1 b))
(def not a () (if a 0 1))

xFUN has two arguments encoded into its argument field:  fun.a.s where a is the arity of the function, s is the size of its activation record, in terms of the
number of local variables of this function, that includes its arguments and its local variables.

Here are the examples of parsing some Nut programs into N-code.

[(def sq x () (* x x ))] in file "sq.txt"

e:>nut32 < sq.txt
sq
(fun.1.1 (* get.1 get.1 ))

[(def assign () (a b) (set a (+ b 1)))]  in file "assign.txt"

e:>nut32 < assign.txt
assign
(fun.0.2 (put.1 (+ get.2 lit.1 )))

[
(def parseControl () (i j k)
  (do
    (while (< i 10)
       (set i (+ i 1)))
    (if (= j 2)
       (set k 20)
       ; else
       (set k 10))))

] in file "control.txt"

e:>nut32 < control.txt
parseControl
(fun.0.3 (do
(while (< get.1 lit.10 )(put.1 (+ get.1 lit.1 )))
(if (= get.2 lit.2)(put.3 lit.20 )(put.3 lit.10 ))))

[
(let arrayA g)
(def simple () (a b)
  (do
    (set g 1000)                ; global
    (set a g)
    (set b 11)
    (set arrayA (new 10))
    (setv arrayA 1 20)          ; arrayA[1] = 20
    (set b (vec arrayA 1))))  ; b = arrayA[1]
]  in file "global.txt"

e:>nut32 < global.txt
arrayA
g
simple
(fun.0.2 (do (st.1 lit.1000 )
(put.1 ld.1 )(put.2 lit.11 )
(st.0 (new lit.10 ))
(sty.0 lit.1 lit.20 )
(put.2 (ldy.0 lit.1 ))))

Note: local variable names are changed into 1..n and global variable names are changed to a static address (0..m) by the compiler.  The actual
address will be determined when the real machine code is generated.

End

last update 30 June 2009