-- TexScan.mesa
-- last written by Doug Wyatt, January 19, 1980 12:20 AM
DIRECTORY
TexDefs: FROM "TexDefs"
USING[Char,Font,Dimn,nilDimn,HangSpec,Digit,NumberStyle],
TexErrorDefs: FROM "TexErrorDefs",
TexFileDefs: FROM "TexFileDefs",
TexFontDefs: FROM "TexFontDefs",
TexGlueDefs: FROM "TexGlueDefs",
TexMathDefs: FROM "TexMathDefs",
TexStringDefs: FROM "TexStringDefs",
TexSynDefs: FROM "TexSynDefs",
TexTableDefs: FROM "TexTableDefs",
TexTokenDefs: FROM "TexTokenDefs",
InlineDefs: FROM "InlineDefs";
TexScan: PROGRAM
IMPORTS TexErrorDefs,TexFileDefs,TexFontDefs,TexStringDefs,TexSynDefs,
TexTableDefs,TexTokenDefs,InlineDefs
EXPORTS TexSynDefs =
BEGIN OPEN TexErrorDefs,TexSynDefs,TexGlueDefs,TexDefs;
nbrlength: INTEGER←0;
nbrsign: CHARACTER←'+;
ScanSpacer: PUBLIC PROCEDURE = --INLINE--
BEGIN
GetNCTok[]; IF curcmd#spacer THEN BackInput;
END;
ScanNonSpacer: PUBLIC PROCEDURE = --INLINE--
BEGIN
DO GetNCTok[]; IF curcmd#spacer THEN EXIT ENDLOOP;
END;
ScanDigit: PUBLIC PROCEDURE RETURNS[Digit] =
BEGIN d: CHARACTER;
GetNCTok[];
WITH curtok SELECT FROM
otherchar => d←char;
ENDCASE => d←0C;
IF d NOT IN ['0..'9] THEN
BEGIN
BackError["Missing digit (0 to 9), 0 inserted"L];
d←'0;
END;
ScanSpacer[];
RETURN[d-'0];
END -- of ScanDigit --;
ScanLB: PUBLIC PROCEDURE =
BEGIN
ScanNonSpacer;
IF curcmd#lbrace THEN BackError["Missing { inserted"L];
END;
ScanString: PUBLIC PROCEDURE[s: STRING] RETURNS[BOOLEAN] =
BEGIN OPEN TexTokenDefs;
q: TokenPtr; i,j: CARDINAL;
temphead: TokenLEntry←nilTokenLEntry;
FOR i IN [0..s.length)
DO
GetNCTok[];
IF NOT CurCharMatches[s[i]] THEN
BEGIN
q←@temphead;
FOR j IN [0..i) DO StoreTok[@q,MakeCharTok[s[j]]] ENDLOOP;
StoreTok[@q,curtok];
InsList[temphead.link];
RETURN[FALSE];
END;
ENDLOOP;
RETURN[TRUE];
END -- of ScanString --;
MakeCharTok: PROCEDURE[c: Char] RETURNS[t: TexTokenDefs.Token] =
BEGIN
SELECT TexTableDefs.ChType[c] FROM
macprm => t←[macprm[c]];
mathbr => t←[mathbr[c]];
tabmrk => t←[tabmrk[c]];
supmrk => t←[supmrk[c]];
submrk => t←[submrk[c]];
spacer => t←[spacer[c]];
letter => t←[letter[c]];
otherchar => t←[otherchar[c]];
ENDCASE => ERROR Confusion;
RETURN[t];
END;
CurCharMatches: PROCEDURE[c: Char] RETURNS[BOOLEAN] =
BEGIN
WITH cc:curchar SELECT curcmd FROM
macprm,lbrace,rbrace,mathbr,tabmrk,
supmrk,submrk,spacer,letter,otherchar => RETURN[cc.char=c];
ENDCASE;
RETURN[FALSE];
END;
ScanLongNumber: PROCEDURE RETURNS[LONG CARDINAL] =
BEGIN
bign: LONG CARDINAL;
nbrlength←0; nbrsign←'+;
ScanNonSpacer;
SELECT curtok FROM
[otherchar['-]] => BEGIN nbrsign←'-; ScanNonSpacer END;
[otherchar['+]] => ScanNonSpacer;
ENDCASE;
WITH cc:curchar SELECT curcmd FROM
count => BEGIN bign←TexTableDefs.Kount[ScanDigit[]]; GetNCTok END;
letter => BEGIN bign←LOOPHOLE[cc.char,CARDINAL]; GetNCTok END;
ENDCASE =>
BEGIN
digit: BOOLEAN; d: CARDINAL;
radix: CARDINAL←10;
IF curtok=[otherchar['']] THEN BEGIN radix←8; GetNCTok END;
bign←0;
DO
[digit,d]←CurDigit[]; IF NOT digit THEN EXIT;
bign←radix*bign+d; nbrlength←nbrlength+1; GetNCTok;
ENDLOOP;
END;
IF curcmd#spacer THEN BackInput;
RETURN[bign];
END;
ScanNumber: PUBLIC PROCEDURE RETURNS[n: CARDINAL] =
BEGIN
bign: LONG CARDINAL←ScanLongNumber[];
IF InlineDefs.HighHalf[bign]>0 THEN
BEGIN Error["Number bigger than 65535"L]; bign←LAST[CARDINAL] END;
RETURN[InlineDefs.LowHalf[bign]];
END;
CurDigit: PROCEDURE RETURNS[isdigit: BOOLEAN, d: [0..9]] =
BEGIN
WITH cc:curchar SELECT curcmd FROM
otherchar => IF cc.char IN['0..'9] THEN RETURN[TRUE,cc.char-'0];
ENDCASE;
RETURN[FALSE,0];
END;
ScanFrac: PROCEDURE RETURNS[n: CARDINAL] =
BEGIN OPEN InlineDefs;
pofTen: CARDINAL←1; longn: LongNumber;
digit: BOOLEAN; d: CARDINAL;
n←0;
ScanNonSpacer[];
DO
[digit,d]←CurDigit[];
IF NOT digit THEN EXIT;
IF pofTen<=1000 THEN
BEGIN n←10*n+d; pofTen←pofTen*10 END;
GetNCTok[];
ENDLOOP;
IF curcmd#spacer THEN BackInput;
longn←LongNumber[num[0,n]];
RETURN[LongDiv[longn.lc,pofTen]];
END -- of ScanFrac --;
ScanLongLength: PROCEDURE RETURNS[LONG CARDINAL] =
BEGIN
magnify: BOOLEAN←TRUE;
x: LONG CARDINAL; f: CARDINAL←0;
Scale: PROCEDURE [int,frac: CARDINAL] =
BEGIN OPEN InlineDefs;
t2,t3,t4: LongNumber;
t2.lc←x*frac; t3.lc←LongMult[f,int]; t4.lc←LongMult[f,frac];
t4.lc←t2.lowbits+t3.lowbits+t4.highbits+LONG[0];
x←x*int+t2.highbits+t3.highbits+t4.highbits
+(IF t4.lowbits>77777B THEN 1 ELSE 0);
END;
x←ScanNumber[];
GetNCTok[];
IF curtok=[otherchar['.]] THEN f←ScanFrac[] ELSE BackInput;
IF ScanString["true"L] THEN magnify←FALSE;
SELECT TRUE FROM
ScanString["mc"L] => Scale[1,0];
ScanString["pt"L] => Scale[35,9567]; -- 35.14598
ScanString["in"L] => Scale[2540,0];
ScanString["pc"L] => Scale[421,49267]; --421.75176
ScanString["cm"L] => Scale[1000,0];
ScanString["mm"L] => Scale[100,0];
ScanString["dd"L] => Scale[37,38927]; --37.59398496
ScanString["vu"L] => Scale[TexTableDefs.DimnParam[varunit],0];
ScanString["em"L] =>
BEGIN curfont: Font←TexTableDefs.CurFont[];
Scale[TexFontDefs.FontPar[curfont,quad],0];
END;
ENDCASE => BEGIN
Scale[35,9567];
Error["Illegal unit of measure (pt inserted)"L];
END;
ScanSpacer[];
-- *** for debugging, introduce rfudge
IF magnify THEN Scale[1,14632B]; -- 1.1
RETURN[x];
END -- of ScanLongLength --;
ScanLength: PUBLIC PROCEDURE RETURNS[n: Dimn] =
BEGIN
x: LONG CARDINAL←ScanLongLength[];
IF x<=77777B THEN n←InlineDefs.LowHalf[x]
ELSE BEGIN
Error["Length greater than 32767 micas"L];
n←LAST[Dimn];
END;
RETURN[IF nbrsign='+ THEN n ELSE -n];
END -- of ScanLength --;
epsilonDimn: Dimn=1;
ScanPosLength: PUBLIC PROCEDURE RETURNS[Dimn] =
BEGIN r: Dimn←ScanLength[];
IF r>0 THEN RETURN[r];
IF r<0 THEN Error["This dimension shouldn't be negative"L];
RETURN[epsilonDimn];
END -- of ScanPosLength --;
ScanFlex: PUBLIC PROCEDURE RETURNS[f: Flex] =
BEGIN
x: LONG CARDINAL; n: Dimn;
ScanSpacer[];
f.order←(SELECT TRUE FROM
ScanString["regular"L] => regular,
ScanString["lowerfill"L] => lowerfill,
ScanString["fill"L] => fill,
ENDCASE => regular);
x←ScanLongLength[];
IF x>77777B THEN BEGIN x←LongRShift[x,15]; f.order←fill END;
n←InlineDefs.LowHalf[x];
f.val←IF nbrsign='+ THEN n ELSE -n;
RETURN[f];
END -- of ScanFlex --;
ScanGlue: PUBLIC PROCEDURE[g: GluePtr] =
BEGIN
g.space←ScanLength[]; g.flex←[zeroFlex,zeroFlex];
IF ScanString["plus"L] THEN g.flex[str]←ScanFlex[];
IF ScanString["minus"L] THEN g.flex[shr]←ScanFlex[];
END -- of ScanGlue --;
ScanSpec: PUBLIC PROCEDURE[parok: BOOLEAN, size: Dimn]
RETURNS[len: Dimn, xpand, break: BOOLEAN] =
BEGIN
break←FALSE;
IF ScanString["to"L] OR (break←(parok AND ScanString["par"L])) THEN
BEGIN
xpand←FALSE;
ScanSpacer;
len←IF ScanString["size"L] THEN size ELSE ScanLength[];
END
ELSE
BEGIN
xpand←TRUE;
len←IF ScanString["expand"L] THEN ScanLength[] ELSE 0;
END;
ScanLB;
END -- of ScanSpec --;
ScanHang: PUBLIC PROCEDURE RETURNS[HangSpec] =
BEGIN
hang: HangSpec;
hang.width←ScanLength[];
SELECT TRUE FROM
ScanString["for"L] => BEGIN hang.begin←ScanNumber[]; hang.first←TRUE END;
ScanString["after"L] => BEGIN hang.begin←ScanNumber[]; hang.first←FALSE END;
ENDCASE => BEGIN hang.begin←1; hang.first←FALSE END;
RETURN[hang];
END;
ScanFileName: PUBLIC PROCEDURE [filename: STRING] =
BEGIN OPEN TexStringDefs;
c: Char;
filename.length←0;
DO
GetNCTok[];
WITH cc:curchar SELECT curcmd FROM
spacer => EXIT;
macprm,lbrace,rbrace,mathbr,tabmrk,supmrk,submrk,letter,otherchar => c←cc.char;
ENDCASE => BEGIN BackError["Blank space should follow file name"L]; EXIT END;
AppendChar[filename,c];
ENDLOOP;
END -- of ScanFileName --;
ScanFont: PUBLIC PROCEDURE RETURNS[Font] =
BEGIN OPEN TexFontDefs;
f: Font;
DO
GetNCTok;
IF curtok.cmd=ctrlseq THEN BackError["Illegal Font Code"L] ELSE EXIT;
ENDLOOP;
f←LOOPHOLE[InlineDefs.BITAND[curchar,37B]];
GetNCTok;
IF FontDefined[f] THEN BEGIN IF curcmd#spacer THEN BackInput END
ELSE
BEGIN
c: Char;
DO
c←TexTokenDefs.TokChar[curtok];
IF c='= OR c='← THEN EXIT;
BackError["First use of font must define it"L];
GetNCTok;
ENDLOOP;
DefineFont[f];
END;
RETURN[f];
END -- of ScanFont --;
DefineFont: PROCEDURE[f: TexDefs.Font] =
BEGIN
filename: STRING←[TexFileDefs.filenamesize];
ScanFileName[filename];
TexFileDefs.StripExtension[filename];
TexFontDefs.ReadFontInfo[filename,f];
END;
NumToMChar: PROCEDURE[n: CARDINAL] RETURNS[TexMathDefs.MChar] =
BEGIN
mfontmap: ARRAY [0..3] OF TexMathDefs.MFont = [rm,it,sy,ex];
Bits: TYPE = MACHINE DEPENDENT RECORD[x:[0..177B], f:[0..3B], c:[0..177B]];
bits: Bits=LOOPHOLE[n];
RETURN[[mfont: mfontmap[bits.f], char: LOOPHOLE[bits.c,Char]]];
END;
ScanMChar: PUBLIC PROCEDURE RETURNS[TexMathDefs.MChar] =
BEGIN RETURN[NumToMChar[ScanNumber[]]] END;
LongRShift: PROCEDURE[n: LONG CARDINAL, shift: [0..15]]
RETURNS[LONG CARDINAL] =
BEGIN OPEN InlineDefs;
hi,lo: CARDINAL;
result: LongNumber;
hi←HighHalf[n]; lo←LowHalf[n];
result.highbits←BITSHIFT[hi,-shift];
result.lowbits←BITOR[BITSHIFT[hi,16-shift],BITSHIFT[lo,-shift]];
RETURN[result.lc];
END;
ScanDelim: PUBLIC PROCEDURE RETURNS[TexMathDefs.Delimiter] =
BEGIN OPEN TexMathDefs;
GetNCTok;
WITH cc:curchar SELECT curcmd FROM
otherchar =>
BEGIN defined: BOOLEAN; delim: Delimiter;
[defined,delim]←TexTableDefs.DelimLookup[cc.char];
IF defined THEN RETURN[delim];
END;
mathonly =>
BEGIN mch: MChar←cc.tmchar.mchar;
IF mch.mfont=sy AND mch.char IN Char[142C..153C] THEN
BEGIN largechar: MChar←[ex,mch.char-(142B-4B)];
-- *** Note the built-in dependency on the relationship
-- between the symbol and mathex fonts!
RETURN[[small: [TRUE,mch], large: [TRUE,largechar]]];
END;
END;
ascii =>
BEGIN OPEN InlineDefs;
DChar: PROCEDURE[n: CARDINAL] RETURNS[DelimChar] =
BEGIN
IF n=0 THEN RETURN[nullDelimChar]
ELSE RETURN[[TRUE,NumToMChar[n]]]
END;
nsm,nlg: CARDINAL;
bign: LONG CARDINAL←ScanLongNumber[];
nsm←BITAND[LowHalf[LongRShift[bign,9]],777B];
nlg←BITAND[LowHalf[bign],777B];
RETURN[[small: DChar[nsm], large: DChar[nlg]]];
END;
ENDCASE;
BackError["Unknown Delimiter"L];
RETURN[nullDelimiter];
END -- of ScanDelim --;
defaultRuleDimn: Dimn=14; -- approximately 0.4 points
ScanRuleSpec: PUBLIC PROCEDURE RETURNS[width,height,depth: Dimn] =
BEGIN
IF curcmd=hrule THEN
BEGIN width←nilDimn; height←defaultRuleDimn; depth←0; END
ELSE
BEGIN width←defaultRuleDimn; height←nilDimn; depth←nilDimn; END;
DO
SELECT TRUE FROM
ScanString["width"L] => width←ScanPosLength[];
ScanString["height"L] => height←ScanPosLength[];
ScanString["depth"L] => depth←ScanPosLength[];
ENDCASE => EXIT;
ENDLOOP;
RETURN[width,height,depth];
END -- of ScanRuleSpec --;
PassBlock: PUBLIC PROCEDURE =
BEGIN unbal: INTEGER←0;
DO -- ScanToks with no StoreItems
GetTok[];
SELECT curcmd FROM
lbrace => unbal←unbal+1;
rbrace => IF (unbal←unbal-1)<=0 THEN EXIT;
ENDCASE;
ENDLOOP;
IF unbal<0 THEN Error["Missing { inserted"L];
ScanSpacer[];
END -- of PassBlock --;
InsNum: PUBLIC PROCEDURE[n: CARDINAL, style: NumberStyle] =
BEGIN OPEN TexTokenDefs;
p,q: TokenPtr; j,k: INTEGER;
SELECT style FROM
decimal =>
BEGIN
p←NIL;
DO
q←MakeTokenLEntry[[otherchar[(n MOD 10)+'0]]];
q.link←p; p←q;
n←n/10;
IF n=0 THEN EXIT;
ENDLOOP;
END;
roman =>
BEGIN
romval: ARRAY [1..7] OF CARDINAL ← [1000,500,100,50,10,5,1];
romtok: ARRAY [1..7] OF CHARACTER ← ['m,'d,'c,'l,'x,'v,'i];
temphead: TokenLEntry←nilTokenLEntry;
q←@temphead;
j←1;
DO
WHILE n>=romval[j]
DO StoreTok[@q,[letter[romtok[j]]]]; n←n-romval[j]; ENDLOOP;
IF n=0 THEN EXIT;
k←j+1+(IF (j MOD 2)=0 THEN 0 ELSE 1);
IF n+romval[k]>=romval[j] THEN
BEGIN StoreTok[@q,[letter[romtok[j]]]]; n←n+romval[k]; END
ELSE j←j+1;
ENDLOOP;
p←temphead.link;
END;
ENDCASE;
InsList[p];
END -- of InsNum --;
ScanInteger: PUBLIC PROCEDURE RETURNS[INTEGER] =
BEGIN
n: INTEGER←ScanNumber[];
RETURN[IF nbrsign='- THEN -n ELSE n]; -- *** will do for now
END;
ScanAscii: PUBLIC PROCEDURE RETURNS[Char] =
BEGIN
n: CARDINAL←ScanNumber[];
RETURN[LOOPHOLE[n MOD 200B]];
END;
END -- of TexScan --.