I have finished a version of the ‘Meta II’ compiler with lower case letters.! is constant
to EOL.
Rather than byte codes, I compile to assmbly code. JSV is a subroutine call.
I did how ever need to add a new branch instruction LIT R #n
to permit in-line constants. R = PC, PC = PC + #n
FCS " string " is a ASM macro for string constants. It is just over 4K long.
! META II 67
.SYNTAX PROGRAM
OUT1 =
'*1' .CRD('JSV A Z GN1')
/ '*2' .CRD('JSV A Z GN2')
/ '*' .CRD('JSV A Z CI')
/ .STRING .CRD('FCS ' *)
.CRD('JSV A Z CL')
;
OUTPUT =
('.CRD' '(' $ OUT1 ')'
/ '.LABEL' .CRD('JSV A Z LB') OUT1)
.CRD('JSV A Z OUT')
/ '.TTY' '(' $ OUT1 ')'.CRD('JSV A Z TTY')
;
EX3 = .ID .CRD('LEA X Z ' *) .CRD('JSV A Z CSR')
/ .STRING .CRD('FCS ' *)
.CRD('JSV A Z TST')
/ '.ID' .CRD('JSV A Z ID')
/ '.NUMBER' .CRD('JSV A Z NUM')
/ '.STRING' .CRD('JSV A Z SR')
/ '(' EX1 ')'
/ '.EMPTY' .CRD('LD. A #1') .CRD('ST A Z SWITCH')
/ '$' .LABEL *1 EX3 .CRD('LD A Z SWITCH')
.CRD('BNE A #' *1) .CRD('LD. A #1') .CRD('ST A Z SWITCH')
;
EX2 = (EX3 .CRD('LD A Z SWITCH') .CRD('BEQ A #' *1)
/ OUTPUT)
$ (EX3 .CRD('JSV A Z BE') / OUTPUT)
.LABEL *1 ;
EX1 = EX2 $('/' .CRD('LD A Z SWITCH') .CRD('BNE A #' *1)EX2)
.LABEL *1 ;
ST = .ID .LABEL * '=' EX1 ';' .CRD('JMP A Z RR') ;
PROGRAM = '.SYNTAX'
.TTY('meta 67 <CARD.IN> <CARD.OUT>')
.CRD('INC M67V.ASM')
.ID .CRD('LEA X Z ' *) .CRD('JSV A Z CSR')
.CRD('BRA A #ENDOK') $ ST '.END' .CRD('END')
.TTY('Meta 67 finished')
;
.END
I’ve had it on my mind to build an implementation of this myself, since Alan Kay talked about it. I’ve been taking steps toward it through other projects.
Over the summer, I built what I’m calling a “Parr VM”, named after Terence Parr, who demo’d a simple VM of his own design in Java, years ago. Now, I’m writing an assembler for it, but in the process, I decided to build a couple state machines I devised, so that I can program the assembly language using a very simple pattern language, and spec’ing out a grammar.
The state machine project has turned into a larger one than I anticipated, quite a bit larger than the VM!
I have moved to 1969 … the meta compiler has expanded.
! META 69 CARD.IN CARD.OUT
! FEB 27 2023 GENERIC CPU
! META VARIABLES
!STK RS 4 STACK
!DIRTY RS 4 AC DIRTY
!MODE RS 4 MODE 0 GLOBAL 1 PARAMS 2 LOCAL
!SIZE RS 4 0 BYTE 1 HALF 2 WORD
!VARCNT RS 4 VARIABLES USED
!ARGC RS 4 ARG COUNT
!LOCC RS 4 LOCAL COUNT
!GBLC RS 4 GLOBAL COUNT
!ISVALUE RS 4 SYMBOL VALUE
!ISLOCAL RS 4 LOCAL VARIABLE
!ISARRAY RS 4 ARRAY (LEA/AEA)
!ISFLT RS 4 FLOATING POINT
!ISSIZE RS 4 SIZE
!LAST RS 4 FOUND SYMBOL VALUE
!ETAB RS 4 END OF SYMBOL TABLE
!LTAB RS 4 LOCAL END OF SYMBOL TABLE
.SYNTAX PROGRAM
OUT1 =
'*1+' .CRD('JSV A Z GN0') ! NEW LABEL GN1
| '*1' .CRD('JSV A Z GN1')
| '*2' .CRD('JSV A Z GN2')
| '*' .CRD('JSV A Z CI')
| '?' .ID .CRD('LD A Z ' *) .CRD('JSV A Z _ATOS')
| .STRING
.CRD('JMP A Z ' *1)
.LABEL *2
.CRD('STR ' *)
.LABEL *1
.CRD('LEA X Z ' *2)
.CRD('JSV A Z CL')
;
OUTPUT =
('.CRD' '(' $ OUT1 ')'
| '.LABEL' .CRD('JSV A Z LB') OUT1)
.CRD('JSV A Z OUT')
| '.TTY' '(' $ OUT1 ')'.CRD('JSV A Z TTY')
| '.TXT' '(' $ OUT1 ')'
;
!
LDKB = .TEQ 0 ISSIZE .CRD(' LD. A # ' *) ! BYTE
| .TEQ 1 ISSIZE .CRD(' LD: A # ' *) ! HALF
| .EMPTY .CRD(' LD A # ' *) ! WORD
;
META =
'.NSYMB' .CRD('JSV A Z _NSYM') ! SET .ID IN SYMBOL TABLE
| '.SYMB' .CRD('JSV A Z _SYM') ! SYMBOL VALUE
| '.PSHK' .CRD('JSV A Z _PSHK') ! PUSH CONSTANT
| '.POPK' .CRD('JSV A Z _POPK') ! POP CONSTANT
| '.PSHV' .CRD('JSV A Z _PSHV') ! PUSH VARIABLE
| '.POPV' .CRD('JSV A Z _POPV') ! POP VARIABLE
| '.SET' .NUMBER LDKB
.ID .CRD('ST A Z ' *) ! SET CONTANT TO VARIABLE
| '.ADD' .NUMBER LDKB ! ADD CONSTANT TO VARIABLE
.ID .CRD('ADD A Z ' *)
.CRD('ST A Z ' *)
| '.AND' .NUMBER LDKB ! AND CONSTANT TO VARIABLE
.ID .CRD('AND A Z ' *)
.CRD('ST A Z ' *)
| '.SUB' .NUMBER LDKB ! SUB CONSTANT TO VARIABLE
.ID .CRD('CAD A Z ' *)
.CRD('ST A Z ' *)
| '.MOV' ! MOV VARIABLE
.ID .CRD('LD A Z ' *)
.ID .CRD('ST A Z ' *)
| '.TEQ' .NUMBER LDKB ! TEST VARIABLE WITH CONSTANT
.ID .CRD('CAD A Z ' *)
.CRD('SEQ A')
.CRD('ST A Z _SWITCH')
| '.TNE' .NUMBER LDKB ! TEST VARIABLE WITH CONSTANT
.ID .CRD('CAD A Z ' *)
.CRD('SNE A')
.CRD('ST A Z _SWITCH')
| '.PUSH' .CRD('JSV A Z _PUSH') ! PUSH <TOKEN> STRING
| '.POP' .CRD('JSV A Z _POP') ! POP <TOKEN> STRING
;
EX3 = .ID .CRD('LEA X Z ' *) .CRD('JSV A Z CSR')
| .STRING
.CRD('JMP A Z ' *1)
.LABEL *2
.CRD('STR ' *)
.LABEL *1
.CRD('LEA X Z ' *2)
.CRD('JSV A Z TST')
| '.ID' .CRD('JSV A Z ID')
| '.NUMBER' .CRD('JSV A Z NUM')
| '.STRING' .CRD('JSV A Z SR')
| '(' EX1 ')'
| '.EMPTY' .CRD('LD. A #1') .CRD('ST A Z _SWITCH')
| '$' .LABEL *1 EX3 .CRD('LD A Z _SWITCH')
.CRD('BNE A #' *1) .CRD('LD. A #1') .CRD('ST A Z _SWITCH')
| META ;
EX2 = (EX3 .CRD('LD A Z _SWITCH') .CRD('BEQ A #' *1)
| OUTPUT)
$ (EX3 .CRD('JSV A Z BE') | OUTPUT)
.LABEL *1 ;
EX1 = EX2 $('|'
.CRD('LD A Z _SWITCH')
.CRD('BNE A #' *1)
EX2)
.LABEL *1 ;
ST = .ID .LABEL * '=' EX1 ';' .CRD('JMP A Z RR') ;
PROGRAM = '.SYNTAX'
.TTY('meta 69 {CARD.IN} {CARD.OUT}')
.CRD('INC M69V.ASM')
! SET VARIABLES UP
.SET 0 VARCNT
.ID .CRD('LEA X Z ' *) .CRD('JSV A Z CSR')
.CRD('BRA A #ENDOK') $ ST '.END' .CRD('END')
.TTY('Meta 69 finished')
.TTY('Variables used ' ? VARCNT )
;
! TEST STUFF
PUSHME =
.TEQ 0 DIRTY
.SET 1 DIRTY
.SET 0 STK
! ! DIRTY <> 0
|
.EMPTY .ADD 4000 STK
.CRD('ST A S+ ')
;
.END