!Graham Toal - last working version of SKIMPA 10/02/81 11.57
external string (127) fn spec cliparam
external integer fn spec outstream
external routine spec resetinput
const string (1) snl = "
"
external integer spec faults
routine do(string (127) text)
!?%EXTERNALROUTINESPEC M6809
!! For invoking assembler after successful compilation...
! system(text)
printstring(text); newline
end
external integer array a(1 : 500)
! initialisation for i/o routines
external byte integer array named(1 : 1024) = c
10, 'R', 'E', 'A', 'D', 'S', 'Y', 'M', 'B', 'O', 'L',
10, 'N', 'E', 'X', 'T', 'S', 'Y', 'M', 'B', 'O', 'L',
10, 'S', 'K', 'I', 'P', 'S', 'Y', 'M', 'B', 'O', 'L',
11, 'P', 'R', 'I', 'N', 'T', 'S', 'Y', 'M', 'B', 'O', 'L',
5, 'S', 'P', 'A', 'C', 'E',
6, 'S', 'P', 'A', 'C', 'E', 'S',
7, 'N', 'E', 'W', 'L', 'I', 'N', 'E',
8, 'N', 'E', 'W', 'L', 'I', 'N', 'E', 'S',
7, 'N', 'E', 'W', 'P', 'A', 'G', 'E',
4, 'R', 'E', 'A', 'D',
5, 'W', 'R', 'I', 'T', 'E',
0(930)
external integer array namedlink(0 : 255) = 0, 76, 0(12), 89, 0(54), 84,
0(118), 52, 0(11), 1, 12, 23, 34, 0(4), 67, 0(23), 46, 0(5), 59, 0(17)
external integer array taglink(0 : 255) = 0, 13, 0(12), 16, 0(54), 14,
0(118), 8, 0(11), 1, 3, 4, 5, 0(4), 11, 0(23), 7, 0(5), 10, 0(17)
external integer array tag(1 : 512) = 16_40100001, 16_11010002, 16_41000002,
16_40000003, 16_40100004, 16_01010002, 16_40000005, 16_40100006, 16_01010002,
16_40000007, 16_40100008, 16_01010002, 16_40000009, 16_4010000A, 16_11010002,
16_4020000B, 16_01010002, 16_01010003, 0(494)
external integer array link(1 : 512) = 2, 0, 0, 0, 6, 0, 0, 9, 0, 0, 12, 0,
0, 15, 0, 17, 18, 0, 0(494)
external integer namedp = 95
external integer tagasl = 19
external integer expropt = 0
external integer condopt = 0
external integer tagsopt = 0
external integer traceopt = 0
external integer checkopt = 0
external integer infoopt = 0
!-----------------------------------------------------------------------
external routine spec statement(integer statementp)
external string (255) fn spec strint(integer n, p)
external routine spec fault(string (63) mess)
external routine spec dump(string (7) opn, reg, base, integer disp)
external string (255) fn spec name(integer ident)
!-----------------------------------------------------------------------
external routine skimp
string (63) s, param
routine spec readps
routine spec readstatement
routine spec rpsym(integer name l)
integer fn spec findk(string (*) name k)
integer fn spec compare(integer p)
record format kdf(byte integer l, n, a, b)
record (kdf) array kd(1 : 255)
string (15) array pn(256 : 319)
integer array pp(256 : 319)
integer array ps(1 : 512)
integer array t, tt(1 : 256)
integer tp, ap, ttp, i, j, psflag
string (63) file, options, option, as
own integer lexopt = 0
own integer analopt = 0
own integer codeopt = 1
own integer listopt = 1
own integer assmopt = 0
own integer shift = 32
own string (63) assopt = ""
s = cliparam
if s -> ("/") . options then start
unless options -> options . (" ") . file then file = ""
cycle
unless options -> option . ("/") . options then c
option = options and options = ""
if option -> ("NO") . option then i = 0 else i = 1
if option = "LEX" then lexopt = i and continue c
else if option = "ANAL" then analopt = i and continue c
else if option = "EXPR" then expropt = i and continue c
else if option = "COND" then condopt = i and continue c
else if option = "TAGS" then tagsopt = i and continue else start
if option -> ("OPT=") . assopt then assmopt = i and continue c
else if option = "TRACE" then traceopt = i and continue c
else if option = "CHECK" then checkopt = i and continue c
else if option = "LIST" then listopt = i and continue c
else if option = "CODE" then codeopt = i and continue c
else if option = "INFO" then infoopt = i and continue
finish
printstring(option . " OPTION ?
")
stop
repeat until options = ""
finish else file = s
on event 9, 13 start
closeinput
closeoutput
printstring("FILE NOT FOUND - OR SOME OTHER ERROR!" . snl) ;! %if event_event = 9
stop if file = "" or codeopt = listopt = 0 or faults > 0
param = ""
if codeopt = 0 then param = param . "/NOOBJECT"
if listopt = 1 then param = param . "/LIST"
do("ass68 " . file . " " . param)
stop
finish
readps
if file = "" then openoutput(1, "/dev/stdout") else openoutput(1, file . ".asm")
selectoutput(1)
printstring(" NAM " . file . snl) if file # ""
printstring(" OPT " . assopt . snl) if assmopt = 1
printstring("
* File: " . file . "
* Options: ")
if lexopt = 1 then printstring("/LEX ")
if analopt = 1 then printstring("/ANAL ")
if expropt = 1 then printstring("/EXPR ")
if condopt = 1 then printstring("/COND ")
if tagsopt = 1 then printstring("/TAGS ")
if infoopt = 1 then printstring("/INFO ")
if traceopt = 1 then printstring("/TRACE ")
if checkopt = 1 then printstring("/CHECK ")
if listopt = 0 then printstring("/NOLIST ")
if codeopt = 0 then printstring("/NOCODE ")
if assmopt = 1 then printstring("/OPT=" . assopt)
newline
if psflag # 0 then fault("PHRASE STRUCTURE FAULTY") and stop
if file = "" then openinput(1, "/dev/stdout") else openinput(1, file . ".imp")
selectinput(1)
! set up tags available space list
for i = tagasl, 1, 511 cycle
link(i) = i + 1
repeat
! PRINTSTRING(" NAM ".FILE.SNL) %IF FILE#""
! PRINTSTRING(" OPT ".ASSOPT.SNL) %IF ASSMOPT=1
cycle
! for each statement
readstatement
ttp = tp - 1
tp = 1
ap = 1
if compare(259) = 0 or tp # ttp then fault("SYNTAX ?") else start
!**FRIG** above for printtext...
if analopt = 1 then start
newline
j = 0
for i = 1, 1, ap - 1 cycle
! print analysis record
if a(i) < 0 then as = " (" . strint(i, 1) . "/" . pn(a(i) << 1 >> 17) . ")" c
and printstring(as) and j = j + length(as) and a(i) = a(i) & 16_FFFF
write(a(i), 4)
j = j + 5
if j > 60 then newline and j = 0
repeat
newlines(2)
finish else start
for i = 1, 1, ap - 1 cycle
! remove phrase numbers
if a(i) < 0 then a(i) = a(i) & 16_FFFF
repeat
finish
statement(1)
! generate code for statement
finish
repeat
!-----------------------------------------------------------------------
routine readps
! read phrase structure from file 'SKIMPPS' and reduce it
string (31) array ka(1 : 128)
integer array kna(1 : 128)
string (31) k
integer kap, kdasl, kn, i, l, psp, pnp, alt
integer name np
routine spec insert(string (15) k)
routine spec extract(integer i, string (15) k)
routine spec assign(integer i)
integer fn spec newkd
routine spec returnkd(integer i)
routine spec returnlist(integer i)
integer fn spec phrase
routine spec literal
routine spec keyword
openinput(2, "skimpps.new")
selectinput(2)
if infoopt = 1 then openoutput(2, "skimpps.lis") else openoutput(2, "/dev/null")
selectoutput(2)
printstring("
PHRASE STRUCTURE
")
! scan file to build keyword dictionary
kap = 1
cycle
rpsym(l)
if l = '$' then exit
if l = '"' then start
k = ""
cycle
rpsym(l)
if l = '"' then exit
if 'A' <= l <= 'Z' then k = k . tostring(l)
repeat
ka(kap) = k
kap = kap + 1
finish
repeat
for i = 1, 1, 26 cycle
kd(i) = 0
repeat
for i = 27, 1, 254 cycle
kd(i)_b = i + 1
repeat
kdasl = 27
i = 1
insert(ka(i)) and i = i + 1 until i = kap
kn = 128
for i = 1, 1, 26 cycle
if kd(i)_l # 0 then assign(i)
repeat
kap = 1
for i = 1, 1, 26 cycle
if kd(i)_l # 0 then extract(i, "")
repeat
printstring("
KEYWORDS
")
for i = 1, 1, kap - 1 cycle
printstring(strint(kna(i), 3) . " " . ka(i) . "
")
repeat
! reread file and reduce phrase structure
resetinput
pn(256) = "NAME"
pp(256) = 0
pn(257) = "CONST"
pp(257) = 0
pn(258) = "STRING"
pp(258) = 0
pnp = 259
psp = 1
cycle
! for each phrase definition
readsymbol(l)
if l = '$' then exit
if l = '<' then start
! start of phrase definition
pp(phrase) = psp
cycle
! for each alternative
alt = psp
np == ps(psp + 1)
np = 0
! number of phrases
psp = psp + 2
cycle
! for each item
readsymbol(l)
if l = '<' then ps(psp) = phrase and psp = psp + 1 and np = np + 1
if l = '''' then literal
if l = '"' then keyword
if l = ',' or l = ';' then exit
repeat
ps(alt) = psp
if l = ';' then exit
repeat
ps(psp) = 0
psp = psp + 1
finish
repeat
psflag = 0
for i = 259, 1, pnp - 1 cycle
if pp(i) = 0 then fault("<" . pn(i) . "> NOT DEFINED") and psflag = 1
repeat
printstring("
PHRASES
")
for i = 256, 1, pnp - 1 cycle
printstring(strint(i, 3) . strint(pp(i), 6) . " " . pn(i) . "
")
repeat
printstring("
REDUCED PHRASE STRUCTURE
")
for i = 1, 1, psp - 1 cycle
if (i - 1) & 15 = 0 then printstring("
" . strint(i, 3) . " ")
write(ps(i), 3)
repeat
newlines(2)
return
!-----------------------------------------------------------------------
routine insert(string (15) k)
! search for and insert keyword into dictionary
integer i, j, l
l = charno(k, 1)
k -> (tostring(l)) . k
i = l - 'A' + 1
if kd(i)_l # 0 then start
search:
if k = "" then start
if kd(i)_a # 0 then extract(kd(i)_a, "") c
and returnlist(kd(i)_a) and kd(i)_a = 0
return
finish
if kd(i)_a = 0 then insert(k) and return
l = charno(k, 1)
k -> (tostring(l)) . k
i = kd(i)_a
cycle
if kd(i)_l = l then -> search
if kd(i)_b = 0 then exit
i = kd(i)_b
repeat
j = i
i = newkd
kd(j)_b = i
finish
! insert remainder of letters
cycle
kd(i)_l = l
if k = "" then return
l = charno(k, 1)
k -> (tostring(l)) . k
j = i
i = newkd
kd(j)_a = i
repeat
end
!-----------------------------------------------------------------------
routine extract(integer i, string (15) k)
string (15) kk
if i = 0 then return
kk = k . tostring(kd(i)_l)
if kd(i)_a = 0 then ka(kap) = kk and kna(kap) = kd(i)_n c
and kap = kap + 1 else extract(kd(i)_a, kk)
extract(kd(i)_b, k)
end
!-----------------------------------------------------------------------
routine assign(integer i)
if i = 0 then return
if kd(i)_a = 0 then kd(i)_n = kn and kn = kn + 1 else assign(kd(i)_a)
assign(kd(i)_b)
end
!-----------------------------------------------------------------------
integer fn newkd
integer i
if kdasl = 0 then printstring("KD ASL EMPTY") and stop
i = kdasl
kdasl = kd(i)_b
kd(i) = 0
result = i
end
!-----------------------------------------------------------------------
routine returnkd(integer i)
kd(i)_b = kdasl
kdasl = i
end
!-----------------------------------------------------------------------
routine returnlist(integer i)
if i = 0 then return
returnlist(kd(i)_a)
returnlist(kd(i)_b)
returnkd(i)
end
!-----------------------------------------------------------------------
integer fn phrase
string (15) p
integer i, l
p = ""
cycle
readsymbol(l)
if l = '>' then exit else p = p . tostring(l)
repeat
for i = 256, 1, pnp - 1 cycle
if pn(i) = p then result = i
repeat
pn(pnp) = p
pp(pnp) = 0
pnp = pnp + 1
result = pnp - 1
end
!-----------------------------------------------------------------------
routine literal
integer l
cycle
readsymbol(l)
if l = '''' then return else ps(psp) = l and psp = psp + 1
repeat
end
!-----------------------------------------------------------------------
routine keyword
string (31) k
integer l
k = ""
cycle
readsymbol(l)
if l = '"' then exit
if 'A' <= l <= 'Z' then k = k . tostring(l)
repeat
ps(psp) = findk(k) and psp = psp + 1 until k = ""
end
end
!-----------------------------------------------------------------------
routine readstatement
routine spec store(integer l)
routine spec keyword
routine spec name
routine spec const
routine spec stringconst
integer i, l, ksh, ttp, ttpp
! line reconstruct phase
newlines(2)
ttp = 1
ksh = 0
cycle
! for each character
rpsym(l)
if l = '%' then ksh = 128 else start
unless 'A' <= l <= 'Z' then ksh = 0
if l # ' ' then start
! discard spaces
if l = '!' and ttp = 1 then start
rpsym(l) until l = ';' or l = nl
! discard comments
finish else start
store(l)
if l = '"' then start
shift = 0
rpsym(l) and store(l) until l = '"'
shift = 32
finish else start
if l = '''' then start
shift = 0
rpsym(l) and store(l) until l = ''''
shift = 32
finish else start
if l = ';' or l = nl then start
if ttp = 2 then ttp = 1 else start
if l = ';' then newline and exit
if tt(ttp - 2) = 'C' + 128 then ttp = ttp - 2 else exit
finish
finish
finish
finish
finish
finish
finish
repeat
! lexical phase
tp = 1
ttpp = 1
cycle
! for each lexical item
i = tt(ttpp)
if i >= 128 then keyword else start
if 'A' <= i <= 'Z' then name else start
if i = '"' then stringconst else start
if '0' <= i <= '9' or i = '''' or i = '$' then c
const else t(tp) = i and tp = tp + 1 and ttpp = ttpp + 1
finish
finish
finish
repeat until ttpp = ttp
if lexopt = 1 then start
newline
for ttpp = 1, 1, tp - 2 cycle
write(t(ttpp), 4)
if ttpp & 16_F = 0 then newline
repeat
newline
finish
return
!-----------------------------------------------------------------------
routine store(integer l)
if ttp > 256 then fault("STATEMENT TOO LONG") and stop
tt(ttp) = l + ksh
ttp = ttp + 1
end
!-----------------------------------------------------------------------
routine keyword
string (255) k
integer i
k = ""
while tt(ttpp) > 128 then k = k . tostring(tt(ttpp) - 128) and ttpp = ttpp + 1
i = findk(k) and t(tp) = i and tp = tp + 1 until k = "" or i = 0
end
!-----------------------------------------------------------------------
routine name
string (*) name sname
integer i, l, hash
sname == string(addr(named(namedp)))
hash = 0
sname = ""
l = tt(ttpp)
cycle
if namedp + length(sname) >= 1022 then fault("NAME DICTIONARY FULL") and stop
if length(sname) = 255 then fault("NAME TOO LONG") and stop
sname = sname . tostring(l)
hash = hash << 8 ! l
ttpp = ttpp + 1
l = tt(ttpp)
repeat until l < '0' or '9' < l < 'A' or l > 'Z'
hash = hash - hash // 251 * 251
i = hash
cycle
! scan dictionary
if namedlink(i) = 0 then namedlink(i) = namedp c
and namedp = namedp + length(sname) + 1 and exit
! insert name
if sname = string(addr(named(namedlink(i)))) then exit
i = (i + 1) & 255
if i = hash then fault("NAME DICTIONARY FULL") and stop
repeat
t(tp) = 256
! <name>
t(tp + 1) = i
! ident
tp = tp + 2
end
!-----------------------------------------------------------------------
routine const
integer l, value, flag, count, maxby10, maxld
value = 0
flag = 0
if tt(ttpp) = '$' then start
cycle
ttpp = ttpp + 1
exit unless '0' <= tt(ttpp) <= '9' or 'A' <= tt(ttpp) <= 'F'
if tt(ttpp) < 'A' then value = value << 4 ! (tt(ttpp) - '0') c
else value = value << 4 ! (tt(ttpp) - 'A' + 10)
flag = 1 and exit if value > 16_FFFF
repeat
finish else start
if tt(ttpp) = '''' then start
count = 0
cycle
ttpp = ttpp + 1
if tt(ttpp) = '''' then start
ttpp = ttpp + 1
if tt(ttpp) # '''' then exit
finish
value = value << 8 ! tt(ttpp)
count = count + 1
repeat
unless count <= 2 then flag = 1
! Only one char per word on M6809
finish else start
maxby10 = 16_7FFF // 10
maxld = 16_7FFF - maxby10 * 10 + '0'
! Bug fixed.
l = tt(ttpp)
cycle
if value > maxby10 or (value = maxby10 and l > maxld) c
then flag = 1 else value = value * 10 + l - '0'
ttpp = ttpp + 1
l = tt(ttpp)
repeat until l < '0' or l > '9'
finish
finish
t(tp) = 257
! <const>
if flag # 0 then fault("CONSTANT INVALID") and value = 0
t(tp + 1) = value
tp = tp + 2
end
!-----------------------------------------------------------------------
routine stringconst
t(tp) = 258
! <STRING>
if tt(ttpp) # '"' then start
fault("INVALID STRING")
t(tp + 1) = 16_80
return
finish
cycle
tp = tp + 1
! Skip the first quote
ttpp = ttpp + 1
if tt(ttpp) = '"' then start
if tt(ttpp + 1) = '"' then ttpp = ttpp + 1 c
and t(tp) = '"' and continue
t(tp) = 16_80
tp = tp + 1
ttpp = ttpp + 1
return
finish
t(tp) = tt(ttpp)
repeat
end
end
!-----------------------------------------------------------------------
routine rpsym(integer name l)
own integer flag = 1
readsymbol(l)
if flag = 1 and outstream = 1 then printstring("* ") and flag = 0
printsymbol(l)
if outstream = 1 and l = ';' and shift # 0 then newline
if outstream = 1 and (l = nl or (l = ';' and shift # 0)) then flag = 1
if 'a' <= l <= 'z' then l = l !! shift
end
!-----------------------------------------------------------------------
integer fn findk(string (*) name k)
! look keyword up in dictionary
integer i, l
l = charno(k, 1)
k -> (tostring(l)) . k
i = l - 'A' + 1
if kd(i)_l = 0 then result = 0
search:
if k = "" or kd(i)_a = 0 then result = kd(i)_n
l = charno(k, 1)
k -> (tostring(l)) . k
i = kd(i)_a
cycle
if kd(i)_l = l then -> search
if kd(i)_b = 0 then result = 0
i = kd(i)_b
repeat
end
!-----------------------------------------------------------------------
integer fn compare(integer p)
integer app, tpp, alt, altend, psp, psi
a(ap) = p << 16 ! 16_80000001
! phrase number & alternative 1
if p <= 257 then start
! <name> or <const>
if p = t(tp) then start
! success
a(ap + 1) = t(tp + 1)
ap = ap + 2
tp = tp + 2
result = 1
finish else result = 0
finish
if p = 258 then start
if t(tp) # p then result = 0
alt = 1
a(ap + alt) = t(tp + alt) and alt = alt + 1 until t(tp + alt) = 16_80
a(ap + alt) = 16_80
ap = ap + alt + 1
tp = tp + alt + 1
result = 1
finish
tpp = tp
! preserve text pointer
app = ap
! preserve analysis record pointer
psp = pp(p)
! start of phrase definition
cycle
! for each alternative
alt = ap + 1
altend = ps(psp)
ap = alt + ps(psp + 1)
! leave gap for forward pointers
if ap > 255 then fault("ANALYSIS RECORD TOO LONG") and stop
psp = psp + 2
cycle
! for each item
if psp = altend then result = 1
! success
psi = ps(psp)
if psi >= 256 then start
! phrase
a(alt) = ap
! forward pointer
if compare(psi) = 0 then exit
alt = alt + 1
finish else start
! literal or keyword
if psi # t(tp) then exit
tp = tp + 1
finish
psp = psp + 1
repeat
if ps(altend) = 0 then result = 0
! failure
psp = altend
tp = tpp
! backtrack text pointer
ap = app
! backtrack analysis record pointer
a(ap) = a(ap) + 1
! next alternative number
repeat
end
end of program