// BLEX0.bcpl - BCPL Compiler -- Lexical Analyzer,Main Program // Copyright Xerox Corporation 1980 // Swinehart, 5-9-77 Fast getframe, return // last modified by Butterfield, May 9, 1979 2:15 PM // - Rch, OpenSource, CloseSource, add -G switch (not SWGetLINEs) - 2/2 // - OpenSource, CloseSource, discardable symbols - 1/23 // - GetMax, increase to 20 - 1/19/79 // ReadSource Main program of LEX // LEXreport Report errors from LEX phase // Rch Read the next source char from INPUT into Ch // OpenSource Open a source stream and remember any previous stream's state // Closesource Close the current source stream, restore any previous stream // DictionaryEntry Make an entry in the Dictionary get "blexx" //---------------------------------------------------------------------------- static //---------------------------------------------------------------------------- [ V = nil //vector filled by Readsymb in LEX and by Nextsymb in CAE Symb = nil //output of Readsymb and Nextsymb GetV = nil //stack for nested GET files GetP = 0 //pointer into GetV Ch = nil //output of Rch Chline = -1 //line pointer of char read by Rch LineV = nil //circular buffer for source input LineP = 0 //pointer into LineV ///*DCS* Compiled Declarations LexLength = 0 ///* # bytes in Lex File ///*DCS* command line manifests bp = 0 ] //---------------------------------------------------------------------------- manifest //---------------------------------------------------------------------------- [ dictionarySize = #7777 GetMax = 20 //max number of nested GET files GetN = 3 //size if a GetV entry GetT = GetMax*GetN-1 //length of GetV (-1) getF = 0; getS = 1; getD = 2; // file, stream, and dictionary GetV offsets LineMax = 120 //size of the circular line buffer ] //---------------------------------------------------------------------------- let ReadSource() be //---------------------------------------------------------------------------- [ if SWDebug do WriteS("LEX*n") // *** Allocate source file maintenance tables *** let v = vec GetT; GetV = v // The stack for nested GET files let v = vec LineMax; LineV = v // The circular line buffer for i = 0 to LineMax do LineV!i = 0 let v = vec Vmax; V = v // The information for a lexeme Chline = -1 // *** Allocate Dictionary *** Dictionary = Newvec(dictionarySize); Dictionary!0 = ($z-$a+1)*2+1; for i = 1 to Dictionary!0 do Dictionary!i = 0 ///*DCS* Precompiled Declarations if SWUseDecl then ReadDecl() ///* All Communications Global Movestring(SourceName, GetnameV!GetnameP) SourceStream = OpenInput(GetnameV!GetnameP) SourceLength = lv GetnameV!(GetnameP+1); rv SourceLength = -1 Curfile = GetnameP; Curline = Chline; test SWPrepare ifnot [ LexStream = OpenTemp($l, false); if SWUseDecl then ReadLex(); ] ifso LexStream = OpenOutput(DECLName) ///*DCS* ** process command line manifests ** if SWParamset then enterparams() // **** READ SOURCE **** [ Readsymb() ] repeatuntil Symb eq END // ** clean up ** test SWPrepare ifso [ /// ** DCS ** if LexLength&1 ne 0 then LexWrite(LINE); // must be even! CloseOutput(LexStream) DictStream = OpenOutput(DICTName) ] ifnot DictStream = OpenTemp($d, false) DictLength = Dictionary!0 ///*DCS* Precompiled Declarations if SWPrepare then WriteDecl() ///* All communications Global ///* Enhanced Performance WriteSequential(DictStream, Dictionary,DictLength) test SWPrepare ifso CloseOutput(DictStream) ifnot ResetStream(DictStream, $d) ] //---------------------------------------------------------------------------- and DictionaryEntry(Name) = valof //---------------------------------------------------------------------------- // The Dictionary chain table contains the pointers to 52 chains // Each chain is sorted (increasing) // The name blocks contain // pointer to next link (or 0) // extra word (unused at present, set to 0 on creation) // n words for the packed string ///*DCS* Symbol Table Compaction, during NCG Phase ///* When symbol first entered, virgin bit of its link field is ///* set. When symbol is again seen, virgin bit cleared. During ///* NCG, only non-virgin symbols will be allowed into core. [ let n,c,p,q = nil,nil,nil,nil //length, first char, and two pointers n = Length(Name)/Bytesperword; c = Char(Name,1) test $a le c & c le $z // Get the header index of the first char then c = (c - $a) * 2 + 1 or test $A le c & c le $Z then c = (c - $A) * 2 + 2 or resultis 0 // A non-alphabetic initial char?? q = c + 1 p = Dictionary!(q-1) until p eq 0 do [ let i = 0 while Dictionary!(p+i) eq Name!i do [ if i eq n do ///*DCS* symbol seen again. [ c = Dictionary!(p-1) if c<<SYMPTR.Virgin then // record # non-virgin symbs., size. [ Dictionary!(p-1) = c<<SYMPTR.link // No longer virgin RealSymCount = RealSymCount+1 RealSymSize = RealSymSize + (n+1) + 1 ] resultis p ] i = i + 1 ] if Dictionary!(p+i) gr Name!i break q = p p = (Dictionary!(q-1))<<SYMPTR.link ] //enter the symbol p = Dictionary!0 + 1; Dictionary!0 = Dictionary!0 + (n+1) + 1 if Dictionary!0 gr dictionarySize then LEXreport(2) Dictionary!(p-1) = Dictionary!(q-1) (Dictionary!(p-1))<<SYMPTR.Virgin = 1 (Dictionary!(q-1))<<SYMPTR.link = p for i = 0 to n do Dictionary!(p+i) = Name!i resultis p // and return the pointer ] ///*DCS* End of BLEX changes for BNCG Symbol Table Compaction //---------------------------------------------------------------------------- and LEXreport(n) be // Report LEX errors //---------------------------------------------------------------------------- [ static [ LastCharPtr = -1 ] // Line pointer for last error message. Ostream = ErrorStream WW($*n) unless Curline eq LastCharPtr do [ LastCharPtr = Curline // Remember where this error occurred. unless Curfile eq 0 do // Identify any file other than the initial one. [ WriteS(" in file "); WriteS( GetnameV!Curfile); WW($*n) ] let i, j = LineP, -1 // Skip up to next newline. [ i = i+1 if i > LineMax do i = 0 if LineV!i eq $*n do [ j = i; LineV!i = 0; break ] if i eq LineP do [ WriteS("..."); break ] ] repeat // Print last few lines. [ i = i+1 if i > LineMax do i = 0 WW(LineV!i) if LineV!i eq $*n do [ j = i; LineV!i = 0 ] ] repeatuntil i eq LineP unless j eq -1 do LineV!j = $*n WW($*n) ] let m = selecton n into [ default: 0 case 1: "TOO MANY *"GET*" FILES" case 2: "DICTIONARY IS TOO BIG" case 3: 0 case 4: "ILLEGAL *"GET*"" case 5: "TOO MANY NESTED *"GET*" FILES" case 6: "ILLEGAL NUMERIC CONSTANT" case 7: "BRACKET LABEL TOO LONG" case 8: "ILLEGAL CHARACTER" case 9: "STRING TOO LONG" case 10: "ILLEGAL CHARACTER FOLLOWS *"***"" case 11: "NAME TOO LONG" case 12: "ILLEGAL SWITCH or TOO MANY SOURCE FILES" ] BCPLreport(n, m) if SWHelp do Help("LEX REPORT") if n le 5 goto Abort Ostream = OutputStream ] //---------------------------------------------------------------------------- and Rch() be // Read the next char //---------------------------------------------------------------------------- [ Readch(SourceStream, lv Ch) //Readch returns #777 at end of stream,so Endofstream() is no more //if Endofstream(SourceStream) do Ch = #777 // Pass special EOF char to Readsymb if GetP eq 0 % SWGetLINEs then Chline = Chline+1; rv SourceLength = rv SourceLength + 1 // Step character count if SWOneCase do if $a le Ch & Ch le $z do Ch = Ch + ($A-$a) if SWList do [ WW(Ch);WriteO(Ch);WW($*n) if Ch eq $*n & not SWLexTrace do [ WriteO(Chline+1); WW($*s) ] ] // store the char into circular line buffer (for error reports) LineP = LineP+1; if LineP gr LineMax do LineP = 0; LineV!LineP = Ch; ] //---------------------------------------------------------------------------- and OpenSource(Name, discardSymbols; numargs na) be // Open a source stream //---------------------------------------------------------------------------- [ if SWGetLINEs then [ if GetlineP gr GetlineT do [ LEXreport(1) ] GetlineV!GetlineP = Chline; GetlineV!(GetlineP+1) = Curfile GetlineV!(GetlineP+2) = rv SourceLength; GetlineP = GetlineP + GetlineN ] if GetP gr GetT do [ LEXreport(5) ] GetV!GetP = Curfile; GetV!(GetP+1) = SourceStream; GetP = GetP + GetN GetnameP = GetnameP + GetnameN; if GetnameP gr GetnameT do [ LEXreport(1) ] Unpackstring(Name, filename); // use global filename vector for FixFileName FixFileName(Name, "", SourceDevice) // Tack on the device if any Movestring(Name, GetnameV!GetnameP) SourceStream = OpenInput(GetnameV!GetnameP) SourceLength = lv GetnameV!(GetnameP+1); rv SourceLength = -1 Curfile = GetnameP GetV!(GetP-GetN+getD) = ((na ls 2 % not discardSymbols)? 0, Dictionary!0); ] //---------------------------------------------------------------------------- and CloseSource() = valof // Close the current stream, reopen the last //---------------------------------------------------------------------------- // returns true if there is no last [ if SWGetLINEs % GetP eq 0 then [ if GetlineP gr GetlineT do [ LEXreport(1) ] GetlineV!GetlineP = Chline; GetlineV!(GetlineP+1) = Curfile GetlineV!(GetlineP+2) = rv SourceLength; GetlineP = GetlineP + GetlineN ] if GetP eq 0 then [ V!0 = 0; resultis true; ] CloseInput(SourceStream, GetnameV!Curfile) GetP = GetP - GetN; Curfile = GetV!GetP SourceStream = GetV!(GetP+1); SourceLength = lv GetnameV!(Curfile + 1) let newEnd = GetV!(GetP+getD); V!0 = newEnd; if newEnd ne 0 then [ for i = 2 to ($z-$a+1)*2+1 do [ let q = i; while q ne 0 do [ let p = (Dictionary!(q-1))<<SYMPTR.link; if p ge newEnd then [ while p ge newEnd do p = (Dictionary!(p-1))<<SYMPTR.link; (Dictionary!(q-1))<<SYMPTR.link = p; ] q = p; ] ] Dictionary!0 = newEnd; ] resultis false ] //---------------------------------------------------------------------------- and enterparams() be //---------------------------------------------------------------------------- ///*DCS* read command line manifests [ let fn, uc, swu = FirstName, UpperCase, SWUpperCase // danger! won't swap! let orch = Rch Rch = Getch let value = true //default manifest value ReadCOMCM() // processor name, global switches ReadCOMCM() // first file name while filename!0 ne -1 do [ bp = 0 for i = 1 to sw!0 do switchon sw!i into [ case $S: // DCS 5-9-77 value for fast getframe, return Rch() SWFastFrame = DoNumber(-8) // get value (see just below) unless SWAlto do SWFastFrame = 0 // ignore on Nova endcase case $V: Rch() value = DoNumber(-10) // get value, don't write to BL file endcase case $M: LexOut(MANIFEST) if ReadAhead then Readsymb() // force manifest Readsymb() LexOut(ASS) // manifest name = value V!0 = value LexOut(NUMBER) LexOut(SEMICOLON) NLPending = true // hedge bets, generate <cr> default: endcase ] ReadCOMCM() ] Rch = orch if fn then [ FirstName = true UpperCase = uc SWUpperCase = swu ] ] //---------------------------------------------------------------------------- and Getch() be //---------------------------------------------------------------------------- [ bp = bp + 1 Ch = bp>filename!0? 0, filename!bp ]