// ResistParse.bcpl -- parse/unparse routines
// Last modified by McCreight June 25, 1984 10:48 AM
get "Resist.decl"
get "Streams.d"
external
[
// outgoing procedures
ReadResistFile; ReadWireListFile; UnparseIC
// incoming procedures
EncodeOhms; DecodeOhms
LookupOrDefineSymbol; DefineSymbol; LookupSymbol; InsertSymbol
SymbolsObject; ObjectsString; SymbolsString; CreateNet
ReportError; ExpandTemplate
FilePos; SetFilePos
Ws; Wss; Gets; Puts; Endofs; PutTemplate; DefaultArgs
Allocate; Free; Zero; MoveBlock
// outgoing statics
unknownNet
// incoming statics
dsp; sysZone; maxNPins
]
static [ unknownNet = 0 ]
manifest ecEof = 1302
manifest [ ok = 0; bad = 1; ignore = 2 ]
// ---------------------------------------------------------------------------
let ReadResistFile(stream, symbolTable, readingExceptions; numargs na) = valof
// ---------------------------------------------------------------------------
[
DefaultArgs(lv na, -2, false)
let firstIC = 0
let lvNextIC = lv firstIC
let locationString, tempString = vec 127, vec 127
stream>>ST.par1 = 0
let filePos = vec 1
stream>>ST.par2 = stream>>ST.error
stream>>ST.error = ReadTokenError
let symDIP3 = LookupOrDefineSymbol(symbolTable, "DIP3", stICPackage)
let symSIP = LookupOrDefineSymbol(symbolTable, "SIP", stICPackage)
if unknownNet eq 0 then unknownNet = CreateNet(symbolTable, "?")
let ic = Allocate(sysZone, lenIC + maxNPins*lenPin)
[ // repeat
FilePos(stream, filePos)
let token = ReadToken(stream, locationString)
if token eq -1 then break
if token eq $*n loop
let result = valof
[
if token ne 0 resultis bad
if ReadToken(stream, tempString) ne $( resultis bad
if ReadToken(stream, tempString) ne 0 resultis bad
ic>>IC.package =
LookupOrDefineSymbol(symbolTable, tempString, stICPackage)
if ReadToken(stream, tempString) ne $, resultis bad
unless ReadNumber(stream, lv ic>>IC.nPins) resultis bad
if ic>>IC.nPins ls 1 % ic>>IC.nPins gr maxNPins then
resultis ExpandTemplate("IC has too many pins -- only $D allowed.",
maxNPins)
// Ignore SIPs and bypass capacitors
if ic>>IC.package eq symSIP %
(ic>>IC.package eq symDIP3 & ic>>IC.nPins eq 2) resultis ignore
if ReadToken(stream, tempString) ne $, resultis bad
if ReadToken(stream, tempString) ne 0 resultis bad
for i = 1 to tempString>>String.length do
if tempString>>String.char↑i eq $/ then
[ tempString>>String.length = i-1; break ]
ic>>IC.type = LookupOrDefineSymbol(symbolTable, tempString, stICType)
if ReadToken(stream, tempString) ne $) resultis bad
for i = 1 to ic>>IC.nPins do
[
let pin = lv ic>>IC.pins↑i
let expectedOhms = nil
if ReadToken(stream, tempString) ne 0 resultis bad
unless GetNumber(tempString, lv expectedOhms) do
[
if tempString>>String.length ne 1 resultis bad
switchon tempString>>String.char↑1 into
[
case $$:
expectedOhms = open; endcase
case $?:
expectedOhms = unknown; endcase
default:
resultis bad
]
]
let token = ReadToken(stream, tempString)
if token eq $< then
[
token = ReadToken(stream, tempString) repeatuntil token eq $>
token = ReadToken(stream, tempString)
]
if token ne (i eq ic>>IC.nPins? $*n, $,) resultis bad
pin>>Pin.expectedOhmsCode = EncodeOhms(expectedOhms)
pin>>Pin.measuredOhmsCode = unknownCode
pin>>Pin.nextPin = lv unknownNet>>Net.dummyPin
]
resultis ok
]
switchon result into
[
case ignore:
until ReadToken(stream, tempString) eq $*n do loop
endcase
case ok:
[
let icSymbol = LookupSymbol(symbolTable, locationString)
test icSymbol eq 0
ifso unless readingExceptions do
[
let icObject = SymbolsObject(DefineSymbol(symbolTable,
locationString, stIC, ic, lenIC + ic>>IC.nPins*lenPin))
@lvNextIC = icObject
lvNextIC = lv icObject>>IC.next
icObject>>IC.next = 0
]
ifnot
[
unless readingExceptions do
[
result = ExpandTemplate("IC at $S defined multiple times.",
locationString)
docase bad
]
let icObject = SymbolsObject(icSymbol)
if ic>>IC.nPins ne icObject>>IC.nPins %
ic>>IC.package ne icObject>>IC.package %
ic>>IC.type ne icObject>>IC.type then
[
result = ExpandTemplate("Exceptions file inconsistent with Resist file for IC at $S.",
locationString)
docase bad
]
MoveBlock(lv icObject>>IC.pins, lv ic>>IC.pins,
ic>>IC.nPins*lenPin)
]
endcase
]
default:
Ws("*n")
SetFilePos(stream, filePos)
[ // repeat
let char = Gets(stream)
if char eq $*n % char eq -1 break
Puts(dsp, char)
] repeat
test result eq bad
ifso ReportError("Syntax error in $S file.",
(readingExceptions? "Exceptions", "Resist"))
ifnot [ ReportError(result); Free(sysZone, result) ]
stream>>ST.par1 = 0
endcase
]
] repeat
Free(sysZone, ic)
stream>>ST.error = stream>>ST.par2
resultis firstIC
]
// ---------------------------------------------------------------------------
and ReadWireListFile(stream, symbolTable) be
// ---------------------------------------------------------------------------
[
let netNameString, tempString = vec 127, vec 127
stream>>ST.par1 = 0
let filePos = vec 1
stream>>ST.par2 = stream>>ST.error
stream>>ST.error = ReadTokenError
let symCALIBRATE = LookupOrDefineSymbol(symbolTable, "CALIBRATE", stDummy)
let symDISCONNECT = LookupOrDefineSymbol(symbolTable, "DISCONNECT", stDummy)
until ReadToken(stream, tempString) eq 0 &
tempString>>String.length eq 1 & tempString>>String.char↑1 eq $@ do loop
[ // repeat
FilePos(stream, filePos)
let token = ReadToken(stream, netNameString, true)
if token eq -1 then break
if token eq $*n loop
let result = valof
[
if token ne 0 resultis bad
let length = netNameString>>String.length
if netNameString>>String.char↑length ne $: resultis bad
netNameString>>String.length = length-1
let netSymbol = LookupSymbol(symbolTable, netNameString)
if netSymbol eq symCALIBRATE % netSymbol eq symDISCONNECT then
resultis ignore
if netSymbol ne 0 then
resultis ExpandTemplate("Multiply-defined net: $S",
SymbolsString(netSymbol))
until ReadToken(stream, tempString) eq $*n do loop
let net, pLastNextPin = 0, nil
[ // repeat
let token = ReadToken(stream, tempString)
if token eq $*n then
[
token = ReadToken(stream, tempString)
if token eq $*n % token eq -1 resultis ok
]
if token ne 0 resultis bad
result = valof
[
let period = 0
for i = 1 to tempString>>String.length do
if tempString>>String.char↑i eq $. then period = i
if period eq 0 resultis ignore
let pinNumber = 0
for i = period+1 to tempString>>String.length do
[
let digit = tempString>>String.char↑i - $0
if digit ls 0 % digit gr 9 then
test i eq tempString>>String.length
ifso break
ifnot resultis ExpandTemplate("Illegal pin name: $S",
tempString)
pinNumber = 10*pinNumber + digit
]
tempString>>String.length = period-1
let icSymbol = LookupSymbol(symbolTable, tempString)
if icSymbol eq 0 resultis ignore
let ic = SymbolsObject(icSymbol)
if pinNumber ls 1 % pinNumber gr ic>>IC.nPins then
resultis ExpandTemplate("Pin number $D illegal for IC at $S",
pinNumber, SymbolsString(icSymbol))
let pin = lv ic>>IC.pins↑pinNumber
if net eq 0 then
[
net = CreateNet(symbolTable, netNameString)
pLastNextPin = lv net>>Net.firstPin
]
@pLastNextPin = pin
pLastNextPin = lv pin>>Pin.nextPin
pin>>Pin.nextPin = lv net>>Net.dummyPin
resultis ok
]
unless result eq ok % result eq ignore resultis result
until ReadToken(stream, tempString) eq $} do loop
] repeat
]
switchon result into
[
case ok:
endcase
case ignore:
[ // repeat
let token = ReadToken(stream, tempString)
if token eq $*n then
if ReadToken(stream, tempString) eq $*n then endcase
if token eq -1 then endcase
] repeat
default:
Ws("*n")
SetFilePos(stream, filePos)
[ // repeat
let char = Gets(stream)
if char eq $*n % char eq -1 break
Puts(dsp, char)
] repeat
test result eq bad
ifso ReportError("Syntax error in Wire List file.")
ifnot [ ReportError(result); Free(sysZone, result) ]
stream>>ST.par1 = 0
endcase
]
] repeat
stream>>ST.error = stream>>ST.par2
]
// ---------------------------------------------------------------------------
and ReadToken(stream, string, dontStopOnParen; numargs na) = valof
// ---------------------------------------------------------------------------
// Reads the next token from the input stream.
// If the token is a separator character, returns it.
// If the token is an atom, copies it into string and returns zero.
// If end of file has been reached, returns -1.
// Separator characters are: { } < > , *n
// plus ( ) if dontStopOnParen is false (the default).
// Ignores comments (beginning with ;) and spaces between tokens.
[
let char = stream>>ST.par1
stream>>ST.par1 = 0
let length = 0
[ // repeat
switchon char into
[
case $*s:
if length ne 0 then [ char = 0; break ]
endcase
case $;:
char = Gets(stream) repeatuntil char eq $*n % char eq -1
docase char
case $(: case $):
if na ge 3 & dontStopOnParen then docase $A // docase default
case $<: case $>:
case ${: case $}:
case $,: case $*n: case -1:
if length eq 0 break
stream>>ST.par1 = char
char = 0
break
default:
length = length+1
string>>String.char↑length = char
case 0:
endcase
]
char = Gets(stream)
] repeat
string>>String.length = length
resultis char
]
// ---------------------------------------------------------------------------
and ReadTokenError(stream, ec) =
// ---------------------------------------------------------------------------
ec eq ecEof? -1, stream>>ST.par2(stream, ec)
// ---------------------------------------------------------------------------
and ReadNumber(stream, lvNumber, radix; numargs na) = valof
// ---------------------------------------------------------------------------
[
if na ls 3 then radix = 10
let tempString = vec 127
if ReadToken(stream, tempString) ne 0 resultis false
resultis GetNumber(tempString, lvNumber, radix)
]
// ---------------------------------------------------------------------------
and GetNumber(string, lvNumber, radix; numargs na) = valof
// ---------------------------------------------------------------------------
// Converts string to a number and stores the result in @lvNumber.
// Returns true normally, false if string wasn't a number.
[
if na ls 3 then radix = 10
let number = 0
for i = 1 to string>>String.length do
[
let digit = string>>String.char↑i - $0
if digit ls 0 % digit ge radix resultis false
number = 10*number + digit
]
@lvNumber = number
resultis true
]
// ---------------------------------------------------------------------------
and UnparseIC(stream, ic) be
// ---------------------------------------------------------------------------
// Unparses ic and sends the result to stream.
[
PutTemplate(stream, "$S ($S, $D, $S)", ObjectsString(ic),
SymbolsString(ic>>IC.package), ic>>IC.nPins, SymbolsString(ic>>IC.type))
for i = 1 to ic>>IC.nPins do
[
Wss(stream, (i eq 1? " ", ", "))
let pin = lv ic>>IC.pins↑i
switchon pin>>Pin.expectedOhmsCode into
[
case openCode:
Puts(stream, $$); endcase
case unknownCode:
Puts(stream, $?); endcase
default:
PutTemplate(stream, "$D", DecodeOhms(pin>>Pin.expectedOhmsCode)); endcase
]
]
Puts(stream, $*n)
]