Data update

This commit is contained in:
Ingy döt Net 2026-04-30 12:34:36 -04:00
parent 4bb20c9b71
commit cbaf4c4b64
12390 changed files with 318560 additions and 27248 deletions

View file

@ -0,0 +1,652 @@
>>SOURCE FORMAT IS FREE
identification division.
*> this code is dedicated to the public domain
*> (GnuCOBOL) 2.3-dev.0
program-id. generator.
environment division.
configuration section.
repository. function all intrinsic.
data division.
working-storage section.
01 program-name pic x(32) value spaces global.
01 input-name pic x(32) value spaces global.
01 input-status pic xx global.
01 ast-record global.
03 ast-type pic x(14).
03 ast-value pic x(48).
03 filler redefines ast-value.
05 asl-left pic 999.
05 asl-right pic 999.
01 error-record pic x(64) value spaces global.
01 loadstack global.
03 l pic 99 value 0.
03 l-lim pic 99 value 64.
03 load-entry occurs 64.
05 l-node pic x(14).
05 l-left pic 999.
05 l-right pic 999.
05 l-link pic 999.
01 abstract-syntax-tree global.
03 t pic 999 value 0.
03 t1 pic 999.
03 t-lim pic 999 value 998.
03 filler occurs 998.
05 p1 pic 999.
05 p2 pic 999.
05 p3 pic 999.
05 n1 pic 999.
05 leaf.
07 leaf-type pic x(14).
07 leaf-value pic x(48).
05 node redefines leaf.
07 node-type pic x(14).
07 node-left pic 999.
07 node-right pic 999.
01 opcodes global.
03 opFETCH pic x value x'00'.
03 opSTORE pic x value x'01'.
03 opPUSH pic x value x'02'.
03 opADD pic x value x'03'.
03 opSUB pic x value x'04'.
03 opMUL pic x value x'05'.
03 opDIV pic x value x'06'.
03 opMOD pic x value x'07'.
03 opLT pic x value x'08'.
03 opGT pic x value x'09'.
03 opLE pic x value x'0A'.
03 opGE pic x value x'0B'.
03 opEQ pic x value x'0C'.
03 opNE pic x value x'0D'.
03 opAND pic x value x'0E'.
03 opOR pic x value x'0F'.
03 opNEG pic x value x'10'.
03 opNOT pic x value x'11'.
03 opJMP pic x value x'13'.
03 opJZ pic x value x'14'.
03 opPRTC pic x value x'15'.
03 opPRTS pic x value x'16'.
03 opPRTI pic x value x'17'.
03 opHALT pic x value x'18'.
01 variables global.
03 v pic 99.
03 v-max pic 99 value 0.
03 v-lim pic 99 value 16.
03 variable-entry occurs 16 pic x(48).
01 strings global.
03 s pic 99.
03 s-max pic 99 value 0.
03 s-lim pic 99 value 16.
03 string-entry occurs 16 pic x(48).
01 generated-code global.
03 c pic 999 value 1.
03 c1 pic 999.
03 c-lim pic 999 value 512.
03 kode pic x(512).
procedure division chaining program-name.
start-generator.
call 'loadast'
if program-name <> spaces
call 'readinput' *> close input-file
end-if
>>d perform print-ast
call 'codegen' using t
call 'emitbyte' using opHALT
>>d call 'showhex' using kode c
call 'listcode'
stop run
.
print-ast.
call 'printast' using t
display 'ast:' upon syserr
display 't=' t
perform varying t1 from 1 by 1 until t1 > t
if leaf-type(t1) = 'Identifier' or 'Integer' or 'String'
display t1 space trim(leaf-type(t1)) space trim(leaf-value(t1)) upon syserr
else
display t1 space node-left(t1) space node-right(t1) space trim(node-type(t1))
upon syserr
end-if
end-perform
.
identification division.
program-id. codegen common recursive.
data division.
working-storage section.
01 r pic ---9.
linkage section.
01 n pic 999.
procedure division using n.
start-codegen.
if n = 0
exit program
end-if
>>d display 'at 'c ' node=' space n space node-type(n) upon syserr
evaluate node-type(n)
when 'Identifier'
call 'emitbyte' using opFetch
call 'variableoffset' using leaf-value(n)
call 'emitword' using v '0'
when 'Integer'
call 'emitbyte' using opPUSH
call 'emitword' using leaf-value(n) '0'
when 'String'
call 'emitbyte' using opPUSH
call 'stringoffset' using leaf-value(n)
call 'emitword' using s '0'
when 'Assign'
call 'codegen' using node-right(n)
call 'emitbyte' using opSTORE
move node-left(n) to n1(n)
call 'variableoffset' using leaf-value(n1(n))
call 'emitword' using v '0'
when 'If'
call 'codegen' using node-left(n) *> conditional expr
call 'emitbyte' using opJZ *> jump to false path or exit
move c to p1(n)
call 'emitword' using '0' '0'
move node-right(n) to n1(n) *> true path
call 'codegen' using node-left(n1(n))
if node-right(n1(n)) <> 0 *> there is a false path
call 'emitbyte' using opJMP *> jump past false path
move c to p2(n)
call 'emitword' using '0' '0'
compute r = c - p1(n) *> fill in jump to false path
call 'emitword' using r p1(n)
call 'codegen' using node-right(n1(n)) *> false path
compute r = c - p2(n) *> fill in jump to exit
call 'emitword' using r p2(n)
else
compute r = c - p1(n)
call 'emitword' using r p1(n) *> fill in jump to exit
end-if
when 'While'
move c to p3(n) *> save address of while start
call 'codegen' using node-left(n) *> conditional expr
call 'emitbyte' using opJZ *> jump to exit
move c to p2(n)
call 'emitword' using '0' '0'
call 'codegen' using node-right(n) *> while body
call 'emitbyte' using opJMP *> jump to while start
compute r = p3(n) - c
call 'emitword' using r '0'
compute r = c - p2(n) *> fill in jump to exit
call 'emitword' using r p2(n)
when 'Sequence'
call 'codegen' using node-left(n)
call 'codegen' using node-right(n)
when 'Prtc'
call 'codegen' using node-left(n)
call 'emitbyte' using opPRTC
when 'Prti'
call 'codegen' using node-left(n)
call 'emitbyte' using opPRTI
when 'Prts'
call 'codegen' using node-left(n)
call 'emitbyte' using opPRTS
when 'Less'
call 'codegen' using node-left(n)
call 'codegen' using node-right(n)
call 'emitbyte' using opLT
when 'Greater'
call 'codegen' using node-left(n)
call 'codegen' using node-right(n)
call 'emitbyte' using opGT
when 'LessEqual'
call 'codegen' using node-left(n)
call 'codegen' using node-right(n)
call 'emitbyte' using opLE
when 'GreaterEqual'
call 'codegen' using node-left(n)
call 'codegen' using node-right(n)
call 'emitbyte' using opGE
when 'Equal'
call 'codegen' using node-left(n)
call 'codegen' using node-right(n)
call 'emitbyte' using opEQ
when 'NotEqual'
call 'codegen' using node-left(n)
call 'codegen' using node-right(n)
call 'emitbyte' using opNE
when 'And'
call 'codegen' using node-left(n)
call 'codegen' using node-right(n)
call 'emitbyte' using opAND
when 'Or'
call 'codegen' using node-left(n)
call 'codegen' using node-right(n)
call 'emitbyte' using opOR
when 'Subtract'
call 'codegen' using node-left(n)
call 'codegen' using node-right(n)
call 'emitbyte' using opSUB
when 'Add'
call 'codegen' using node-left(n)
call 'codegen' using node-right(n)
call 'emitbyte' using opADD
when 'Divide'
call 'codegen' using node-left(n)
call 'codegen' using node-right(n)
call 'emitbyte' using opDIV
when 'Multiply'
call 'codegen' using node-left(n)
call 'codegen' using node-right(n)
call 'emitbyte' using opMUL
when 'Mod'
call 'codegen' using node-left(n)
call 'codegen' using node-right(n)
call 'emitbyte' using opMOD
when 'Negate'
call 'codegen' using node-left(n)
call 'emitbyte' using opNEG
when 'Not'
call 'codegen' using node-left(n)
call 'emitbyte' using opNOT
when other
string 'in generator unknown node type: ' node-type(n) into error-record
call 'reporterror'
end-evaluate
.
end program codegen.
identification division.
program-id. variableoffset common.
data division.
linkage section.
01 variable-value pic x(48).
procedure division using variable-value.
start-variableoffset.
perform varying v from 1 by 1
until v > v-max
or variable-entry(v) = variable-value
continue
end-perform
if v > v-lim
string 'in generator variable offset v exceeds ' v-lim into error-record
call 'reporterror'
end-if
if v > v-max
move v to v-max
move variable-value to variable-entry(v)
end-if
.
end program variableoffset.
identification division.
program-id. stringoffset common.
data division.
linkage section.
01 string-value pic x(48).
procedure division using string-value.
start-stringoffset.
perform varying s from 1 by 1
until s > s-max
or string-entry(s) = string-value
continue
end-perform
if s > s-lim
string ' generator stringoffset s exceeds ' s-lim into error-record
call 'reporterror'
end-if
if s > s-max
move s to s-max
move string-value to string-entry(s)
end-if
subtract 1 from s *> convert index to offset
.
end program stringoffset.
identification division.
program-id. emitbyte common.
data division.
linkage section.
01 opcode pic x.
procedure division using opcode.
start-emitbyte.
if c >= c-lim
string 'in generator emitbyte c exceeds ' c-lim into error-record
call 'reporterror'
end-if
move opcode to kode(c:1)
add 1 to c
.
end program emitbyte.
identification division.
program-id. emitword common.
data division.
working-storage section.
01 word-x.
03 word usage binary-int.
01 loc pic 999.
linkage section.
01 word-value any length.
01 loc-value any length.
procedure division using word-value loc-value.
start-emitword.
if c + length(word) > c-lim
string 'in generator emitword exceeds ' c-lim into error-record
call 'reporterror'
end-if
move numval(word-value) to word
move numval(loc-value) to loc
if loc = 0
move word-x to kode(c:length(word))
add length(word) to c
else
move word-x to kode(loc:length(word))
end-if
.
end program emitword.
identification division.
program-id. listcode common.
data division.
working-storage section.
01 word-x.
03 word usage binary-int.
01 address-display pic ---9.
01 address-absolute pic zzz9.
01 data-display pic -(9)9.
01 v-display pic z9.
01 s-display pic z9.
01 c-display pic zzz9.
procedure division.
start-listcode.
move v-max to v-display
move s-max to s-display
display 'Datasize: ' trim(v-display) space 'Strings: ' trim(s-display)
perform varying s from 1 by 1
until s > s-max
display string-entry(s)
end-perform
move 1 to c1
perform until c1 >= c
compute c-display = c1 - 1
display c-display space with no advancing
evaluate kode(c1:1)
when opFETCH
add 1 to c1
move kode(c1:4) to word-x
compute address-display = word - 1
display 'fetch [' trim(address-display) ']'
add 3 to c1
when opSTORE
add 1 to c1
move kode(c1:4) to word-x
compute address-display = word - 1
display 'store [' trim(address-display) ']'
add 3 to c1
when opPUSH
add 1 to c1
move kode(c1:4) to word-x
move word to data-display
display 'push ' trim(data-display)
add 3 to c1
when opADD display 'add'
when opSUB display 'sub'
when opMUL display 'mul'
when opDIV display 'div'
when opMOD display 'mod'
when opLT display 'lt'
when opGT display 'gt'
when opLE display 'le'
when opGE display 'ge'
when opEQ display 'eq'
when opNE display 'ne'
when opAND display 'and'
when opOR display 'or'
when opNEG display 'neg'
when opNOT display 'not'
when opJMP
move kode(c1 + 1:length(word)) to word-x
move word to address-display
compute address-absolute = c1 + word
display 'jmp (' trim(address-display) ') ' trim(address-absolute)
add length(word) to c1
when opJZ
move kode(c1 + 1:length(word)) to word-x
move word to address-display
compute address-absolute = c1 + word
display 'jz (' trim(address-display) ') ' trim(address-absolute)
add length(word) to c1
when opPRTC display 'prtc'
when opPRTI display 'prti'
when opPRTS display 'prts'
when opHALT display 'halt'
when other
string 'in generator unknown opcode ' kode(c1:1) into error-record
call 'reporterror'
end-evaluate
add 1 to c1
end-perform
.
end program listcode.
identification division.
program-id. loadast common recursive.
procedure division.
start-loadast.
if l >= l-lim
string 'in generator loadast l exceeds ' l-lim into error-record
call 'reporterror'
end-if
add 1 to l
call 'readinput'
evaluate true
when ast-record = ';'
when input-status = '10'
move 0 to return-code
when ast-type = 'Identifier'
when ast-type = 'Integer'
when ast-type = 'String'
call 'makeleaf' using ast-type ast-value
move t to return-code
when ast-type = 'Sequence'
move ast-type to l-node(l)
call 'loadast'
move return-code to l-left(l)
call 'loadast'
move t to l-right(l)
call 'makenode' using l-node(l) l-left(l) l-right(l)
move t to return-code
when other
move ast-type to l-node(l)
call 'loadast'
move return-code to l-left(l)
call 'loadast'
move return-code to l-right(l)
call 'makenode' using l-node(l) l-left(l) l-right(l)
move t to return-code
end-evaluate
subtract 1 from l
.
end program loadast.
identification division.
program-id. printast common recursive.
data division.
linkage section.
01 n pic 999.
procedure division using n.
start-printast.
if n = 0
display ';' upon syserr
exit program
end-if
display leaf-type(n) upon syserr
evaluate leaf-type(n)
when 'Identifier'
when 'Integer'
when 'String'
display leaf-type(n) space trim(leaf-value(n)) upon syserr
when other
display node-type(n) upon syserr
call 'printast' using node-left(n)
call 'printast' using node-right(n)
end-evaluate
.
end program printast.
identification division.
program-id. makenode common.
data division.
linkage section.
01 parm-type any length.
01 parm-l-left pic 999.
01 parm-l-right pic 999.
procedure division using parm-type parm-l-left parm-l-right.
start-makenode.
if t >= t-lim
string 'in generator makenode t exceeds ' t-lim into error-record
call 'reporterror'
end-if
add 1 to t
move parm-type to node-type(t)
move parm-l-left to node-left(t)
move parm-l-right to node-right(t)
.
end program makenode.
identification division.
program-id. makeleaf common.
data division.
linkage section.
01 parm-type any length.
01 parm-value pic x(48).
procedure division using parm-type parm-value.
start-makeleaf.
add 1 to t
if t >= t-lim
string 'in generator makeleaf t exceeds ' t-lim into error-record
call 'reporterror'
end-if
move parm-type to leaf-type(t)
move parm-value to leaf-value(t)
.
end program makeleaf.
identification division.
program-id. readinput common.
environment division.
input-output section.
file-control.
select input-file assign using input-name
status is input-status
organization is line sequential.
data division.
file section.
fd input-file.
01 input-record pic x(64).
procedure division.
start-readinput.
if program-name = spaces
move '00' to input-status
accept ast-record on exception move '10' to input-status end-accept
exit program
end-if
if input-name = spaces
string program-name delimited by space '.ast' into input-name
open input input-file
if input-status = '35'
string 'in generator ' trim(input-name) ' not found' into error-record
call 'reporterror'
end-if
end-if
read input-file into ast-record
evaluate input-status
when '00'
continue
when '10'
close input-file
when other
string 'in generator ' trim(input-name) ' unexpected input-status: ' input-status
into error-record
call 'reporterror'
end-evaluate
.
end program readinput.
program-id. reporterror common.
procedure division.
start-reporterror.
report-error.
display error-record upon syserr
stop run with error status -1
.
end program reporterror.
identification division.
program-id. showhex common.
data division.
working-storage section.
01 hex.
03 filler pic x(32) value '000102030405060708090A0B0C0D0E0F'.
03 filler pic x(32) value '101112131415161718191A1B1C1D1E1F'.
03 filler pic x(32) value '202122232425262728292A2B2C2D2E2F'.
03 filler pic x(32) value '303132333435363738393A3B3C3D3E3F'.
03 filler pic x(32) value '404142434445464748494A4B4C4D4E4F'.
03 filler pic x(32) value '505152535455565758595A5B5C5D5E5F'.
03 filler pic x(32) value '606162636465666768696A6B6C6D6E6F'.
03 filler pic x(32) value '707172737475767778797A7B7C7D7E7F'.
03 filler pic x(32) value '808182838485868788898A8B8C8D8E8F'.
03 filler pic x(32) value '909192939495969798999A9B9C9D9E9F'.
03 filler pic x(32) value 'A0A1A2A3A4A5A6A7A8A9AAABACADAEAF'.
03 filler pic x(32) value 'B0B1B2B3B4B5B6B7B8B9BABBBCBDBEBF'.
03 filler pic x(32) value 'C0C1C2C3C4C5C6C7C8C9CACBCCCDCECF'.
03 filler pic x(32) value 'D0D1D2D3D4D5D6D7D8D9DADBDCDDDEDF'.
03 filler pic x(32) value 'E0E1E2E3E4E5E6E7E8E9EAEBECEDEEEF'.
03 filler pic x(32) value 'F0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF'.
01 cdx pic 9999.
01 bdx pic 999.
01 byte-count pic 9.
01 bytes-per-word pic 9 value 4.
01 word-count pic 9.
01 words-per-line pic 9 value 8.
linkage section.
01 data-field any length.
01 length-data-field pic 999.
procedure division using
by reference data-field
by reference length-data-field.
start-showhex.
move 1 to byte-count
move 1 to word-count
perform varying cdx from 1 by 1
until cdx > length-data-field
compute bdx = 2 * ord(data-field(cdx:1)) - 1 end-compute
display hex(bdx:2) with no advancing upon syserr
add 1 to byte-count end-add
if byte-count > bytes-per-word
display ' ' with no advancing upon syserr
move 1 to byte-count
add 1 to word-count end-add
end-if
if word-count > words-per-line
display ' ' upon syserr
move 1 to word-count
end-if
end-perform
if word-count <> 1
or byte-count <> 1
display ' ' upon syserr
end-if
display ' ' upon syserr
goback
.
end program showhex.
end program generator.

View file

@ -0,0 +1,287 @@
Const NULL As Any Ptr = 0
Const WORD_SIZE = 4
Enum NodeTypes
nd_Ident, nd_String, nd_Integer, nd_Sequence, nd_If, nd_Prtc, nd_Prts, nd_Prti, nd_While
nd_Assign, nd_Negate, nd_Not, nd_Mul, nd_Div, nd_Mod, nd_Add, nd_Sub, nd_Lss, nd_Leq
nd_Gtr, nd_Geq, nd_Eql, nd_Neq, nd_And, nd_Or
End Enum
Enum ByteCode
bcFetch, bcStore, bcPush, bcAdd, bcSub, bcMul, bcDiv, bcMod, bcLt, bcGt, bcLe, bcGe
bcEq, bcNe, bcAnd, bcOr, bcNeg, bcNot, bcJmp, bcJz, bcPrtc, bcPrts, bcPrti, bcHalt
End Enum
Type Node
nodTyp As NodeTypes
izda As Node Ptr
dcha As Node Ptr
sValue As String
iValue As Long
End Type
Type SymbolEntry
nombre As String
offset As Integer
End Type
Dim Shared As Ubyte code(0 To 9999)
Dim Shared As Integer codeSize = 0
Dim Shared As SymbolEntry stringPool(0 To 99)
Dim Shared As SymbolEntry globals(0 To 99)
Dim Shared As Integer numStrings = 0
Dim Shared As Integer numGlobals = 0
Sub EmitByte(b As Ubyte)
code(codeSize) = b
codeSize += 1
End Sub
Sub EmitWord(w As Long)
Dim As Long value = w
For i As Integer = 0 To 3
code(codeSize + i) = 0
Next
*Cast(Long Ptr, @code(codeSize)) = value
codeSize += 4
End Sub
Sub EmitWordAt(at As Integer, n As Long)
For i As Integer = 0 To 3
code(at + i) = 0
Next
*Cast(Long Ptr, @code(at)) = n
End Sub
Function Hole() As Integer
Dim As Integer t = codeSize
EmitWord(0)
Return t
End Function
Function FetchVarOffset(nombre As String) As Integer
nombre = Trim(nombre)
For i As Integer = numGlobals - 1 To 0 Step -1
If globals(i).nombre = nombre Then Return i
Next
globals(numGlobals).nombre = nombre
globals(numGlobals).offset = numGlobals
numGlobals += 1
Return numGlobals - 1
End Function
Function FetchStringOffset(s As String) As Integer
s = Trim(s)
If Left(s, 1) = """" Then s = Mid(s, 2, Len(s) - 2)
For i As Integer = numStrings - 1 To 0 Step -1
If stringPool(i).nombre = s Then Return i
Next
stringPool(numStrings).nombre = s
numStrings += 1
Return numStrings - 1
End Function
Function GetNodeType(text As String) As NodeTypes
text = Trim(text)
Select Case text
Case "Identifier": Return nd_Ident
Case "String" : Return nd_String
Case "Integer" : Return nd_Integer
Case "Sequence" : Return nd_Sequence
Case "If" : Return nd_If
Case "While" : Return nd_While
Case "Assign" : Return nd_Assign
Case "Add" : Return nd_Add
Case "Less" : Return nd_Lss
Case "Prts" : Return nd_Prts
Case "Prti" : Return nd_Prti
Case Else
Print "Error: Unknown symbol "; text
End 1
End Select
Return 0
End Function
Sub CodeGen(n As Node Ptr)
If n = NULL Then Return
Select Case n->nodTyp
Case nd_Integer
EmitByte(bcPush)
EmitWord(n->iValue)
Case nd_String
EmitByte(bcPush)
EmitWord(FetchStringOffset(n->sValue))
Case nd_Ident
EmitByte(bcFetch)
EmitWord(FetchVarOffset(n->sValue))
Case nd_Assign
Dim As Integer offset = FetchVarOffset(n->izda->sValue)
CodeGen(n->dcha)
EmitByte(bcStore)
EmitWord(offset)
Case nd_If
CodeGen(n->izda)
EmitByte(bcJz)
Dim As Integer p1 = Hole()
CodeGen(n->dcha->izda)
If n->dcha->dcha <> NULL Then
EmitByte(bcJmp)
Dim As Integer p2 = Hole()
EmitWordAt(p1, codeSize - p1)
CodeGen(n->dcha->dcha)
EmitWordAt(p2, codeSize - p2)
Else
EmitWordAt(p1, codeSize - p1)
End If
Case nd_While
Dim startPos As Integer = codeSize
CodeGen(n->izda)
EmitByte(bcJz)
Dim jzPos As Integer = codeSize
EmitWord(0)
CodeGen(n->dcha)
EmitByte(bcJmp)
Dim jmpOpPos As Integer = codeSize
EmitWord(startPos - jmpOpPos)
EmitWordAt(jzPos, codeSize - jzPos)
Case nd_Sequence
If n->izda <> NULL Then CodeGen(n->izda)
If n->dcha <> NULL Then CodeGen(n->dcha)
Case nd_Prtc, nd_Prti, nd_Prts
CodeGen(n->izda)
Select Case n->nodTyp
Case nd_Prtc: EmitByte(bcPrtc)
Case nd_Prti: EmitByte(bcPrti)
Case nd_Prts: EmitByte(bcPrts)
End Select
Case nd_Add
CodeGen(n->izda)
CodeGen(n->dcha)
EmitByte(bcAdd)
Case nd_Lss
CodeGen(n->izda)
CodeGen(n->dcha)
EmitByte(bcLt)
End Select
End Sub
Function LoadAst() As Node Ptr
Static As String linea
Line Input #1, linea
linea = Trim(linea)
If linea = "" Orelse linea = ";" Then Return NULL
Dim As Integer posic = Instr(linea, " ")
Dim As String head, tail
If posic = 0 Then
head = linea
tail = ""
Else
head = Left(linea, posic - 1)
tail = Trim(Mid(linea, posic + 1))
End If
Dim As Node Ptr n = New Node
n->nodTyp = GetNodeType(head)
Select Case n->nodTyp
Case nd_Integer
n->iValue = Vallng(tail)
Return n
Case nd_String, nd_Ident
n->sValue = tail
Return n
End Select
n->izda = LoadAst()
n->dcha = LoadAst()
Return n
End Function
Sub ListCode()
Print "Datasize:"; numGlobals; " Strings:"; numStrings
For i As Integer = 0 To numStrings - 1
Print """"; stringPool(i).nombre; """"
Next
Dim As Integer pc = 0
While pc < codeSize
Print Using "#####"; pc;
Dim As Integer op = code(pc)
pc += 1
Dim As Long v = *Cast(Long Ptr, @code(pc))
Select Case op
Case bcFetch
Print " fetch [" & v & "]"
pc += 4
Case bcStore
Print " store [" & v & "]"
pc += 4
Case bcPush
Print " push "; v
pc += 4
Case bcAdd: Print " add"
Case bcSub: Print " sub"
Case bcMul: Print " mul"
Case bcDiv: Print " div"
Case bcMod: Print " mod"
Case bcLt : Print " lt"
Case bcGt : Print " gt"
Case bcLe : Print " le"
Case bcGe : Print " ge"
Case bcEq : Print " eq"
Case bcNe : Print " ne"
Case bcAnd: Print " and"
Case bcOr : Print " or"
Case bcNeg: Print " neg"
Case bcNot: Print " not"
Case bcJmp
Print " jmp (" & v; ") " & pc + v
pc += 4
Case bcJz
Print " jz (" & v; ") " & pc + v
pc += 4
Case bcPrtc: Print " prtc"
Case bcPrti: Print " prti"
Case bcPrts: Print " prts"
Case bcHalt: Print " halt"
End Select
Wend
End Sub
' Main program
If Command(1) <> "" Then
Open Command(1) For Input As #1
Else
Print "Usage: compiler input.ast"
Sleep: End 1
End If
Dim As Node Ptr ast = LoadAst()
CodeGen(ast)
EmitByte(bcHalt)
ListCode()
Close #1
Sleep

View file

@ -0,0 +1,172 @@
Red [
Title: "Compiler/code generator"
Author: "hinjolicious"
]
#include %lex2.red
#include %parse.red
ast: copy []
ops: #[MUL: MUL DIV: DIV MOD: MOD ADD: ADD SUB: SUB NEG: NEG NOT: NOT
LT: LT GT: GT LEQ: LE GEQ: GE EQ: EQ NEQ: NE AND: AND OR: OR]
unary: [NEG: NEG NOT: NOT]
code: copy []
str-pool: #[]
var-pool: #[]
str-n: var-n: 0
wsize: 4
error: func [msg][ print ["ERROR:" msg halt] ]
slice: func [blk st n][ copy/part at blk st n ]
i2b: func [v][ to-binary v ]
b2i: func [v][ to-integer v ]
i2blk: func [i /local b blk x][
b: to-binary i
blk: copy []
foreach x b [append blk x]
blk ]
blk2i: func [blk /local b x][
b: make binary! wsize
foreach x blk [append b x]
to-integer b ]
emit-byte: func [x][ append code x ]
emit-word: func [x][ append code i2blk x ]
emit-word-at: func [a n][ change/part (at code a) (i2blk n) wsize ]
hole: func [/local t][
t: length? code
emit-word 0
t ]
var-offset: func [name /local n][
n: var-pool/:name
if n == none [
var-pool/:name: var-n
n: var-n
var-n: var-n + 1 ]
n ]
str-offset: func [str /local n][
n: str-pool/:str
if n = none [
str-pool/:str: str-n
n: str-n
str-n: str-n + 1 ]
n ]
_gen: func [a /local n p1 p2 ][
case [
none = a [exit]
'ID = a/1 [ emit-byte 'FETCH emit-word var-offset a/2 ]
'INT = a/1 [ emit-byte 'PUSH emit-word a/2 ]
'STR = a/1 [ emit-byte 'PUSH emit-word str-offset a/2 ]
'ASGN = a/1 [ n: var-offset a/2/2 _gen a/3 emit-byte 'STORE emit-word n ]
'IF = a/1 [
_gen a/2 ; if cond
emit-byte 'JZ ; if false, jump to to else
p1: hole ; reserve for else address
_gen a/3/2 ; then body
if a/3/3 <> none [
emit-byte 'JMP ; skip the else body
p2: hole ] ; reserve the location
emit-word-at (p1 + 1) ((length? code) - p1) ; fix for jz
if a/3/3 <> none [
_gen a/3/3 ; else body
emit-word-at (p2 + 1) ((length? code) - p2) ] ] ; fix for jmp
'WHILE = a/1 [
p1: length? code ; before while
_gen a/2 ; while cond
emit-byte 'JZ ; if false, jump to after while
p2: hole ; reserve after while address
_gen a/3 ; while body
emit-byte 'JMP ; jump-back to before while
emit-word (p1 - (length? code))
emit-word-at (p2 + 1) ((length? code) - p2) ] ; fix jz to this location
'SEQ = a/1 [ _gen a/2 _gen a/3 ]
'PRTC = a/1 [ _gen a/2 emit-byte 'PRTC ]
'PRTI = a/1 [ _gen a/2 emit-byte 'PRTI ]
'PRTS = a/1 [ _gen a/2 emit-byte 'PRTS ]
ops/(:a/1) [ _gen a/2 _gen a/3 emit-byte ops/(:a/1) ]
unary/(:a/1) [ _gen a/2 emit-byte unary/(:a/1) ]
true [ error rejoin ["Expecting operator, found '" a/1 "'"] ]
]
] ; _gen
gen: func [ast][
clear code clear str-pool clear var-pool str-n: var-n: 0
_gen ast emit-byte 'HALT
code ]
list-code: func[/local out s op c][
out: copy ""
pad-pc: func [x][pad/left x 5]
pad-op: func [x][pad x 6]
append out rejoin ["Datasize: " length? var-pool " Strings: " length? str-pool "^/"]
foreach [a b] sort/skip (to-block str-pool) 2 [
append out rejoin [mold a "^/"] ]
pc: 0
while [pc < length? code][
s: pad-pc pc
op: code/(:pc + 1) ; 1-based block
pc: pc + 1
switch/default to-lit-word op [
'FETCH [ x: blk2i slice code (pc + 1) wsize c: rejoin [pad-op op "[" x "]"] pc: pc + wsize ]
'STORE [ x: blk2i slice code (pc + 1) wsize c: rejoin [pad-op op "[" x "]"] pc: pc + wsize ]
'PUSH [ x: blk2i slice code (pc + 1) wsize c: rejoin [pad-op op x] pc: pc + wsize ]
'ADD [ c: "ADD" ]
'SUB [ c: "SUB" ]
'MUL [ c: "MUL" ]
'DIV [ c: "DIV" ]
'MOD [ c: "MOD" ]
'LT [ c: "LT" ]
'GT [ c: "GT" ]
'LE [ c: "LE" ]
'GE [ c: "GE" ]
'EQ [ c: "EQ" ]
'NE [ c: "NE" ]
'AND [ c: "AND" ]
'OR [ c: "OR" ]
'NEG [ c: "NEG" ]
'NOT [ c: "NOT" ]
'JMP [ x: blk2i slice code (pc + 1) wsize c: rejoin [pad-op op "(" x ") " pc + x] pc: pc + wsize ]
'JZ [ x: blk2i slice code (pc + 1) wsize c: rejoin [pad-op op "(" x ") " pc + x] pc: pc + wsize ]
'PRTC [ c: "PRTC" ]
'PRTI [ c: "PRTI" ]
'PRTS [ c: "PRTS" ]
'HALT [ c: "HALT" ]
][ error rejoin ["list-code: Unknown opcode " op] ]
append out rejoin [s " " c "^/"]
]
out
] ; list-code
test: does [
while [(tx: ask "Code: ") <> ""] [
case [
tx = "r" [tx: read fn: request-file]
all [tx = "s" fn <> "" tcode <> ""] [
out-fn: replace fn ".t" ".tcode"
write out-fn tcode
print ["Saved to " out-fn]
continue ] ]
?? fn
?? tx
lx: lex tx
?? lx
ast: parse lx
?? ast
gen ast
?? code
tcode: list-code
print tcode
]
]
test

View file

@ -0,0 +1,160 @@
Red [
Title: "Compiler/code generator"
Author: "hinjolicious"
Purpose: "list-based code generator that is more suitable Red's native block data structure"
]
#include %lex2-bak.red
#include %parse.red
ast: copy []
ops: #[MUL: MUL DIV: DIV MOD: MOD ADD: ADD SUB: SUB NEG: NEG NOT: NOT
LT: LT GT: GT LEQ: LE GEQ: GE EQ: EQ NEQ: NE AND: AND OR: OR]
unary: [NEG: NEG NOT: NOT]
code: copy []
str-pool: #[]
var-pool: #[]
str-n: var-n: 0
wsize: 1 ; we're using an integer based code
error: func [msg][ print ["ERROR:" msg halt] ]
emit: func [x][ append code x ]
emit-at: func [a n][ change at code a n ]
hole: func [/local t][ t: length? code emit 0 t ]
var-offset: func [name /local n][
n: var-pool/:name
if n == none [
var-pool/:name: var-n
n: var-n
var-n: var-n + 1 ]
n ]
str-offset: func [str /local n][
n: str-pool/:str
if n = none [
str-pool/:str: str-n
n: str-n
str-n: str-n + 1 ]
n ]
_gen: func [a /local n p1 p2 ][
case [
none = a [exit]
'ID = a/1 [ emit 'FETCH emit a/2 ] ;var-offset a/2 ]
'INT = a/1 [ emit 'PUSH emit a/2 ]
'STR = a/1 [ emit 'PUSH emit a/2 ] ;str-offset a/2 ]
;'ASGN = a/1 [ n: var-offset a/2/2 _gen a/3 emit 'STORE emit n ]
'ASGN = a/1 [ n: a/2/2 _gen a/3 emit 'STORE emit n ]
'IF = a/1 [
_gen a/2 ; if cond
emit 'JZ ; if false, jump to to else
p1: hole ; reserve for else address
_gen a/3/2 ; then body
if a/3/3 <> none [
emit 'JMP ; skip the else body
p2: hole ] ; reserve the location
emit-at (p1 + 1) ((length? code) - p1) ; fix for jz
if a/3/3 <> none [
_gen a/3/3 ; else body
emit-at (p2 + 1) ((length? code) - p2) ] ] ; fix for jmp
'WHILE = a/1 [
p1: length? code ; before while
_gen a/2 ; while cond
emit 'JZ ; if false, jump to after while
p2: hole ; reserve after while address
_gen a/3 ; while body
emit 'JMP ; jump-back to before while
emit (p1 - (length? code))
emit-at (p2 + 1) ((length? code) - p2) ] ; fix jz to this location
'SEQ = a/1 [ _gen a/2 _gen a/3 ]
'PRTC = a/1 [ _gen a/2 emit 'PRTC ]
'PRTI = a/1 [ _gen a/2 emit 'PRTI ]
'PRTS = a/1 [ _gen a/2 emit 'PRTS ]
ops/(:a/1) [ _gen a/2 _gen a/3 emit ops/(:a/1) ]
unary/(:a/1) [ _gen a/2 emit unary/(:a/1) ]
true [ error rejoin ["Expecting operator, found '" a/1 "'"] ]
]
] ; _gen
gen: func [ast][
;clear code clear str-pool clear var-pool str-n: var-n: 0
code: copy []
str-pool: #[]
var-pool: #[]
str-n: var-n: 0
_gen ast emit 'HALT
code ]
list-code: func[/local out s op c][
out: copy ""
pad-pc: func [x][pad/left x 5]
pad-op: func [x][pad x 6]
append out rejoin ["Datasize: " length? var-pool " Strings: " length? str-pool "^/"]
foreach [a b] sort/skip (to-block str-pool) 2 [
append out rejoin [mold a "^/"] ]
pc: 0
while [pc < length? code][
s: pad-pc pc
op: code/(:pc + 1) ; 1-based block
pc: pc + 1
switch/default to-lit-word op [
'FETCH [ x: code/(pc + 1) c: rejoin [pad-op op x] pc: pc + 1 ]
'STORE [ x: code/(pc + 1) c: rejoin [pad-op op x] pc: pc + 1 ]
'PUSH [ x: code/(pc + 1) c: rejoin [pad-op op x] pc: pc + 1 ]
'ADD [ c: "ADD" ]
'SUB [ c: "SUB" ]
'MUL [ c: "MUL" ]
'DIV [ c: "DIV" ]
'MOD [ c: "MOD" ]
'LT [ c: "LT" ]
'GT [ c: "GT" ]
'LE [ c: "LE" ]
'GE [ c: "GE" ]
'EQ [ c: "EQ" ]
'NE [ c: "NE" ]
'AND [ c: "AND" ]
'OR [ c: "OR" ]
'NEG [ c: "NEG" ]
'NOT [ c: "NOT" ]
'JMP [ x: code/(pc + 1) c: rejoin [pad-op op "(" x ") " pc + x] pc: pc + 1 ]
'JZ [ x: code/(pc + 1) c: rejoin [pad-op op "(" x ") " pc + x] pc: pc + 1 ]
'PRTC [ c: "PRTC" ]
'PRTI [ c: "PRTI" ]
'PRTS [ c: "PRTS" ]
'HALT [ c: "HALT" ]
][ error rejoin ["list-code: Unknown opcode " op] ]
append out rejoin [s " " c "^/"]
]
out
] ; list-code
test: does [
while [(tx: ask "Code: ") <> ""] [
case [
tx = "r" [tx: read fn: request-file]
all [tx = "s" fn <> "" tcode <> ""] [
out-fn: replace fn ".t" ".tcode"
write out-fn tcode
print ["Saved to " out-fn]
continue ] ]
?? fn
?? tx
lx: lex tx
?? lx
ast: parse lx
?? ast
gen ast
?? code
tcode: list-code
print tcode
]
]
test