-- TexMMode.mesa -- last written by Doug Wyatt, December 13, 1979 4:39 PM DIRECTORY TexDefs: FROM "TexDefs", TexErrorDefs: FROM "TexErrorDefs", TexIODefs: FROM "TexIODefs", TexMainDefs: FROM "TexMainDefs", TexMathDefs: FROM "TexMathDefs", TexMathOpDefs: FROM "TexMathOpDefs", TexNoadDefs: FROM "TexNoadDefs", TexNodeDefs: FROM "TexNodeDefs", TexPackDefs: FROM "TexPackDefs", TexSynDefs: FROM "TexSynDefs", TexTableDefs: FROM "TexTableDefs"; TexMMode: PROGRAM IMPORTS TexErrorDefs,TexIODefs,TexMainDefs,TexMathOpDefs,TexNoadDefs, TexNodeDefs,TexPackDefs,TexSynDefs,TexTableDefs EXPORTS TexMainDefs = BEGIN OPEN TexTableDefs,TexSynDefs,TexMainDefs,TexNodeDefs, TexNoadDefs,TexMathDefs; -- ************* -- * Math mode * -- ************* eqnobox: BoxNodePtr; -- box containing \eqno for display MMode MMode: PROCEDURE[mlist: NoadListPtr, restricted: BOOLEAN] = BEGIN incompleatnoad: AboveNoadPtr_NIL; -- if not NIL, incompleatnoad points to a partly completed AboveNoad head: NoadPtr_mlist.last; AddToMlist: PROCEDURE[p: NoadPtr] = --INLINE-- BEGIN StoreNoad[mlist, p] END; MathChar: PROCEDURE[t: TMChar] = --INLINE-- BEGIN StoreNoad[mlist, MakeCharNoad[t]] END; MakeMathBox: PROCEDURE[ff: MField] = --INLINE-- BEGIN StoreNoad[mlist, MakeScriptedNoad[ff]] END; Store: PROCEDURE[p: NodePtr] = BEGIN StoreNoad[mlist, MakeNodeNoad[p]] END; ScanMlist: PROCEDURE[ec: EndingCode] RETURNS[MField] = BEGIN block: NoadListPtr_InitNoadList[]; NewSaveLevel[ec]; MMode[block, restricted]; UnSave[ec]; RETURN[[mlist[FinishNoadList[block]]]]; END; ScanMath: PROCEDURE[f: MFieldPtr] = BEGIN -- At this point the next portion of the input should be -- either a single character or "{}". -- We want to fill the MField pointed to by f. ScanNonSpacer[]; -- get next non-spacer WITH cc:curchar SELECT curcmd FROM letter,otherchar => f^_[mchar[MModeCode[cc.char].mchar]]; mathonly => f^_[mchar[cc.tmchar.mchar]]; ascii => f^_[mchar[ScanMChar[]]]; ENDCASE => BEGIN IF curcmd#lbrace THEN TexErrorDefs.BackError["Missing { inserted"]; f^_ScanMlist[endscanmath]; END; END; DO GetNext; BEGIN ENABLE BEGIN FallThru => BEGIN SIGNAL CantDoThat[m, restricted]; CONTINUE END; Reswitch => RETRY; Continue => CONTINUE; END; WITH cc:curchar SELECT curcmd FROM spacer => NULL; -- ignore spacers in math mode undefined => SIGNAL Undefined; -- unknown control sequence call => MacroCall[]; -- defined control sequence lbrace => MakeMathBox[ScanMlist[mathblock]]; -- Append a subformula rbrace => SELECT SaveCode[] FROM simpleblock => UnSave[simpleblock]; -- just pop the savestack -- (topbotmark can start simpleblocks) trueend => TrueEnd[]; -- skip over the \else part falseend => FalseEnd[]; -- skip over a spacer, if any mathcode,mathleft => TexErrorDefs.Error["Extra }"]; -- ignore it mathblock,endscanmath => EXIT; -- we're done aligncode,noalignend => SIGNAL Unimplemented; -- *** figure out later bottomlevel,justend,outputend,topinsend,botinsend,endvcenter => ERROR TexErrorDefs.Confusion; -- invalid endcode in MMode ENDCASE => ERROR; -- bad EndingCode leftright => SELECT cc.lr FROM left => BEGIN dlist: NoadListPtr_InitNoadList[]; StoreNoad[dlist,MakeDelimNoad[left,ScanDelim[]]]; -- left delimiter NewSaveLevel[mathleft]; MMode[dlist,restricted]; UnSave[mathleft]; StoreNoad[dlist,MakeDelimNoad[right,ScanDelim[]]]; -- right delimiter MakeMathBox[[mlist[FinishNoadList[dlist]]]]; END; right => SELECT SaveCode[] FROM mathleft => EXIT; -- all is well mathcode => BEGIN []_ScanDelim[]; -- eat the delimiter TexErrorDefs.Error["Extra \right"]; -- complain, then press on END; ENDCASE => MissingRB; -- will SIGNAL Reswitch ENDCASE => ERROR; -- bad DelimType mathbr => BEGIN IF SaveCode[]#mathcode THEN MissingBrace; -- will SIGNAL Reswitch IF restricted THEN EXIT; -- end of restricted math mode -- end of display mode, look for another $ GetNCTok; IF curcmd#mathbr THEN TexErrorDefs.BackError["Display math should end with $$"]; EXIT; -- end of display math mode END; letter,otherchar => MathChar[TexTableDefs.MModeCode[cc.char]]; mathonly => MathChar[cc.tmchar]; ascii => MathChar[[Ord,ScanMChar[]]]; supmrk,submrk => BEGIN scriptfield: MFieldPtr; Fp: PROCEDURE[p: ScriptedNoadPtr] RETURNS[MFieldPtr] = --INLINE-- BEGIN RETURN[IF curcmd=supmrk THEN @p.supscr ELSE @p.subscr] END; ScriptFieldPtr: PROCEDURE RETURNS[MFieldPtr] = --INLINE-- BEGIN p: ScriptedNoadPtr; -- is the last noad in mlist a ScriptedNoad? WITH qq:mlist.last SELECT FROM common => WITH qqq:qq SELECT FROM scripted => BEGIN -- We have a scripted noad. Check the script field. f: MFieldPtr_Fp[@qqq]; IF EmptyField[f] THEN RETURN[f] -- all is well ELSE -- oops, the super or subscript has already been set BEGIN OPEN TexErrorDefs,TexIODefs; BeginError; Ws["Double "]; Ws[IF curcmd=supmrk THEN "super" ELSE "sub"]; Ws["script"]; Error[EndError[]]; -- after complaining, append a dummy noad END; END; ENDCASE; ENDCASE; -- add a dummy noad to mlist to receive the super or subscript p_MakeScriptedNoad[]; AddToMlist[p]; RETURN[Fp[p]]; END; -- get a pointer to the MField for the super or subscript scriptfield_ScriptFieldPtr[]; -- now scan a character or subformula to put in the field ScanMath[scriptfield]; END; mathinput => BEGIN q: ScriptedNoadPtr_MakeScriptedNoad[mtype: cc.mtype, stype: cc.stype]; ScanMath[@q.operand]; AddToMlist[q]; END; accent => BEGIN q: ScriptedNoadPtr_MakeAccentNoad[[rm,cc.char]]; ScanMath[@q.operand]; AddToMlist[q]; END; eqno => IF restricted THEN SIGNAL FallThru -- allowed only in displays ELSE BEGIN hlist: NodeListPtr_InitNodeList[]; ScanFormula[hlist,TRUE]; -- scan the eqno in restricted math mode eqnobox_TexPackDefs.HBox[hlist]; -- box the resulting hlist -- the $ that terminated the equation number is the beginning of -- the $$ that should terminate the display, so scan it again BackInput; END; mathspace => AddToMlist[MakeSpaceNoad[cc.space]]; exspace => AddToMlist[MakeSpaceNoad[user]]; mathstyle => AddToMlist[MakeStyleNoad[[norm,cc.style]]]; hskip => Store[SkipGlue[cc.gluetype]]; vmove => MakeMathBox[[box[ScanMovedBox[cc.neg]]]]; box => MakeMathBox[[box[GetBox[cc.boxtype]]]]; parend,endv => MissingMathbr; -- will SIGNAL Reswitch mdiscr => AddToMlist[MakeDiscNoad[cc.mchar]]; halign => SIGNAL Unimplemented; above => BEGIN IF incompleatnoad#NIL THEN ExtraAbove[cc.abovetype] -- two \above's in same mlist ELSE BEGIN incompleatnoad_ScanAbove[cc.abovetype]; incompleatnoad.numerator_[mlist[head.link]]; head.link_incompleatnoad; mlist.last_head_incompleatnoad; END; END; limsw => DoLimsw[mlist.last]; vcenter => AddToMlist[ScanVcenter[cc.vctr]]; penlty => Store[ScanPenltyNode[]]; eject => IF restricted THEN Store[MakeEjectNode[]] ELSE SIGNAL FallThru; tabmrk,carret => SIGNAL Unimplemented; assignreal => SetDimnParam[cc.dimnparam, ScanLength[]]; assignglue => SetGlueParam[cc.glueparam, ScanGlueSpec[]]; def => MacroDef[cc.deftype]; output => SetOutputRoutine[ScanToks[output]]; -- ddt => Debug; chcode => DoChng[cc.chngtype]; setcount => DoSetCount[]; advcount => DoAdvCount[]; count => DoCount[]; ifeven => DoIfEven[cc.iftype]; ifT => DoIfT[]; save => DoSave[]; topbotmark => DoTopBotMark[cc.marktype]; newaccent => SIGNAL Unimplemented; ENDCASE => SIGNAL FallThru; END; ENDLOOP; -- Now finish the AboveNoad, if one has been made. IF incompleatnoad#NIL THEN BEGIN incompleatnoad.denominator_[mlist[head.link]]; mlist.last_head; head.link_NIL; END; RETURN; END; EmptyField: PROCEDURE[f: MFieldPtr] RETURNS[BOOLEAN] = --INLINE-- BEGIN WITH ff:f SELECT FROM box => RETURN[ff.box=NIL]; ENDCASE => RETURN[FALSE]; END; DoLimsw: PROCEDURE[q: NoadPtr] = --INLINE-- BEGIN WITH qq:q SELECT FROM common => WITH qqq:qq SELECT FROM scripted => WITH qqq SELECT FROM op => BEGIN limitswitch_NOT limitswitch; RETURN END; ENDCASE; ENDCASE; ENDCASE; TexErrorDefs.Error["Limit switch must follow math operator"]; END; ExtraAbove: PROCEDURE[type: AboveType] = BEGIN SELECT type FROM above => []_ScanLength[]; atop,over => NULL; comb => BEGIN []_ScanDelim[]; []_ScanDelim[] END; ENDCASE => ERROR; -- bad AboveType TexErrorDefs.Error["Ambiguous; you need another { and }"]; END; ScanAbove: PROCEDURE[type: AboveType] RETURNS[AboveNoadPtr] = BEGIN p: AboveNoadPtr_MakeAboveNoad[]; SELECT type FROM above => p.aboverule_ScanLength[]; atop => NULL; over => p.aboverule_TexMathOpDefs.MathExPar[defaultrulethickness]; comb => BEGIN p.ldelim_ScanDelim[]; p.rdelim_ScanDelim[] END; ENDCASE => ERROR; -- bad AboveType RETURN[p]; END; ScanVcenter: PROCEDURE[vc: VctrType] RETURNS[ScriptedNoadPtr] = BEGIN q: ScriptedNoadPtr; vlist: NodeListPtr_InitNodeList[]; vhead: VHead_[vlist,pflag]; ScanLB; NewSaveLevel[endvcenter]; VMode[@vhead,TRUE]; -- scan a list in restricted vmode UnSave[endvcenter]; q_MakeScriptedNoad[[box[TexPackDefs.VBox[vlist]]]]; q.svariant_vctr[vc]; -- vc is vtop or vcenter RETURN[q]; END; ScanFormula: PROCEDURE[tlist: NodeListPtr, restricted: BOOLEAN] = BEGIN OPEN TexMathOpDefs; mlist: NoadListPtr_NIL; style: MathStyle_[norm,IF restricted THEN text ELSE disp]; StartNoadAllocation; mlist_InitNoadList[]; NewSaveLevel[mathcode]; MMode[mlist, restricted]; UnSave[mathcode]; -- the third parameter to EvalMlist controls whether penalty nodes are -- inserted after top level Bin and Rel operators -- restricted math mode: text style, penalty nodes at possible breaks -- display math mode: disp style, no breaks allowed tlist.link_EvalMlist[FinishNoadList[mlist], style, restricted]; FinishNoadAllocation; tlist.last_NIL; CompactList[tlist]; END; GetFormula: PUBLIC PROCEDURE[flist: NodeListPtr] = BEGIN ScanFormula[flist, TRUE]; -- scan a formula in restricted MMode END; GetDisplay: PUBLIC PROCEDURE[dlist: NodeListPtr] RETURNS[eqno: BoxNodePtr] = BEGIN eqnobox_NIL; -- eqnobox will be set by MMode if it sees \eqno ScanFormula[dlist, FALSE]; -- scan a formula in display MMode RETURN[eqnobox]; END; MathQuad: PUBLIC PROCEDURE RETURNS[TexDefs.Dimn] = BEGIN RETURN[TexMathOpDefs.MathFontPar[quad,text]]; END; END.