// BLEX2.bcpl - BCPL Complier -- Lexical Analyzer,part 2 // Copyright Xerox Corporation 1980 // Swinehart, 5-10-77: docase exp, remove wenn, dann, sonst, probieren // last modified by Butterfield, May 8, 1979 7:24 PM // - incorporate Paxton's unsigned compares under SWUnsignedCompares - 5/8 // - LexWrite, formatting and write symbol information with END - 1/24 // - add from for use by get a, b, ... from "file" - 1/23/79 // Paxton, 9-14-78: unsigned compares // ReservedWord // Look up string as a reserved word // *veq // Test for string equality // * local to this file get "blexx" static [ W = nil //pointer to the string that veq compares its argument with N = nil //length of this string ] let ReservedWord(Name) = valof [ unless V!0 gr 1 resultis 0 // All reserved words have at least two letters let w = vec (NAMELENGTH/Bytesperword); W = w let ch = V!1 // The first char of the word V!1 = V!0 - 1; Packstring(V+1,W); N = V!1/Bytesperword // The rest of the word V!1 = ch // Restore V for use in Readsymb resultis selecton ch into // Look up the word [ default: 0 case $a: ( veq("nd" )?AND, ( veq("bort" )?ABORT, 0)) case $b: ( veq("e" )?BE, ( veq("y" )?BY, ( veq("reak" )?BREAK, ( veq("it" )?BIT, ( veq("yte" )?BYTE, ( veq("lank" )?BLANK, 0)))))) case $c: ( veq("ase" )?CASE, ( veq("ompileif" )?COMPILEIF, ( veq("ompiletest")?COMPILETEST, 0))) ///*DCS* add compileif, compiletest case $d: ( veq("efault" )?DEFAULT, ( veq("o" )?DO, ( veq("ocase" )?DOCASE, 0))) case $e: ( veq("q" )?EQ, ( veq("qv" )?EQV, ( veq("xternal" )?EXT, ( veq("ndcase" )?ENDCASE, 0)))) case $f: ( veq("or" )?FOR, ( veq("alse" )?FALSE, ( veq("inish" )?FINISH, ( veq("rom" )?FROM, 0)))) case $g: ( veq("e" )?GE, ( veq("r" )?GR, ( veq("et" )?GET, ( veq("oto" )?GOTO, 0)))) case $h: (0) case $i: ( veq("f" )?IF, ( veq("fso" )?IFSO, ( veq("fnot" )?IFNOT, ( veq("nto" )?INTO, 0)))) case $j: (0) case $k: (0) case $l: ( veq("et" )?LET, ( veq("e" )?LE, ( veq("s" )?LS, ( veq("v" )?LV, ( veq("oop" )?LOOP, ( veq("ogand" )?LOGAND, ( veq("ogor" )?LOGOR, ( veq("ogeqv" )?EQV, ( veq("ogxor" )?NEQV, ( veq("shift" )?LSHIFT, 0)))))))))) case $m: ( veq("anifest" )?MANIFEST, 0) case $n: ( veq("e" )?NE, ( veq("eg" )?NEG, ( veq("il" )?NIL, ( veq("ot" )?NOT, ( veq("eqv" )?NEQV, ( veq("umargs" )?NUMARGS, ( veq("ewname" )?NEWNAME, 0))))))) case $o: ( veq("r" )?OR, ( veq("ffset" )?OFFSET, 0)) case $p: (0) case $q: (0) case $r: ( veq("v" )?RV, ( veq("eturn" )?RETURN, ( veq("esultis" )?RESULTIS, ( veq("epeat" )?REPEAT, ( veq("epeatwhile" )?REPEATWHILE, ( veq("epeatuntil" )?REPEATUNTIL, ( veq("em" )?REM, ( veq("shift" )?RSHIFT, 0)))))))) case $s: ( veq("witchon" )?SWITCHON, ( veq("tatic" )?STATIC, ( veq("ize" )?SIZE, ( veq("tep" )?BY, ( veq("electon" )?SELECTON, ( veq("tructure" )?STRUCTURE, 0)))))) case $t: ( veq("o" )?TO, ( veq("est" )?TEST, ( veq("rue" )?TRUE, ( veq("hen" )?DO, ( veq("able" )?TABLE, 0))))) case $u: ( veq("nless" )?UNLESS, ( veq("ntil" )?UNTIL, (SWUnsignedCompares & veq("ls" )?ULS, (SWUnsignedCompares & veq("le" )?ULE, (SWUnsignedCompares & veq("gr" )?UGR, (SWUnsignedCompares & veq("ge" )?UGE, 0)))))) case $v: ( veq("ec" )?VEC, ( veq("alof" )?VALOF, 0)) case $w: ( veq("hile" )?WHILE, ( veq("ord" )?WORD, 0)) case $x: ( veq("or" )?NEQV, 0) case $y: (0) case $z: (0) ] ] and veq(s) = valof // Compare the arg to W [ unless rv W eq rv s resultis false // Quick test on first words (including length) let w = W + 1 s = s + 1 for i = 1 to N do [ unless rv w eq rv s resultis false w = w + 1; s = s + 1 ] resultis true ] // The parameter Item of the following routine contains a lexeme and the data for insertion // of SEMICOLON or DO, packed like this... // bits 2-3 (0 ? never, 1 ? may, 2 ? must) begin a command // bits 4-5 (0 ? never, 1 ? may, 2 ? must) end a command // bits 8-15 the numeric lexeme itself. // Two kinds of processing are done... // 1.If last item may or must end a command and this item may begin a command and a NEWLINE // has intervened between them, insert a SEMICOLON before this item. // 2. If last item may end a command and this one must begin one, insert a DO before this one. // The lexeme is written on the LEX file (one byte) // followed by the V information,if any // followed by the line pointer and LexOut(Item) be // Include canonic symbol Item in the lexical stream. [ Symb = Item // Unpack the lexeme fields let Beg = (Item & #1400) rshift 8 // (this item) doesn"t, may, does begin a command and End = (LastItem & #6000) rshift 10 // (the last item) doesn"t, may, does end a command test NLPending ifso if Beg>0 & End>0 do // We have a carr.ret. between commands [ ReadAhead, ExtraItem = true, Item // Remember this item Symb = SEMICOLON; LexWrite(Symb) // and output a SEMICOLON ] ifnot if Beg eq 2 & End eq 1 do // We are at the start of a command and need a DO [ ReadAhead, ExtraItem = true, Item // Remember this item Symb = DO; LexWrite(Symb) // and output a DO ] if NLPending do LexWrite(LINE) unless ReadAhead do LexWrite(Item) // If no extra item, output the lexeme LastItem = Item // Remember this item for next time NLPending = false // Reset NLPending ] //---------------------------------------------------------------------------- and LexWrite(item) be // Write the lexeme, perhaps with info from V //---------------------------------------------------------------------------- [ switchon item into [ case AND: case DO: case OR: case IFSO: case IFNOT: case INTO: LexWrite(SEMICOLON); ] Writech(LexStream, item & #377); LexLength = LexLength + 1; if SWLexTrace do [ WriteS("*t*******s"); ] switchon item into [ case NAME: [ Writeaddr(LexStream, V!0); LexLength = LexLength + 2; if SWLexTrace then [ WriteS("NAME "); WriteS(lv (Dictionary!(V!0))); WriteO(V!0); ] endcase ] case LINE: [ Writeaddr(LexStream, NewLineptr+1); LexLength = LexLength + 2; if SWLexTrace then [ WriteS("LINE "); WriteO(NewLineptr+1); ] endcase ] case END: [ Writeaddr(LexStream, V!0); LexLength = LexLength + 2; if SWLexTrace then [ WriteS("END "); WriteO(V!0); ] endcase ] case CHARCONST: case NUMBER: [ Writeword(LexStream, V!0); LexLength = LexLength + 2; if SWLexTrace then [ WriteN(item & #377); WW($*s); WriteO(V!0); ] endcase ] case NAMEBRA: case NAMEKET: case STRINGCONST: [ for i = 0 to Length(V)/Bytesperword do [ Writeword(LexStream, V!i); LexLength = LexLength + 2; ] if SWLexTrace then [ WriteN(item & #377); WW($*s); WriteS(V); ] endcase ] default: if SWLexTrace then WriteN(item & #377); ] if SWLexTrace then WW($*n); ] and DoString() be [ let Type = Ch // Remember what it was. and Vp = 0 // A counter and VV = vec StringLength // A place to put the characters of the string. [ Rch() if Ch eq Type & Type eq $*" do // Just read the end of a string. [ VV!0 = Vp; Packstring(VV, V) // Pack the string into V. LexOut(STRINGCONST) return ] if Vp > StringLength % Ch eq #777 % Ch eq $*n do [ LEXreport(9) V!0 = "?"!0 LexOut(STRINGCONST) return ] if Ch eq $** do [ Rch() Ch = valof [ switchon Ch into [ default: LEXreport(10); resultis Ch case $*": resultis #42 case $**: resultis #52 case $C: case $c: resultis #15 case $L: case $l: resultis #12 case $S: case $s: resultis #40 // space case $T: case $t: resultis #11 case $N: case $n: resultis #15 // new line case $0: case $1: case $2: case $3: // Octal escape. case $4: case $5: case $6: case $7: [ let t = Ch & 7 Rch() t = (t lshift 3) + (Ch&7) Rch() t = (t lshift 3) + (Ch&7) unless t le #377 do LEXreport(6) resultis t ] ] ] ] Vp = Vp + 1; VV!Vp = Ch // Store the character. if Type eq $*" loop // Keep reading a string constant. V!0 = Ch; LexOut(CHARCONST) return ] repeat ] and Kind(Chr) = valof [ if Chr ge $a & Chr le $z resultis Small if Chr ge $A & Chr le $Z resultis Capital if Chr ge $0 & Chr le $9 resultis Digit if Chr eq $*s % Chr eq $*t % Chr eq 0 resultis Ignorable if Chr eq #32 resultis BravoTail // ↑Z resultis Simple ] and DoNumber(radix) = valof [ let n = 0 ///*DCS* for command line manifests -- see LEX0 let flag = false if radix < 0 then [ flag = true radix = -radix ] V!0 = 0 while $0 le Ch & Ch ls ($0 + radix) do [ V!0 = V!0 + 1; V!(V!0) = Ch; Rch() ] if V!0 gr 6 do LEXreport(6) test Ch eq $B % Ch eq $b ifnot test radix eq 8 then n = Ovalue(V) or n = Dvalue(V) ifso [ n = Ovalue(V) let m = 0 Rch() if $0 le Ch & Ch le $9 do [ m = Ch-$0 Rch() if $0 le Ch & Ch le $9 do [ m = m*10 + (Ch-$0) Rch() ] ] unless m le 15 do LEXreport(6) let t = n lshift m unless (t rshift m) eq n do LEXreport(6) n = t ] ///*DCS* flag test for command line manifests V!0 = n; unless flag do LexOut(NUMBER) Chkind = Kind(Ch) resultis n ] and Ovalue(v) = valof [ let n = 0 for i = 1 to v!0 do [ unless $0 le v!i & v!i le $7 do [ LEXreport(6); resultis n ] let t = (n lshift 3) + (v!i-$0) unless (t rshift 3) eq n do [ LEXreport(6); resultis t ] n = t ] resultis n ] and Dvalue(v) = valof [ let n = 0 for i = 1 to v!0 do [ unless $0 le v!i & v!i le $9 do [ LEXreport(6); resultis n ] let t = n*10 + (v!i-$0) unless t/10 eq n do [ LEXreport(6); resultis t ] n = t ] resultis n ]