Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Mini-Interp

43 views
Skip to first unread message

s_dub...@munged.microcosmotalk.com

unread,
Oct 15, 2009, 12:07:09 PM10/15/09
to

In the thread "Mini--x86" Rod P. posted a ddj ref to a mini
interpreter, and I had alook at it... the
article is well worth a read and speaks well of assembler.

It seems to me to be an example of threaded code, Forth like in a way,
anyway I did a nasm syntax conversion and afew kludges to get the
animation to work, here's the nasm source for a .com file for a dos
box, or XP's cmd.exe...

Enjoy,

Steve

;;--------------------------------------------------------60
;; File: MINITERP.NSM
;; modified for NASM syntax. s_dub...@yahoo.com 14OCT2009
;; -f bin -l MINITERP.LST -o MINITERP.COM MINITERP.NSM
;; Note: has some int21h calls, use a dos box or cmd.exe
;; Ref: http://www.ddj.com/184408206?pgno=3
;
; This program demonstrates the use of a mini-interpreter to produce
; code that is compact, flexible and easy to modify. The mini-
; program draws and labels a maze and animates an arrow through
; the maze.
;
; Note: This program must be run in 80-column text mode.
;
; By Dan Illowsky & Michael Abrash 2/18/89
; Public Domain
;
;Stak segment para stack 'stack' ;allocate stack space
; db 200h dup (?)
;Stak ends
;
;_TEXT segment para public 'code'
; assume cs:_TEXT, ds:_TEXT
;
;
; Overall animation delay. Selected for an AT: set higher to slow
; animation more for faster computers, lower to slow animation less
; for slower computers.
;
DELAY_COUNT equ 0FFFFh
;
; Equates for mini-language commands, used in the data
; sequences that define mini-programs. The values of these
; equates are used by Interp as indexes into the jump table
; Function_Table in order to call the corresponding subroutines.
;
; Lines starting with ">>" describe the parameters that must
; follow the various commands.
;
Done# equ 0 ; Ends program or subprogram.
; >>No parms.
SubProg# equ 1 ; Executes a subprogram.
; >>Parm is offset of subprogram.
SetXY# equ 2 ; Sets the cursor location (the location at
; which to output the next character).
; >>Parms are X then Y coordinates (both
; bytes).
SetXYInc# equ 3 ; Sets the distance to move after displaying
; each character.
; >>Parms are X then Y amount to move after
; displaying character (both bytes).
SetX# equ 4 ; Sets the X part of the cursor location.
; >>Parm is the X coordinate (byte).
SetY# equ 5 ; Sets the Y part of the cursor location.
; >>Parm is the Y coordinate (byte).
SetXInc# equ 6 ; Sets the X part of the amount to move after
; displaying each character.
; >>Parm is the X amount to move after
; character is displayed (byte).
SetYInc# equ 7 ; Sets the Y part of the amount to move after
; displaying each character.
; >>Parm is the Y amount to move after
; character is displayed (byte).
SetAtt# equ 8 ; Sets the screen attribute of characters to
; be displayed.
; >>Parm is attribute (byte).
TextUp# equ 9 ; Displays a string on the screen.
; >>Parm is an ASCII string of bytes,
; which must be terminated by an EndO# byte.
RepChar# equ 10 ; Displays a single character on the screen
; a number of times.
; >>Parms are char to be displayed followed
; by byte count of times to output byte.
Cls# equ 11 ; Clears screen and makes text cursor
; invisible.
; >>No parms.
SetMStart# equ 12 ; Sets location of maze start.
; >>Parms are X then Y coords (both bytes).
Mup# equ 13 ; Draws maze wall upwards.
; >>Parm is byte length to draw in characters.
Mrt# equ 14 ; Draws maze wall right.
; >>Parm is byte length to draw in characters.
Mdn# equ 15 ; Draws maze wall downwards.
; >>Parm is byte length to draw in characters.
Mlt# equ 16 ; Draws maze wall left.
; >>Parm is byte length to draw in characters.
SetAStart# equ 17 ; Sets arrow starting location.
; >>Parms are X then Y coordinates
; (both bytes).
Aup# equ 18 ; Animates arrow going up.
; >>No parms.
Art# equ 19 ; Animates arrow going right.
; >>No parms.
Adn# equ 20 ; Animates arrow going down.
; >>No parms.
Alt# equ 21 ; Animates arrow going left.
; >>No parms.
DoRep# equ 22 ; Repeats the command that follows
; a specified number of times.
; >>Parm is repetition count (one byte).
;
EndO# equ 0 ; used to indicate the end of a
; string of text in a TextUp#
; command.

[SECTION .cseg vstart=0100h] ;; <sd> .com section
;;
;; --== M a i n ==--
;;
;
; Program start point.
;
Start: ;; proc far
push cs ; code and data segments are the
pop ds ; same for this program
mov sp,0FFFEh ;; seed SP to top of segment <sd>
mov si, DemoScreen$ ; point to mini-program
call Interp ; execute it

mov ah,1 ; wait for a key before clearing the
int 21h ; the screen and ending
mov ah,15 ; get the current screen mode
int 10h ; so it can be set to force
sub ah,ah ; the screen to clear and the
int 10h ; cursor to reset
mov ah,4ch
int 21h ; end the program
;; Start endp
;
; Mini-interpreter main loop and dispatcher. Gets the next
; command and calls the associated function.
;
Interp: ;; proc near
cld
GetNextCommand:
lodsb ; get the next command
mov bl,al
xor bh,bh ; convert to a word in BX
shl bx,1 ; *2 for word lookup
call [bx+Function_Table] ; call the corresponding
; function
jmp short GetNextCommand ; do the next command
;
; The remainder of the listing consists of functions that
; implement the commands supported by the mini-interpreter.
;
; Ends execution of mini-program and returns to code that
; called Interp.
;
_@Done_:
pop ax ; don't return to Interp
ret ; done interpreting mini-program or subprogram
; so return to code that called Interp
;
; Executes a subprogram.
;
_@SubProg_:
lodsw ; get the address of the subprogram
push si ; save pointer to where to
; resume the present program
mov si,ax ; address of subprogram
call Interp ; call interpreter recursively
; to execute the subprogram
pop si ; restore pointer and resume
ret ; the program
;
; Sets the screen coordinates at which text will be drawn.
;
_@SetXY_:
lodsw
mov word [Cursor_X_Coordinate],ax
ret
;
; Sets the amount by which the cursor will move after each
; character is output to the screen.
;
_@SetXYInc_:
lodsw
mov word [Cursor_X_Increment],ax
ret
;
; Sets individual X coordinate, Y coordinate, X movement after
; character is output to the screen, Y movement, or character
; attribute depending on function number.
;
_@Set_:
shr bx,1 ; calculate the command number
lodsb ; get the new value
mov [bx+Text_Out_Data-SetX#],al ; store in location
; corresponding to
; the command number
Return:
ret
;
; Displays a string of text on the screen.
;
_@TextUp_:
GetNextCharacter:
lodsb ; get next text character
or al,al ; see if end of string
je Return ; if so, next command
call OutputCharacter ; else output character
jmp short GetNextCharacter ; next character
;
; Displays a single character on the screen multiple times.
;
_@RepChar_:
lodsw ; get the character in AL
; and the count in AH
RepCharLoop:
push ax ; save the character and count
call OutputCharacter ; output it once
pop ax ; restore count and character
dec ah ; decrement count
jne RepCharLoop ; jump if count not now 0
ret
;
; Clears the screen and turns off the cursor.
;
_@Cls_:
mov ax,600h ; BIOS clear screen parameters
mov bh,[Character_Attribute]
xor cx,cx
mov dx,184fh
int 10h ; clear the screen
mov ah,01 ; turn off cursor
mov cx,2000h ; by setting bit 5 of the
int 10h ; cursor start parameter
ret
;
; Sets the start coordinates for maze-drawing.
;
_@SetMStart_:
lodsw ; get both X and Y coordinates and store
mov word [Cursor_X_Coordinate], ax
mov [Last_Maze_Direction], byte 0ffh ; indicate no
ret ; last direction

;
;; --== Data to Interpreter to interpret ==--
;********************************************************************
; The sequences of bytes and words between this line and the next
; line of stars are the entire mini-program that our interpreter will
; execute. This mini-program will initialize the screen, put text on
; the screen, draw a maze, and animate an arrow through the maze.
;
DemoScreen$: ;;label byte ; this is the main mini-program that our
; interpreter will execute
; Initialize the screen
db SubProg#
dw InitScreen$
; Put up words
db SetXY#,0,0, SetXYInc#,0,1, TextUp#,'START',EndO#
db SetXY#,79,20, TextUp#,'END',EndO#
; Draw the maze
db SetMStart#,4,0, Mrt#,8, Mdn#,4, Mrt#,4, Mup#,3, Mrt#,4,
Mdn#,3
db Mrt#,4, Mdn#,8, Mrt#,3, Mup#,3, Mrt#,5, Mup#,9, Mrt#,17,
Mdn#,9
db Mrt#,5, Mdn#,3, Mrt#,4, Mup#,10, Mrt#,12, Mdn#,18, Mrt#,6
db SetXY#,4,2, Mrt#,4, Mdn#,2, Mlt#,4, Mdn#,18, Mrt#,12, Mup#,
4
db Mrt#,4, Mdn#,4, Mrt#,11, Mup#,11, Mrt#,5, Mup#,9, Mrt#,9,
Mdn#,9
db Mrt#,5, Mdn#,11, Mrt#,12, Mup#,4, Mrt#,4, Mdn#,4, Mrt#,10
db SetXY#,8,6, SubProg#
dw Box4x6$
db SetXY#,8,14, SubProg#
dw Box4x6$
db SetXY#,24,14, SubProg#
dw Box4x6$
db SetXY#,54,14, SubProg#
dw Box4x6$
db SetXY#,62,4, SubProg#
dw Box4x6$
db SetXY#,16,6, SubProg#
dw Box4x4$
db SetXY#,16,12, SubProg#
dw Box4x4$
db SetXY#,62,12, SubProg#
dw Box4x4$
; Animate the arrow through the maze.
db SetAStart#,3,0, Alt#,2, Adn#,2, Art#,2, Aup#,2
db SetXY#,0,0
db DoRep#,5,SubProg#
dw SpinAround$
db Alt#,2, Adn#,1, Art#,9, Adn#,4, Alt#,4, Adn#,8, Art#,8,
Adn#,8
db Alt#,8, Aup#,8, Art#,8, Aup#,2, Art#,8, Adn#,2, Art#,7,
Aup#,3
db Art#,5, Aup#,9, Art#,13, Adn#,9, Art#,5, Adn#,11, Art#,8,
Aup#,10
db Art#,8, Aup#,8, Alt#,8, Adn#,8, Art#,8, Adn#,10, Art#,8,
Adn#,1
db Art#,2, Aup#,2, DoRep#,5,SubProg#
dw SpinAround$
db Alt#,2, Adn#,1, Art#,1
db Done#

; Subprogram to clear the screen and initialize drawing variables.
InitScreen$ db SetXY#,0,0, SetAtt#,7, SetXYInc#,1,0, Cls#, Done#

; Subprograms to draw boxes.
Box4x4$ db Mrt#,4, Mdn#,4, Mlt#,4, Mup#,4, Mrt#,2, Done#
Box4x6$ db Mrt#,4, Mdn#,6, Mlt#,4, Mup#,6, Mrt#,2, Done#

; Subprogram to spin the arrow around a square.
SpinAround$ db Alt#,2, Adn#,2, Art#,2, Aup#,2, Done#

;********************************************************************
; Data for outputting text characters to the screen.

Text_Out_Data:
Cursor_X_Coordinate: db 0
Cursor_Y_Coordinate: db 0
Cursor_X_Increment: db 1
Cursor_Y_Increment: db 0
Character_Attribute: db 7
Last_Maze_Direction: db 0ffh ; 0-up, 1-rt, 2-dn, 3-lt
; 0ffh-starting
AnimateLastCoordinates: dw 0 ; low byte is X, high byte is Y
;
; Jump table used by Interp to call the subroutines associated
; with the various function numbers equated above. The functions
; called through this jump table constitute the mini-language
; used in this program.
;
Function_Table: ;; label word ; list of function addresses
dw _@Done_ ; which correspond one for
dw _@SubProg_ ; one with the commands defined
dw _@SetXY_ ; with EQU above
dw _@SetXYInc_
dw _@Set_ ; _@Set_, _@MOut_, and _@Animate_ all
use
dw _@Set_ ; the function number to determine
dw _@Set_ ; which byte to set or which
dw _@Set_ ; direction is called for
dw _@Set_
dw _@TextUp_
dw _@RepChar_
dw _@Cls_
dw _@SetMStart_
dw _@MOut_
dw _@MOut_
dw _@MOut_
dw _@MOut_
dw _@SetAStart_
dw _@Animate_
dw _@Animate_
dw _@Animate_
dw _@Animate_
dw _@DoRep_
;
; Maze-drawing tables.
;
XYIncTable db 0,-1, 1,0, 0,1, -1,0
; X & Y increment pairs for the 4 directions
CharacterGivenDirectionTable db 179,196,179,196
; vertical or horizontal line character to use
; for a given direction
FirstCharGivenNewAndOldDirectionTable: ;; label byte
db 179,218,179,191, 217,196,191,196 ; table of corner
db 179,192,179,217, 192,196,218,196 ; characters
;
; Outputs a maze line to the screen.
;
_@MOut_:
sub bx,Mup#+Mup# ; find new direction word index
mov ax,word [bx+XYIncTable] ; set for new
mov word [Cursor_X_Increment],ax ; direction
shr bx,1 ;change to byte index from word index
mov al,[bx+CharacterGivenDirectionTable] ; get char for
; this direction
mov ah,al ; move horizontal or vert
mov dl,[Last_Maze_Direction] ; character into AH
mov [Last_Maze_Direction],bl ; if last dir is 0ffh then
or dl,dl ; just use horiz or vert char
js OutputFirstCharacter ; look up corner character
shl dl,1 ; in table using last
shl dl,1 ; direction*4 + new direction
add bl,dl ; as index
mov al,[bx+FirstCharGivenNewAndOldDirectionTable]
OutputFirstCharacter:
push ax ; AL has corner, AH side char
call OutputCharacter ; put out corner character
pop ax ; restore side char to AH
lodsb ; get count of chars for this
dec al ; side, minus 1 for corner
xchg al,ah ; already output
jmp RepCharLoop ; put out side char n times
;
; Table of arrow characters pointing in four directions.
;
AnimateCharacterTable db 24,26,25,27
;
; Animates an arrow moving in one of four directions.
;
_@Animate_:
sub bx,(Aup#+Aup#) ; get word dir index
mov ax, word [XYIncTable+bx] ; set move direction
mov word [Cursor_X_Increment], ax
lodsb ; get move count
shr bx,1 ; make into byte
mov ah,[bx+AnimateCharacterTable] ; index and get
xchg al,ah ; char to animate
NextPosition: ; into AL, AH count
mov dx,[AnimateLastCoordinates] ; coords of last arrow
; move cursor to where last
; character was output
mov word [Cursor_X_Coordinate], dx
push ax ; save char and count
mov al,20h ; output a space there
call OutputCharacter ; to erase it
pop ax ;restore char in AL, count in AH
push ax ;save char and count
mov dx,word [Cursor_X_Coordinate] ; store new coords
mov [AnimateLastCoordinates],dx ; as last
call OutputCharacter ; output in new
; mov cx,DELAY_COUNT ; location then
;WaitSome: ; wait so doesn't
; loop WaitSome ; move too fast
call TDelay ;; <sd>

pop ax ; restore count and
; character
dec ah ; count down
jne NextPosition ; if not done
ret ; do again
;
; Sets the animation start coordinates.
;
_@SetAStart_:
lodsw ; get both X & Y
mov [AnimateLastCoordinates],ax ; coordinates and
ret ; store
;
; Repeats the command that follows the count parameter count times.
;
_@DoRep_:
lodsb ; get count parameter
NextRep:
push si ; save pointer to command
; to repeat
push ax ; save count
lodsb ; get command to repeat
mov bl,al ; convert command byte to
xor bh,bh ; word index in BX
shl bx,1 ;
call [bx+Function_Table] ; execute command once
pop ax ; get back the count
dec al ; see if it's time to stop
je DoneWithRep ; jump if done all repetitions
pop si ; get back the pointer to the
; command to repeat, and
jmp NextRep ; do it again
DoneWithRep:
pop ax ; clear pointer to command to
; repeat from stack, leave
; SI pointing to the next
; command
ret
;
;; Interp endp
;
; Outputs a text character at the present cursor coordinates,
; then advances the cursor coordinates according to the
; X and Y increments.
;
OutputCharacter: ;; proc near
push ax ; save the character to output
mov ah,2 ; set the cursor position
mov dx,word [Cursor_X_Coordinate]
xor bx,bx ; page 0
int 10h ; use BIOS to set cursor position
pop ax ; restore character to be output
mov ah,9 ; write character BIOS function
mov bl,[Character_Attribute] ; set attribute
mov cx,1 ; write just one character
int 10h ; use BIOS to output character
; advance X & Y coordinates
mov ax,word [Cursor_X_Coordinate] ; both x & y Incs
add al,[Cursor_X_Increment] ; can be negative
add ah,[Cursor_Y_Increment] ; so must add bytes
; separately
mov word [Cursor_X_Coordinate], ax ; store new X & Y
; coordinates
ret
;; OutputCharacter endp

;;--------------------------------------------------------60
;; <sd> my TDelay kludge reads the RTC seconds for a 1
;; second delay in the animation frame, alittle too slow,
;; but the original delay routine had too short of time
;; resolution so the animation's last frame was what got
;; displayed.

TDelay:
; mov ah, 0 ;; test code in lieu of timer. user keypress
; int 16h ;; to advance animation frame.
; RET

push cx
push dx

TDelay2:
mov ah, 2
int 1Ah ;; read real-time clock values, CX, DX, AH affected.
;; CH`hrs_BCD,CL`minutes_BCD,DH`seconds_BCD,DL`tz_flg
cmp [byte BCD_val], dh ;; look for unequal as state change
jne ETDelay
;; .else. same value, loop until changed.
jmp TDelay2

ETDelay: ;; .diff. so second rolled into next second, finally.
mov [BCD_val], dh ;; update, we'll be back here within 1 sec.

pop dx
pop cx
RET

BCD_val: db 0

;; --== eof ==--
;; -for nasm-
;; Valid chars in labels are letters, numbers, _, $, #, @, ~, .,
and ?.
;; The only characters which may be used as the first character of an
;; identifier are letters, . (with special meaning: see section 3.9),
;; _ and ?. An identifier may also be prefixed with a $ to indicate
;; that it is intended to be read as an identifier and not a reserved
;; word; thus, if some other module you are linking with defines a
;; symbol called eax, you can refer to $eax in NASM code to
distinguish
;; the symbol from the register. Maximum length of an identifier is
;; 4095 characters.
;; --== eof2 ==--

Rod Pemberton

unread,
Oct 17, 2009, 8:31:53 AM10/17/09
to

<s_dub...@MUNGED.microcosmotalk.com> wrote in message
news:4ad748ad$0$4975$9a6e...@unlimited.newshosting.com...

>
> In the thread "Mini--x86" Rod P. posted a ddj ref to a mini
> interpreter, and I had alook at it...
>
> the article is well worth a read and speaks well of assembler.
>
> It seems to me to be an example of threaded code, Forth like in a way,

Sort of an "unrolled" STC FORTH... with a single stack comprised of
execution tokens and data.

> anyway I did a nasm syntax conversion and afew kludges to get the
> animation to work, here's the nasm source for a .com file for a dos
> box, or XP's cmd.exe...
>

It works.


Steve,

Did you make a connection with Small C? The quantity of instruction
sequences emitted by Small C is small. It's possible that one could
implement each sequence as a routine in such a mini-interpreter. Then,
Small C could emit byte-code or actually word-code. It could be useful in
portability...


Rod Pemberton


s_dub...@munged.microcosmotalk.com

unread,
Oct 18, 2009, 5:27:03 PM10/18/09
to

On Oct 17, 7:31=A0am, "Rod Pemberton" <do_not_h...@nohavenot.cmm> wrote:
> <s_dubrov...@MUNGED.microcosmotalk.com> wrote in message

>
> news:4ad748ad$0$4975$9a6e...@unlimited.newshosting.com...
>
>
>
> > In the thread "Mini--x86" Rod P. posted a ddj ref to a mini
> > interpreter, and I had alook at it...
>
> > the article is well worth a read and speaks well of assembler.
>
> > It seems to me to be an example of threaded code, Forth like in a way,
>
> Sort of an "unrolled" STC FORTH... with a single stack comprised of
> execution tokens and data.
>
> > anyway I did a nasm syntax conversion and afew kludges to get the
> > animation to work, here's the nasm source for a .com file for a dos
> > box, or XP's cmd.exe...
>
> It works.
>
> Steve,
>
> Did you make a connection with Small C? =A0The quantity of instruction
> sequences emitted by Small C is small. =A0It's possible that one could
> implement each sequence as a routine in such a mini-interpreter. =A0Then,
> Small C could emit byte-code or actually word-code. =A0It could be useful=
in
> portability...
>
> Rod Pemberton

Hi Rod,

Hey, thanks again for posting that link.

I sort of made a connection to small-c, I guess you mean emitting an
intermediate code?

The syntactic actions in small-c are embedded in the parser as an
expression is evaluated, and are generated as an expression is
decoded. The syntactic actions are generic stack machine operations;
zpush(), zpop(), push_primary(), pop_secondary(), ..and the like.
This form of syntactic action is highly portable because the elements
like push, pop, etc. are of an Abstract Data Type :: Stack. This is
one thing that piqued my interest in small-c, along with single-pass,
and self-compiling. The parser tho has.. errata.., but I'd rather not
mess with it and still call it small-c, y'know? ;-)

But, yes it did cross my mind to institute, at least, the parser in
such a mini-interp way. Let's call that future project small-c2. So,
for small-c2, you have my vote! It seems like it would aid in code
generation optimizing.

Coincindentally, I've been revisiting the original 'Dragon Book' (from
time to time) to see how small-c would handle the example C code from
the book, and what kludges allow small-c to be used on it. Also to
gather or refresh ideas for just such a small-c2, or for another
language I'd been thinking about.

The mini-interp article lit up a few lights..
"
The basic operation of a mini-interpreter is simple, then: A data
sequence, or "miniprogram," provides function numbers, which are used
to vector through a jump table to functions. The function numbers are
basically commands in the "minilanguage" defined by the functions in
the jump table. The functions then acquire their own parameters from
the data sequence as needed.

Another way to view a mini-interpreter is as a control program that
allows you to call various functions in any order and with any
parameters. The jump table defines the functions that can be called --
in effect defining a minilanguage -- and the data sequence defines the
calling order and the parameters, thereby serving as a miniprogram.
The same result could, of course, be accomplished simply by writing
code that calls the desired routine with the desired parameters. The
great advantage of using a mini-interpreter over writing equivalent
code is that a mini-interpreter makes for more compact code that's
also easier to write and maintain.

Now, consider this: Pointers to the jump table and/or the data
sequence can be parameters passed to the interpreter, so the operation
of the interpreter can be changed instantly. By passing in a pointer
to a different data sequence, the functions in the jump table can be
combined in different orders and with different parameters; in other
words, a different miniprogram can be run. By passing in a pointer to
a different jump table, the very minilanguage that the mini-
interpreter supports can be altered.

In other words, not only the miniprogram that the mini-interpreter is
running but also the minilanguage that it supports can easily be
changed, even in mid-program -- the ultimate in flexibility.
"

First, this smacks of a simple system for multitasking.

Second, the data is in the form of: operator.operand_list,++ .
-which reminds me of Lisp notation of (cons X Y), ie,
operator.operand_list.

Third,
"
In a miniprogram, however, a mere byte of miniprogram code would
suffice, with the text built right into the miniprogram:

db 15,'Hello',O
"
Reminds me of old code I've seen quite a few times for inline strings:

call print_routine
db 'Hello There',0
cont:

where the print_routine expects the address of the string on the
stack, (which it is as a result of the call storing 'next'), i.e. the
db string.
Such a print_routine counts the characters in the string as it prints
and modifies the stack ret accordingly to: cont:.
(pop reg ! add reg, chr_count ! push reg ! ret)

Fourth, you know Function_Table could just as well be the function
table
of a generic driver replaceable with specific driver function table
when specific hardware is recognized as long as table index
functionally was mapped correctly; 0->open_device, 1->close_device, 3-
>clear_device, 4->query_device, ..or some such..

Fifth, what about code security???

Steve

Rod Pemberton

unread,
Nov 2, 2009, 6:48:27 AM11/2/09
to

<s_dub...@MUNGED.microcosmotalk.com> wrote in message
news:4adb8827$0$5086$9a6e...@unlimited.newshosting.com...

>
> I sort of made a connection to small-c, I guess you mean emitting an
> intermediate code?

Yes. I was thinking bytecode, tokens, or similar...

> The syntactic actions in small-c are embedded in the parser as an
> expression is evaluated, and are generated as an expression is
> decoded. The syntactic actions are generic stack machine operations;
> zpush(), zpop(), push_primary(), pop_secondary(), ..and the like.
> This form of syntactic action is highly portable because the elements
> like push, pop, etc. are of an Abstract Data Type :: Stack.

I'd think that'd be suitable to tokens.

> But, yes it did cross my mind to institute, at least, the parser in
> such a mini-interp way. Let's call that future project small-c2. So,
> for small-c2, you have my vote! It seems like it would aid in code
> generation optimizing.

Parser? ...

> Coincindentally, I've been revisiting the original 'Dragon Book' (from
> time to time) to see how small-c would handle the example C code from
> the book, and what kludges allow small-c to be used on it.

Great. I'd be interested in what does/doesn't work. I'd also be interested
in any test program that tests all those early C features.

> The mini-interp article lit up a few lights..

Yes. It might be more useful if you add a stack. You could then separate
the parameters from the function calls. That might allow you to implement
variables instead of hardcoded constants for parameters. You might have to
rework calls to into computed jumps or use xchg to separate the control flow
from data.

> The mini-interp article lit up a few lights..

It's a much simpler method of implementing features similar to FORTH,
without FORTH. At it's core, FORTH has an interpreter - well, two actually:
inner and outer, some "primitives" - which are routines in assemlby (or C),
compiled "words" - subroutines - which are lists of addresses "called" by
the "inner" interpreter until the assembly in the "primitives" gets
executed, and two stacks: one for data and one for return stack - i.e.,
control flow data. Of course, there are a number of complexities, higher
level stuff I've skipped - like dictionaries, variables and constants etc.,
and the "outer" interpreter which is a text parser - and subtleties to
actually implementing FORTH with those techniques. I'm still working on my
one in C...


Rod Pemberton


s_dub...@munged.microcosmotalk.com

unread,
Nov 5, 2009, 9:38:32 PM11/5/09
to

On Nov 2, 5:48=A0am, "Rod Pemberton" <do_not_h...@nohavenot.cmm> wrote:
> <s_dubrov...@MUNGED.microcosmotalk.com> wrote in message

>
> news:4adb8827$0$5086$9a6e...@unlimited.newshosting.com...
>
>
>
> > I sort of made a connection to small-c, I guess you mean emitting an
> > intermediate code?
>
> Yes. =A0I was thinking bytecode, tokens, or similar...
>

Ok.

> > The syntactic actions in small-c are embedded in the parser as an
> > expression is evaluated, and are generated as an expression is

> > decoded. =A0The syntactic actions are generic stack machine operations;


> > zpush(), zpop(), push_primary(), pop_secondary(), ..and the like.
> > This form of syntactic action is highly portable because the elements
> > like push, pop, etc. are of an Abstract Data Type :: Stack.
>
> I'd think that'd be suitable to tokens.
>

I think the later versions of Hendrix's small-c did that.

> > But, yes it did cross my mind to institute, at least, the parser in

> > such a mini-interp way. =A0Let's call that future project small-c2. =A0=
So,
> > for small-c2, you have my vote! =A0It seems like it would aid in code
> > generation optimizing.
>
> Parser? ...

Parser, Lexical Analyzer, they are both wrapped up together in the
recursive descent parser. Perhaps the threaded code isn't such a good
candidate for this, the article went on to comment that coditional
flow control wasn't a strong point of the method.


>
> > Coincindentally, I've been revisiting the original 'Dragon Book' (from
> > time to time) to see how small-c would handle the example C code from
> > the book, and what kludges allow small-c to be used on it.
>

> Great. =A0I'd be interested in what does/doesn't work. =A0I'd also be int=


erested
> in any test program that tests all those early C features.
>

Ok. It's been ad-hoc discovery sofar. Things like '|' instead of
'||' and '&' instead of '&&' in the small-c syntax. Test code for K&R
syntax is hard to find.

> > The mini-interp article lit up a few lights..
>

> Yes. =A0It might be more useful if you add a stack. =A0You could then sep=
arate
> the parameters from the function calls. =A0That might allow you to implem=
ent
> variables instead of hardcoded constants for parameters. =A0You might hav=
e to
> rework calls to into computed jumps or use xchg to separate the control f=
low
> from data.
>
I've more ideas than time..

> > The mini-interp article lit up a few lights..
>
> It's a much simpler method of implementing features similar to FORTH,

> without FORTH. =A0At it's core, FORTH has an interpreter - well, two actu=
ally:
> inner and outer, some "primitives" - which are routines in assemlby (or C=


),
> compiled "words" - subroutines - which are lists of addresses "called" by
> the "inner" interpreter until the assembly in the "primitives" gets
> executed, and two stacks: one for data and one for return stack - i.e.,

> control flow data. =A0Of course, there are a number of complexities, high=
er
> level stuff I've skipped - like dictionaries, variables and constants etc=


.,
> and the "outer" interpreter which is a text parser - and subtleties to

> actually implementing FORTH with those techniques. =A0I'm still working o=
n my
> one in C...
>
Yeah, an interpretive programming/control shell is a goal of mine. I
don't think C will be the syntax for it, I'm not sure what it will be,
I'm still mulling that over.

Steve

> Rod Pemberton

0 new messages