-- TexMacro.mesa -- last written by Doug Wyatt, November 16, 1979 3:28 PM DIRECTORY TexDefs: FROM "TexDefs" USING[DefType], TexErrorDefs: FROM "TexErrorDefs", TexHashDefs: FROM "TexHashDefs" USING[maxidsize,IdName], TexInpDefs: FROM "TexInpDefs", TexIODefs: FROM "TexIODefs", TexSynDefs: FROM "TexSynDefs", TexTableDefs: FROM "TexTableDefs" USING[HashIndex,SetHashEquiv,Cmd,CurTracing], TexTokenDefs: FROM "TexTokenDefs"; TexMacro: PROGRAM IMPORTS TexErrorDefs,TexHashDefs,TexInpDefs,TexIODefs,TexSynDefs, TexTableDefs,TexTokenDefs EXPORTS TexSynDefs = BEGIN OPEN TexErrorDefs,TexInpDefs,TexSynDefs,TexTokenDefs; MacroDef: PUBLIC PROCEDURE [dt: TexDefs.DefType] = BEGIN listhead: TokenListPtr; temphead: TokenLEntry←nilTokenLEntry; q: TokenPtr←@temphead; defplace: TexTableDefs.HashIndex; npars: CARDINAL; glob: BOOLEAN←(dt=gdef) OR (dt=xdef); -- remember to catch PageEndError GetTok[]; WITH tok:curtok SELECT FROM ctrlseq => BEGIN defplace←tok.index; StoreTok[@q,tok] END; ENDCASE => BEGIN BackError["You can only define a control sequence"L]; RETURN; END; SELECT dt FROM xdef => BEGIN -- *** is this right? list: TokenListPtr←ScanToks[def]; StoreTok[@q,[match[end]]]; q.link←list.link; FreeTokenLHead[list]; END; gdef,def => BEGIN npars←ScanMacroPars[@q !BadParam => BEGIN BackError["Parameters must be numbered consecutively"L]; RESUME; END]; ScanMacroBody[@q, npars !BadParam => BEGIN OPEN TexIODefs; BeginError; Ws["Illegal parameter number in definition of "L]; MacroName[defplace]; BackError[EndError[]]; RESUME; END]; END; ENDCASE; listhead←MakeTokenLHead[temphead.link]; TexTableDefs.SetHashEquiv[defplace,call,[call[listhead]],glob]; ScanSpacer[]; END -- of MacroDef --; -- write a macro name on the current output stream MacroName: PROCEDURE[defplace: TexTableDefs.HashIndex] = BEGIN OPEN TexHashDefs,TexIODefs; id: STRING←[maxidsize]; IdName[id, defplace]; Esc; Ws[id]; END; BadParam: SIGNAL = CODE; ScanMacroPars: PROCEDURE[qq: POINTER TO TokenPtr] RETURNS[npars: CARDINAL] = BEGIN npars←0; DO GetTok[]; WITH cc:curchar SELECT curcmd FROM rbrace => BEGIN BackError["Missing { has been inserted"L]; EXIT; END; lbrace => EXIT; macprm => BEGIN IF GetParamNum[]#(npars←npars+1) THEN SIGNAL BadParam; IF npars>parsize THEN ERROR OverFlow["npars"L]; StoreTok[qq,[match[par]]]; END; ENDCASE => StoreTok[qq,curtok]; ENDLOOP; StoreTok[qq,[match[end]]]; END; ScanMacroBody: PROCEDURE[qq: POINTER TO TokenPtr, npars: CARDINAL] = BEGIN unbal: CARDINAL←1; DO -- ScanToks with additional check for macprms GetTok[]; WITH cc:curchar SELECT curcmd FROM lbrace => unbal←unbal+1; rbrace => IF unbal=1 THEN EXIT ELSE unbal←unbal-1; macprm => BEGIN par: CARDINAL←GetParamNum[]; IF par IN[1..npars] THEN curtok←[outpar[par]] ELSE IF curcmd#macprm THEN SIGNAL BadParam; END; ENDCASE; StoreTok[qq,curtok]; ENDLOOP; END; GetParamNum: PROCEDURE RETURNS[[0..9]] = --INLINE-- BEGIN GetTok[]; WITH cc:curchar SELECT curcmd FROM otherchar => IF cc.char IN['1..'9] THEN RETURN[cc.char-'0]; ENDCASE; RETURN[0]; END -- of GetParamNum --; ScanToks: PUBLIC PROCEDURE[type: TokListType] RETURNS[TokenListPtr] = BEGIN temphead: TokenLEntry←nilTokenLEntry; q: TokenPtr←@temphead; unbal: CARDINAL←1; docalls: BOOLEAN←(type=mark) OR (type=def); storerb: BOOLEAN←(type#def) AND (type#caseshift); ScanLB; -- *** perhaps this should not skip spacers DO IF docalls THEN GetNCTok[] ELSE GetTok[]; SELECT curcmd FROM lbrace => unbal←unbal+1; rbrace => IF unbal=1 THEN EXIT ELSE unbal←unbal-1; ENDCASE; StoreTok[@q,curtok]; ENDLOOP; IF storerb THEN BEGIN StoreTok[@q,curtok]; ScanSpacer; END; RETURN[MakeTokenLHead[temphead.link]]; END -- of ScanToks --; -- Calling user macros MacroCall: PUBLIC PROCEDURE = BEGIN firsterror: BOOLEAN←TRUE; rclisthead: TokenListPtr; q,r: TokenPtr; npars,ngrps: CARDINAL←0; t: Token; defplace: TexTableDefs.HashIndex; unbal,i: CARDINAL←1; prevcmd: TexTableDefs.Cmd; temphead: TokenLEntry←nilTokenLEntry; -- remember to catch PageEndError defplace←hashentry; WITH cc:curchar SELECT curcmd FROM call => rclisthead←cc.toklist; ENDCASE => ERROR; r←rclisthead.link.link; IF TexTableDefs.CurTracing[].showmacros THEN -- Ps[DumpTokens[rclisthead.link]];-- NULL; -- *** fix this WHILE (t←r.token)#[match[end]] DO q←@temphead; r←r.link; GetTok[]; IF t=[match[par]] THEN BEGIN t←r.token; WHILE curcmd=rbrace DO BEGIN OPEN TexIODefs; BeginError; Ws["Argument begins with } in "L]; MacroName[defplace]; Error[EndError[]]; GetTok[]; END; ENDLOOP; ngrps←0; WHILE curtok#t DO StoreTok[@q,curtok]; IF curcmd=lbrace THEN DO -- ScanToks not called because of recursion GetTok[]; SELECT curcmd FROM lbrace => unbal←unbal+1; rbrace => IF unbal=1 THEN EXIT ELSE unbal←unbal-1; ENDCASE; StoreTok[@q,curtok]; ENDLOOP; ngrps←ngrps+1; prevcmd←curcmd; IF t.cmd=match THEN EXIT; GetTok[]; REPEAT FINISHED => r←r.link; ENDLOOP; IF prevcmd=rbrace THEN IF ngrps#1 THEN StoreTok[@q,curtok] -- store rbrace ELSE BEGIN p: TokenPtr; -- strip off lbrace p←temphead.link; temphead.link←p.link; FreeTokenLEntry[p]; END; pstack[npars]←temphead.link; IF TexTableDefs.CurTracing[].showmacros THEN BEGIN OPEN TexIODefs; Pc['#]; Wn[npars+1]; Wc['←]; DumpTokens[NIL,pstack[npars]]; END; npars←npars+1; END ELSE IF t#curtok AND firsterror THEN BEGIN OPEN TexIODefs; firsterror←FALSE; BeginError; Ws["Use doesn't match definition of "L]; MacroName[defplace]; Error[EndError[]]; END; ENDLOOP; IF parptr+npars>parsize THEN ERROR OverFlow["parstack"L]; FOR i IN [0..npars) DO parstack[parptr+i]←pstack[i]; ENDLOOP; PushInput[]; instate←[tokenlist[r.link,[prune[parptr,rclisthead]]]]; parptr←parptr+npars; rclisthead.refs←rclisthead.refs+1; END -- of MacroCall --; STOP; END -- of TexMacro --.