1
0
mirror of https://github.com/dschmenk/PLASMA.git synced 2025-01-22 23:29:55 +00:00

on-the-metal compiler initial checkin

This commit is contained in:
David Schmenk 2017-12-20 17:51:26 -08:00
parent 65a6c2bdee
commit 6eb5558634
5 changed files with 2714 additions and 0 deletions

View File

@ -4,6 +4,7 @@ import cmdsys
//
const FALSE = 0
const TRUE = not FALSE
const NULL = 0
//
// Machine ID values
//

793
src/toolsrc/codegen.pla Normal file
View File

@ -0,0 +1,793 @@
//
// Symbol table
//
//def dumpsym(idptr, idcnt)#0
// while idcnt
// prword(idptr=>idval)
// cout(' ')
// prbyte(idptr->idtype)
// cout(' ')
// prstr(@idptr->idname)
// cout('=')
// if idptr->idtype & ADDR_TYPE
// if idptr=>idval & IS_CTAG
// prword((ctag_tbl:[idptr=>idval & MASK_CTAG] & MASK_CTAG) + codebuff)
// else
// prword(idptr=>idval + codebuff)
// fin
// else
// prword(idptr=>idval)
// fin
// crout
// idptr = idptr + idptr->idname + idrecsz
// idcnt--
// loop
//end
def idmatch(nameptr, len, idptr, idcnt)
byte i
while idcnt
if len == idptr->idname
for i = 1 to len
if nameptr->[i - 1] <> idptr->idname.[i]
break
fin
next
if i > len
return idptr
fin
fin
idptr = idptr + idptr->idname + idrecsz
idcnt--
loop
return 0
end
def id_lookup(nameptr, len)
word idptr
idptr = idmatch(nameptr, len, idlocal_tbl, locals)
if idptr
return idptr
fin
idptr = idmatch(nameptr, len, idglobal_tbl, globals)
if idptr
return idptr
fin
return parse_err(@undecl_id)
end
def idglobal_lookup(nameptr, len)
return idmatch(nameptr, len, idglobal_tbl, globals)
end
def idlocal_add(namestr, len, type, size)
if idmatch(namestr, len, @idlocal_tbl, locals); return parse_err(@dup_id); fin
lastlocal=>idval = framesize
lastlocal->idtype = type | LOCAL_TYPE
nametostr(namestr, len, lastlocal + idname)
locals++
lastlocal = lastlocal + idrecsz + len
if lastlocal > idlocal_tbl + idlocal_tblsz
prstr(@local_sym_overflw)
exit
fin
framesize = framesize + size
if framesize > 255
return parse_err(@local_overflw)
fin
return TRUE
end
def iddata_add(namestr, len, type, size)
if idmatch(namestr, len, idglobal_tbl, globals); return parse_err(@dup_id); fin
lastglobal=>idval = datasize
lastglobal->idtype = type
nametostr(namestr, len, lastglobal + idname)
emit_iddata(datasize, size, lastglobal + idname)
globals++
lastglobal = lastglobal + idrecsz + len
if lastglobal > idglobal_tbl + idglobal_tblsz
prstr(@global_sym_overflw)
exit
fin
datasize = datasize + size
return TRUE
end
def iddata_size(type, varsize, initsize)#0
if varsize > initsize
datasize = datasize + varsize
emit_data(0, 0, 0, varsize - initsize)
else
datasize = datasize + initsize
fin
end
def idglobal_add(namestr, len, type, value)
if idmatch(namestr, len, idglobal_tbl, globals); return parse_err(@dup_id); fin
lastglobal=>idval = value
lastglobal->idtype = type
nametostr(namestr, len, lastglobal + idname)
globals++
lastglobal = lastglobal + idrecsz + len
if lastglobal > idglobal_tbl + idglobal_tblsz
prstr(@global_sym_overflw)
exit
fin
return TRUE
end
def idfunc_add(namestr, len, tag)
return idglobal_add(namestr, len, FUNC_TYPE, tag)
end
def idconst_add(namestr, len, value)
return idglobal_add(namestr, len, CONST_TYPE, value)
end
def idglobal_init#0
word op
byte i
idglobal_tbl = heapalloc(IDGLOBALSZ)
idlocal_tbl = heapalloc(IDLOCALSZ)
codebuff = heapalloc(CODEBUFSZ)
codeptr = codebuff
entrypoint = 0
globals = 0
lastglobal = idglobal_tbl
codetag = -1
//
//Init free op sequence list
//
freeop_lst = heapalloc(OPSEQNUM*t_opseq)
op = freeop_lst
for i = OPSEQNUM-1 downto 0
op=>nextop = op + t_opseq
op = op + t_opseq
next
op=>nextop = NULL
end
def idlocal_init#0
locals = 0
framesize = 0
lastlocal = idlocal_tbl
end
//
// Code tags. Upper bit is IS_RESOLVED flag, lower 15 is offset into codebuff
// Flags are:
//
def ctag_new
if codetag >= ctag_max; return parse_err(@ctag_full); fin
codetag = codetag + 1
ctag_tbl:[codetag] = 0 // Unresolved, nothing to update yet
return codetag | IS_CTAG
end
def ctag_resolve(ctag)#0
word updtptr, nextptr
ctag = ctag & MASK_CTAG // Better be a ctag!
if ctag_tbl:[ctag] & IS_RESOLVED;parse_err(@dup_id); return; fin
updtptr = ctag_tbl:[ctag] & MASK_CTAG
while updtptr
//
// Update list of addresses needing resolution
//
updtptr = updtptr + codebuff
nextptr = *updtptr & MASK_CTAG
if *updtptr & IS_RELATIVE
*updtptr = codeptr - updtptr
else
*updtptr = codeptr
fin
updtptr = nextptr
loop
ctag_tbl:[ctag] = (codeptr - codebuff) | IS_RESOLVED
end
//
// Emit data/bytecode
//
def emit_byte(bval)#0
^codeptr = bval
codeptr++
end
def emit_word(wval)#0
*codeptr = wval
codeptr = codeptr + 2
end
def emit_fill(size)#0
memset(codeptr, 0, size)
codeptr = codeptr + size
end
def emit_op(op)#0
lastop = op
emit_byte(op)
end
def emit_addr(tag)#0
word updtptr
if tag & IS_CTAG
tag = tag & MASK_CTAG
if ctag_tbl:[tag] & IS_RESOLVED
updtptr = (ctag_tbl:[tag] & MASK_CTAG) + codebuff
else
//
// Add to list of tags needing resolution
//
updtptr = ctag_tbl:[tag] & MASK_CTAG
ctag_tbl:[tag] = codeptr - codebuff
fin
emit_word(updtptr)
else
emit_word(tag + codebuff)
fin
end
def emit_reladdr(tag)#0
word updtptr
if tag & IS_CTAG
tag = tag & MASK_CTAG
if ctag_tbl:[tag] & IS_RESOLVED
updtptr = ((ctag_tbl:[tag] & MASK_CTAG) + codebuff) - codeptr
else
//
// Add to list of tags needing resolution
//
updtptr = ctag_tbl:[tag] | IS_RELATIVE
ctag_tbl:[tag] = codeptr - codebuff
fin
emit_word(updtptr)
else
emit_word(tag - (codeptr - codebuff))
fin
end
def emit_iddata(value, size, namestr)#0
emit_fill(size)
end
def emit_data(vartype, consttype, constval, constsize)
byte i
word size, chrptr
if consttype == 0
size = constsize
emit_fill(constsize)
elsif consttype == STR_TYPE
size = constsize
chrptr = constval
constsize--
emit_byte(constsize)
while constsize > 0
emit_byte(^chrptr)
chrptr++
constsize--
loop
else
if vartype & BYTE_TYPE
size = 1
emit_byte(constval)
else
size = 2
if consttype == CONSTADDR_TYPE
emit_addr(constval)
else
emit_word(constval)
fin
fin
fin
return size
end
def emit_const(cval)#0
if cval == 0
emit_op($00)
elsif cval > 0 and cval < 256
emit_op($2A)
emit_byte(cval)
else
emit_op($2C)
emit_word(cval)
fin
end
def emit_constr(str, size)#0
emit_op($2E)
emit_data(0, STR_TYPE, str, size)
end
def emit_lb#0
emit_op($60)
end
def emit_lw#0
emit_op($62)
end
def emit_llb(offset)#0
emit_op($64)
emit_byte(offset)
end
def emit_llw(offset)#0
emit_op($66)
emit_byte(offset)
end
def emit_lab(tag, offset)#0
if tag & IS_CTAG and offset
parse_err(@no_ctag_offst)
else
emit_op($68)
emit_addr(tag+offset)
fin
end
def emit_law(tag, offset)#0
if tag & IS_CTAG and offset
parse_err(@no_ctag_offst)
else
emit_op($6A)
emit_addr(tag+offset)
fin
end
def emit_sb#0
emit_op($70)
end
def emit_sw#0
emit_op($72)
end
def emit_slb(offset)#0
emit_op($74)
emit_byte(offset)
end
def emit_slw(offset)#0
emit_op($76)
emit_byte(offset)
end
def emit_dlb(offset)#0
emit_op($6C)
emit_byte(offset)
end
def emit_dlw(offset)#0
emit_op($6E)
emit_byte(offset)
end
def emit_sab(tag, offset)#0
if tag & IS_CTAG and offset
parse_err(@no_ctag_offst)
else
emit_op($78)
emit_addr(tag+offset)
fin
end
def emit_saw(tag, offset)#0
if tag & IS_CTAG and offset
parse_err(@no_ctag_offst)
else
emit_op($7A)
emit_addr(tag+offset)
fin
end
def emit_dab(tag, offset)#0
if tag & IS_CTAG and offset
parse_err(@no_ctag_offst)
else
emit_op($7C)
emit_addr(tag+offset)
fin
end
def emit_daw(tag, offset)#0
if tag & IS_CTAG and offset
parse_err(@no_ctag_offst)
else
emit_op($7E)
emit_addr(tag+offset)
fin
end
def emit_call(tag)#0
emit_op($54)
emit_addr(tag)
end
def emit_ical#0
emit_op($56)
end
def emit_localaddr(offset)#0
emit_op($28)
emit_byte(offset)
end
def emit_globaladdr(tag, offset)#0
if tag & IS_CTAG and offset
parse_err(@no_ctag_offst)
else
emit_op($26)
emit_addr(tag+offset)
fin
end
def emit_indexbyte#0
emit_op($02)
end
def emit_indexword#0
emit_op($1E)
end
def emit_unaryop(op)
when op
is NEG_TKN
emit_op($10); break
is ALT_COMP_TKN
is COMP_TKN
emit_op($12); break
is LOGIC_NOT_TKN
emit_op($20); break
is INC_TKN
emit_op($0C); break
is DEC_TKN
emit_op($0E); break
is BPTR_TKN
emit_op($60); break
is WPTR_TKN
emit_op($62); break
otherwise
return FALSE
wend
return TRUE
end
def emit_binaryop(op)
when op
is MUL_TKN
//
// Replace MUL 2 with SHL 1
//
if lastop == $2A and ^(codeptr - 1) == 2 // CB 2
codeptr = codeptr - 1
emit_byte(1) // CB 1
emit_op($1A) // SHL
else
emit_op($06)
fin
break
is DIV_TKN
//
// Replace DIV 2 with SHR 1
//
if lastop == $2A and ^(codeptr - 1) == 2 // CB 2
codeptr = codeptr - 1
emit_byte(1) // CB 1
emit_op($1C) // SHR
else
emit_op($08)
fin
break
is MOD_TKN
emit_op($0A); break
is ADD_TKN
//
// Replace ADD 1 with INCR
//
if lastop == $2A and ^(codeptr - 1) == 1 // CB 1
codeptr = codeptr - 2
emit_op($0C) // INC_OP
else
emit_op($02)
fin
break
is SUB_TKN
//
// Replace SUB 1 with DECR
//
if lastop == $2A and ^(codeptr - 1) == 1 // CB 1
codeptr = codeptr - 2
emit_op($0E) // DEC_OP
else
emit_op($04)
fin
break
is SHL_TKN
emit_op($1A); break
is SHR_TKN
emit_op($1C); break
is AND_TKN
emit_op($14); break
is OR_TKN
emit_op($16); break
is EOR_TKN
emit_op($18); break
is EQ_TKN
emit_op($40); break
is NE_TKN
emit_op($42); break
is GE_TKN
emit_op($48); break
is LT_TKN
emit_op($46); break
is GT_TKN
emit_op($44); break
is LE_TKN
emit_op($4A); break
is LOGIC_OR_TKN
emit_op($22); break
is LOGIC_AND_TKN
emit_op($24); break
otherwise
return FALSE
wend
return TRUE
end
def emit_brtru(tag)#0
emit_op($4E)
emit_reladdr(tag)
end
def emit_brfls(tag)#0
emit_op($4C)
emit_reladdr(tag)
end
def emit_brgt(tag)#0
emit_op($38)
emit_reladdr(tag)
end
def emit_brlt(tag)#0
emit_op($3A)
emit_reladdr(tag)
end
def emit_brne(tag)#0
emit_op($3E)
emit_reladdr(tag)
end
def emit_branch(tag)#0
emit_op($50)
emit_reladdr(tag)
end
def emit_drop#0
emit_op($30)
end
def emit_leave#0
if framesize
emit_op($5A)
else
emit_op($5C)
fin
end
def emit_enter(cparams)#0
emit_byte(emit_enter.[0])
emit_byte(emit_enter.[1])
emit_byte(emit_enter.[2])
if framesize
emit_op($58)
emit_byte(framesize)
emit_byte(cparams)
fin
end
//
//New/release sequence ops
//
def new_op
word op
op = freeop_lst
if not op
puts("Compiler out of sequence ops!")
return NULL
fin
freeop_lst = freeop_lst=>nextop
op=>nextop = NULL
return op
end
def release_op(op)#0
if op
op=>nextop = freeop_lst
freeop_lst = op
fin
end
def release_seq(seq)#0
{
word op
while seq
op = seq
seq = seq=>nextop
//
//Free this op
//
op=>nextop = freeop_lst
freeop_lst = op
loop
end
//
//Generate a sequence of code
//
def gen_seq(seq, opcode, cval, tag, offsz, type)
{
word op
if not seq
seq = new_op
op = seq
else
op = seq
while op=>nextop; op = op=>nextop; loop
op=>nextop = new_op
op = op=>nextop
fin
op->code = opcode
op=>val = cval
op=>tag = tag
op=>offsz = offsz
op->type = type
return seq
end
//
//Append one sequence to the end of another
//
def cat_seq(seq1, seq2)
{
word op
if not seq1; return seq2; fin
op = seq1
while op=>nextop; op = op=>nextop; loop
op=>nextop = seq2
return seq1
fin
//
//Emit the pending sequence
//
def emit_pending_seq#0
word lcl_pending, op
// This is called by some of the emit_*() functions to ensure that any
// pending ops are emitted before they emit their own op when they are
// called from the parser. However, this function itself calls some of those
// emit_*() functions to emit instructions from the pending sequence, which
// would cause an infinite loop if we weren't careful. We therefore set
// pending_seq to null on entry and work with a local copy, so if this
// function calls back into itself it is a no-op.
if not pending_seq; return; fin
lcl_pending = pending_seq
pending_seq = NULL
//if outflags & OPTIMIZE
// while crunch_seq(@lcl_pending, 0); loop
// while crunch_seq(@lcl_pending, 1); loop
//fin
while lcl_pending
op = lcl_pending
when op->code
is NEG_CODE
is COMP_CODE
is LOGIC_NOT_CODE
is INC_CODE
is DEC_CODE
is BPTR_CODE
is WPTR_CODE
emit_unaryop(op->code)
break
is MUL_CODE
is DIV_CODE
is MOD_CODE
is ADD_CODE
is SUB_CODE
is SHL_CODE
is SHR_CODE
is AND_CODE
is OR_CODE
is EOR_CODE
is EQ_CODE
is NE_CODE
is GE_CODE
is LT_CODE
is GT_CODE
is LE_CODE
is LOGIC_OR_CODE
is LOGIC_AND_CODE
emit_op(op->code)
break
is CONST_CODE
emit_const(op=>val)
break
is STR_CODE
emit_conststr(op=>val)
break
is LB_CODE
emit_lb()
break
is LW_CODE
emit_lw()
break
is LLB_CODE
emit_llb(op=>offsz)
break
is LLW_CODE
emit_llw(op=>offsz)
break
is LAB_CODE
emit_lab(op=>tag, op=>offsz, op->type)
break
is LAW_CODE
emit_law(op=>tag, op=>offsz, op->type)
break
is SB_CODE
emit_sb()
break
is SW_CODE
emit_sw()
break;
is SLB_CODE
emit_slb(op-=>offsz)
break
is SLW_CODE
emit_slw(op=>offsz)
break
is DLB_CODE
emit_dlb(op=>offsz)
break
is DLW_CODE
emit_dlw(op=>offsz)
break
is SAB_CODE
emit_sab(op=>tag, op=>offsz, op->type)
break
is SAW_CODE
emit_saw(op=>tag, op=>offsz, op->type)
break
is DAB_CODE
emit_dab(op=>tag, op=>offsz, op->type)
break
is DAW_CODE
emit_daw(op=>tag, op=>offsz, op->type)
break
is CALL_CODE
emit_call(op=>tag, op->type)
break
is ICAL_CODE
emit_ical()
break
is LADDR_CODE
emit_localaddr(op=>offsz)
break
is GADDR_CODE
emit_globaladdr(op=>tag, op=>offsz, op->type)
break
is INDEXB_CODE
emit_indexbyte
break
is INDEXW_CODE
emit_indexword
break
is DROP_CODE
emit_drop
break
is DUP_CODE
emit_dup
break
is PUSH_EXP_CODE
emit_push_exp
break
is PULL_EXP_CODE
emit_pull_exp
break
is BRNCH_CODE
emit_brnch(op=>tag)
break
is BRFALSE_CODE
emit_brfls(op=>tag)
break
is BRTRUE_CODE
emit_brtru(op=>tag)
break
is CODETAG_CODE
printf("_B%03d%c\n", op->tag, LBL);
break;
is NOP_CODE
break
otherwise
return
wend
lcl_pending = lcl_pending=>nextop;
//
//Free this op
//
op=>nextop = freeop_lst
freeop_lst = op
loop
end
//
//Emit a sequence of ops (into the pending sequence)
//
def emit_seq(seq)#0
word op
byte string
string = 0
op = seq
while op
if op->code == STR_CODE; string = 1; fin
op = op=>nextop
loop
pending_seq = cat_seq(pending_seq, seq)
// The source code comments in the output are much more logical if we don't
// merge multiple sequences together. There's no value in doing this merging
// if we're not optimizing, and we optionally allow it to be prevented even
// when we are optimizing by specifing the -N (NO_COMBINE) flag.
//
// We must also force output if the sequence includes a CS opcode, as the
// associated 'constant' is only temporarily valid.
if !(outflags & OPTIMIZE) or (outflags & NO_COMBINE) or string
emit_pending_seq
end

331
src/toolsrc/lex.pla Normal file
View File

@ -0,0 +1,331 @@
//
// Lexical anaylzer
//
def isalpha(c)
if c >= 'A' and c <= 'Z'
return TRUE
elsif c >= 'a' and c <= 'z'
return TRUE
elsif c == '_'
return TRUE
fin
return FALSE
end
def isnum(c)
return c >= '0' and c <= '9'
end
def isalphanum(c)
if c >= 'A' and c <= 'Z'
return TRUE
elsif c >= '0' and c <= '9'
return TRUE
elsif c >= 'a' and c <= 'z'
return TRUE
elsif c == '_'
return TRUE
fin
return FALSE
end
def keymatch
byte i, keypos
word chrptr
keypos = 0
while keywrds[keypos] < tknlen
keypos = keypos + keywrds[keypos] + 2
loop
chrptr = tknptr - 1
while keywrds[keypos] == tknlen
for i = 1 to tknlen
if toupper(^(chrptr + i)) <> keywrds[keypos + i]
break
fin
next
if i > tknlen
return keywrds[keypos + keywrds[keypos] + 1]
fin
keypos = keypos + keywrds[keypos] + 2
loop
return ID_TKN
end
def scan
//
// Skip whitespace
//
while ^scanptr == ' '
scanptr++
loop
tknptr = scanptr
scanchr = ^scanptr
//
// Scan for token based on first character
//
if isalpha(scanchr)
//
// ID, either variable name or reserved word
//
repeat
scanptr++
until not isalphanum(^scanptr)
tknlen = scanptr - tknptr
token = keymatch
elsif scanchr >= '0' and scanchr <= '9' // isnum()
//
// Decimal constant
//
token = INT_TKN
constval = 0
repeat
constval = constval * 10 + ^scanptr - '0'
scanptr++
until ^scanptr < '0' or ^scanptr > '9'
else
//
// Potential multiple character tokens
//
when scanchr
is '$'
//
// Hexadecimal constant
//
token = INT_TKN
constval = 0
repeat
scanptr++
if ^scanptr >= '0' and ^scanptr <= '9'
constval = (constval << 4) + ^scanptr - '0'
elsif ^scanptr >= 'A' and ^scanptr <= 'F'
constval = (constval << 4) + ^scanptr - '7'// 'A'-10
elsif ^scanptr >= 'a' and ^scanptr <= 'f'
constval = (constval << 4) + ^scanptr - 'W'// 'a'-10
else
break
fin
until !^scanptr
break
is '\''
//
// Character constant
//
token = CHR_TKN
scanptr++
if ^scanptr <> '\\'
constval = ^scanptr
else
scanptr++
when ^scanptr
is 'n'
constval = $0D; break
is 'r'
constval = $0A; break
is 't'
constval = $09; break
otherwise
constval = ^scanptr
wend
fin
if ^(scanptr + 1) <> '\''
return parse_err(@bad_cnst)
fin
scanptr = scanptr + 2
break
is '"'
//
// String constant
//
token = STR_TKN
constval = @strconst+1
strconst = 0
scanptr++
while ^scanptr and ^scanptr <> '"'
if ^scanptr <> '\\'
^constval = ^scanptr
else
scanptr++
when ^scanptr
is 'n'
^constval = $0D; break
is 'r'
^constval = $0A; break
is 't'
^constval = $09; break
otherwise
constval = ^scanptr
wend
fin
constval++
strconst++
scanptr++
loop
if !^scanptr; return parse_err(@bad_cnst); fin
constval = @strconst
scanptr++
break
is '/'
if ^(scanptr + 1) == '/'
token = EOL_TKN
^scanptr = $00
else
token = DIV_TKN
scanptr++
fin
break
is '='
if ^(scanptr + 1) == '='
token = EQ_TKN
scanptr = scanptr + 2
elsif ^(scanptr + 1) == '>'
token = PTRW_TKN
scanptr = scanptr + 2
else
token = SET_TKN
scanptr++
fin
break
is '-'
if ^(scanptr + 1) == '>'
token = PTRB_TKN
scanptr = scanptr + 2
elsif ^(scanptr + 1) == '-'
token = DEC_TKN
scanptr = scanptr + 2
else
token = SUB_TKN
scanptr++
fin
break
is '+'
if ^(scanptr + 1) == '+'
token = INC_TKN
scanptr = scanptr + 2
else
token = ADD_TKN
scanptr++
fin
break
is '>'
if ^(scanptr + 1) == '>'
token = SHR_TKN
scanptr = scanptr + 2
elsif ^(scanptr + 1) == '='
token = GE_TKN
scanptr = scanptr + 2
else
token = GT_TKN
scanptr++
fin
break
is '<'
if ^(scanptr + 1) == '<'
token = SHL_TKN
scanptr = scanptr + 2
elsif ^(scanptr + 1) == '='
token = LE_TKN
scanptr = scanptr + 2
elsif ^(scanptr + 1) == '>'
token = NE_TKN
scanptr = scanptr + 2
else
token = LT_TKN
scanptr++
fin
break
is ':
if ^(scanptr + 1) == ':'
token = TRIELSE_TKN;
scanptr = scanptr + 2
else
token = COLON_TKN;
scanptr++
fin
break
is '?'
if ^(scanptr + 1) == '?'
token = TERNARY_TKN;
scanptr = scanptr + 2
else
token = TERNARY_TKN;
scanptr++
fin
break
is 0
is ';'
if token <> EOF_TKN
token = EOL_TKN
fin
break
otherwise
//
// Simple single character tokens
//
token = scanchr | $80
scanptr++
wend
fin
tknlen = scanptr - tknptr
return token
end
def rewind(ptr)#0
scanptr = ptr
end
def lookahead
word backptr, backtkn
byte prevtkn, prevlen, look
backptr = scanptr
backtkn = tknptr
prevtkn = token
prevlen = tknlen
look = scan
scanptr = backptr
tknptr = backtkn
token = prevtkn
tknlen = prevlen
return look
end
//
// Get next line of input
//
def nextln
if ^scanptr == ';'
scanptr++
scan
else
if token <> EOL_TKN or token <> EOF_TKN; return parse_err("Extraneous characters"); fin
scanptr = inbuff
instr = fileio:read(refnum, inbuff, 127)
if instr
^(inbuff + instr + 1) = 0 // NULL terminate string
lineno++
if !(lineno & $0F); putc('.'); fin
if scan == INCLUDE_TKN
if incref; return parse_err("Nested INCLUDEs not allowed"); fin
if scan <> STRING_TKN; return parse_err("Missing INCLUDE file"); fin
incfile = scanptr - constval
memcpy(@incfile + 1, constval, incfile)
sysincbuf = heapallocalign(1024, 256)
incref = fileio:opensys(@incfile, sysincbuf)
if not incref; return parse_err("Unable to open INCLUDE file"); fin
fileio:newline(incref, $7F, $0D)
refnum = incref
parsefile = @incfile
srcline = lineno
lineno = 0
return nextln
fin
else
if refnum == incref
fileio:close(incnum)
heaprelease(sysincbuf)
incref = 0
refnum = srcref
parsefile = srcfile
lineno = srcline
return nextln
else
*instr = 0
token = EOF_TKN
fin
fin
fin
return token
end

1249
src/toolsrc/parse.pla Normal file

File diff suppressed because it is too large Load Diff

340
src/toolsrc/plasm.pla Normal file
View File

@ -0,0 +1,340 @@
//
// Data and text buffer constants
//
const machid = $BF98
const iobuffer = $0800
const databuff = $0C00
const codebuff = $A900
const codebuffsz = $1000
//
// Compiler variables
//
//
// Tokens
//
const ID_TKN = $D6 // V
const CHR_TKN = $C3 // C
const INT_TKN = $C9 // I
const STR_TKN = $D3 // S
const EOL_TKN = $02
const EOF_TKN = $01
const ERR_TKN = $00
//
//Ternary operand operators
//
const TERNARY_TOKEN = $BF // ?
const TRIELSE_TOKEN = $DF // _
//
// Binary operand operators
//
const SET_TKN = $BD // =
const ADD_TKN = $AB // +
const SUB_TKN = $AD // -
const MUL_TKN = $AA // *
const DIV_TKN = $AF // /
const MOD_TKN = $A5 // %
const OR_TKN = $FC // |
const EOR_TKN = $DE // ^
const AND_TKN = $A6 // &
const SHR_TKN = $D2 // R
const SHL_TKN = $CC // L
const GT_TKN = $BE // >
const GE_TKN = $C8 // H
const LT_TKN = $BC // <
const LE_TKN = $C2 // B
const NE_TKN = $D5 // U
const EQ_TKN = $C5 // E
const LOGIC_AND_TKN = $CE // N
const LOGIC_OR_TKN = $CF // O
//
// Unary operand operators
//
const AT_TKN = $C0 // @
const DOT_TKN = $AE // .
const COLON_TKN = $BA // :
const NEG_TKN = $AD // -
const POUND_TKN = $A3 // #
const COMP_TKN = $FE // ~
const LOGIC_NOT_TKN = $A1 // !
const BPTR_TKN = $DE // ^
const WPTR_TKN = $AA // *
const PTRB_TKN = $D8 // X
const PTRW_TKN = $D7 // W
const INC_TKN = $C1 // A
const DEC_TKN = $C4 // D
//
// Enclosure tokens
//
const OPEN_PAREN_TKN = $A8 // (
const CLOSE_PAREN_TKN = $A9 // )
const OPEN_BRACKET_TKN = $DB // [
const CLOSE_BRACKET_TKN = $DD // ]
//
// Misc. tokens
//
const COMMA_TKN = $AC // ,
//const COMMENT_TKN = $BB // //
//
// Keyword tokens
//
const CONST_TKN = $80
const BYTE_TKN = $81
const WORD_TKN = $82
const IF_TKN = $83
const ELSEIF_TKN = $84
const ELSE_TKN = $85
const FIN_TKN = $86
const END_TKN = $87
const WHILE_TKN = $88
const LOOP_TKN = $89
const CASE_TKN = $8A
const OF_TKN = $8B
const DEFAULT_TKN = $8C
const ENDCASE_TKN = $8D
const FOR_TKN = $8E
const TO_TKN = $8F
const DOWNTO_TKN = $90
const STEP_TKN = $91
const NEXT_TKN = $92
const REPEAT_TKN = $93
const UNTIL_TKN = $94
const DEF_TKN = $95
const STRUC_TKN = $96
const SYSFLAGS_TKN = $97
const DONE_TKN = $98
const RETURN_TKN = $99
const BREAK_TKN = $9A
const CONT_TKN = $9B
const PREDEF_TKN = $9C
const IMPORT_TKN = $9D
const EXPORT_TKN = $9E
const INCLUDE_TKN = $9F
//
// Types
//
const CONST_TYPE = $01
const BYTE_TYPE = $02
const WORD_TYPE = $04
const VAR_TYPE = $06 // (WORD_TYPE | BYTE_TYPE)
const FUNC_TYPE = $08
const FUNC_CONST_TYPE = $09
const ADDR_TYPE = $0E // (VAR_TYPE | FUNC_TYPE)
const LOCAL_TYPE = $10
const BPTR_TYPE = $20
const WPTR_TYPE = $40
const PTR_TYPE = $60 // (BPTR_TYPE | WPTR_TYPE)
const XBYTE_TYPE = $22 // (BPTR_TYPE | BYTE_TYPE)
const XWORD_TYPE = $44 // (WPTR_TYPE | WORD_TYPE)
const CONSTADDR_TYPE = $61 // (CONST_TYPE | PTR_TYPE)
const STR_TYPE = $80
//
// Keywords
//
byte keywrds = "IF", IF_TKN
byte = "TO", TO_TKN
byte = "IS", OF_TKN
byte = "OR", LOGIC_OR_TKN
byte = "FOR", FOR_TKN
byte = "FIN", FIN_TKN
byte = "DEF", DEF_TKN
byte = "END", END_TKN
byte = "AND", LOGIC_AND_TKN
byte = "NOT", LOGIC_NOT_TKN
byte = "BYTE", BYTE_TKN
byte = "WORD", WORD_TKN
byte = "ELSE", ELSE_TKN
byte = "NEXT", NEXT_TKN
byte = "WHEN", CASE_TKN
byte = "LOOP", LOOP_TKN
byte = "STEP", STEP_TKN
byte = "DONE", DONE_TKN
byte = "WEND", ENDCASE_TKN
byte = "CONST", CONST_TKN
byte = "STRUC", STRUC_TKN
byte = "ELSIF", ELSEIF_TKN
byte = "WHILE", WHILE_TKN
byte = "UNTIL", UNTIL_TKN
byte = "BREAK", BREAK_TKN
byte = "IMPORT", IMPORT_TKN
byte = "EXPORT", EXPORT_TKN
byte = "DOWNTO", DOWNTO_TKN
byte = "REPEAT", REPEAT_TKN
byte = "RETURN", RETURN_TKN
byte = "PREDEF", PREDEF_TKN
byte = "INCLUDE", INCLUDE_TKN
byte = "CONTINUE", CONT_TKN
byte = "SYSFLAGS", SYSFLAGS_TKN
byte = "OTHERWISE",DEFAULT_TKN
byte = $FF
//
// Mathematical ops
//
const bops_tblsz = 17 // minus 1
byte[] bops_tbl // Highest precedence
byte = MUL_TKN, DIV_TKN, MOD_TKN
byte = ADD_TKN, SUB_TKN
byte = SHR_TKN, SHL_TKN
byte = AND_TKN
byte = EOR_TKN
byte = OR_TKN
byte = GT_TKN, GE_TKN, LT_TKN, LE_TKN
byte = EQ_TKN, NE_TKN
byte = LOGIC_AND_TKN
byte = LOGIC_OR_TKN
// Lowest precedence
byte[] bops_prec // Highest precedence
byte = 1, 1, 1
byte = 2, 2
byte = 3, 3
byte = 4
byte = 5
byte = 6
byte = 7, 7, 7, 7
byte = 8, 8
byte = 9
byte = 10
// Lowest precedence
byte[16] opstack
byte[16] precstack
word opsp = -1
word[16] valstack
byte[16] sizestack
byte[16] typestack
word valsp = -1
//
// Symbol table variables
//
struc t_opseq
byte code
word val
word tag
word offsz
byte type
word nextop
end
const OPSEQNUM = 200
const idglobal_tblsz = 2048
const idlocal_tblsz = 512
const idglobal_tbl = $1600
const idlocal_tbl = $1E00
const ctag_max = 1024
const ctag_tbl = $800
const idval = 0
const idtype = 2
const idname = 3
const idrecsz = 4
word globals = 0
word datasize = 0
word lastglobal
byte locals = 0
word framesize = 0
word lastlocal
const IS_RESOLVED = $8000
const IS_RELATIVE = $8000
const IS_CTAG = $8000
const MASK_CTAG = $7FFF
word codetag = -1
word codeptr, entrypoint = 0
word modsysflags = 0
byte lastop = $FF
//
// Scanner variables
//
const inbuff = $0200
const instr = $01FF
word scanptr = @nullstr
byte scanchr, token, tknlen
byte parserrpos, parserr = 0
word tknptr, parserrln
word constval
word lineno = 0
//
// Compiler output messages
//
byte dup_id[] = "DUPLICATE IDENTIFIER"
byte undecl_id[] = "UNDECLARED IDENTIFIER"
byte bad_cnst[] = "BAD CONSTANT"
byte bad_struc[] = "BAD STRUCTURE"
byte bad_offset[] = "BAD STRUCT OFFSET"
byte bad_decl[] = "BAD DECLARATION"
byte bad_op[] = "BAD OPERATION"
byte bad_stmnt[] = "BAD STATMENT"
byte bad_expr[] = "BAD EXPRESSION"
byte bad_syntax[] = "BAD SYNTAX"
byte local_overflw[] = "LOCAL FRAME OVERFLOW"
byte global_sym_overflw[] = "GLOBAL SYMBOL TABLE OVERFLOW"
byte local_sym_overflw[] = "LOCAL SYMBOL TABLE OVERFLOW"
byte ctag_full[] = "CODE LABEL OVERFLOW"
byte no_ctag_offst[] = "CODE OFFSET NOT SUPPORTED"
byte no_close_paren[] = "MISSING CLOSING PAREN"
byte no_close_bracket[] = "MISSING CLOSING BRACKET"
byte missing_op[] = "MISSING OPERAND"
byte no_fin[] = "MISSING FIN"
byte no_loop[] = "MISSING LOOP"
byte no_until[] = "MISSING UNTIL"
byte no_done[] = "MISSING DONE"
byte no_local_init[] = "NO INITIALIZED LOCALS"
//
// ProDOS/SOS file references
//
byte refnum, srcref, incref
byte[32] srcfile
byte[32] incfile
word parsefile // Pointer to current file
word sysincbuf // System I/O buffer for include files
word srcline // Saved source line number
//
// Parser variables
//
byte[128] strconst
byte infunc = 0
byte stack_loop = 0
byte prevstmnt = 0
word retfunc_tag = 0
word break_tag = 0
word cont_tag = 0
predef parse_constexpr(str,val), parse_expr
//=====================================
//
// PLASMA Compiler
//
//=====================================
//
// Error handler
//
def parse_err(errstr)
if !parserr
parserr = TRUE
parserrln = lineno - 1
parserrpos = tknptr - inbuff
puts(parsefile); putc('['); puti(lineno); putc(']'); putc(':'); puts(errstr); putln
puts(instr)
for i = parseerrpos-1 downto 0
putc(' ')
next
puts("^\n")
fin
return ERR_TKN
end
//
// Include code to reduce size of this file
//
include "toolsrc/codegen.pla"
include "toolsrc/lex.pla"
include "toolsrc/parse.pla"
//
// Look at command line arguments and compile module
//
arg = argNext(argFirst)
if arg
strcpy(@srcfile, arg)
if parsemodule
puts("Bytes compiled: "); puti(codeptr - codebuff); putln
fin
else
puts("Usage: +PLASM [srcfile]\n")
fin
done