diff options
author | Norbert Preining <norbert@preining.info> | 2019-09-02 13:46:59 +0900 |
---|---|---|
committer | Norbert Preining <norbert@preining.info> | 2019-09-02 13:46:59 +0900 |
commit | e0c6872cf40896c7be36b11dcc744620f10adf1d (patch) | |
tree | 60335e10d2f4354b0674ec22d7b53f0f8abee672 /macros/generic/basix |
Initial commit
Diffstat (limited to 'macros/generic/basix')
-rw-r--r-- | macros/generic/basix/basix.tex | 474 | ||||
-rw-r--r-- | macros/generic/basix/paper.tex | 533 |
2 files changed, 1007 insertions, 0 deletions
diff --git a/macros/generic/basix/basix.tex b/macros/generic/basix/basix.tex new file mode 100644 index 0000000000..1592ff5853 --- /dev/null +++ b/macros/generic/basix/basix.tex @@ -0,0 +1,474 @@ +% +% BaSiX (with the emphasis on SICK!) by Andrew Marc Greene +% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% Andrew's Affiliations +% +% Copyright (C) 1990 by Andrew Marc Greene +% <amgreene@mit.edu> +% MIT Project Athena +% Student Information Processing Board +% All rights reserved. +% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% BaSiX's Beginnings +% +\def\flageol{\catcode13=13} +\def\endflageol{\catcode13=5} +\def\struncat{\catcode`\$=12} +\def\strcat{\catcode`\$=11} +\flageol\let\eol +\endflageol +\newif\ifresult +%\newcount\xa\newcount\xb +\def\iw{\immediate\write16} +\def\empty{} +\def\gobble#1{} +\def\spc{ } +\def\itstrue{tt} +\def\itsfalse{tf} +\def\isnull#1{\resultfalse +\expandafter\ifx\csname empty#1\endcsname\empty\resulttrue\fi} +\newcount\matha\newcount\mathb +% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% Character-string Calls +% +\newcount\strtmp +\def\ascii#1{\strtmp`#1} +\def\chr#1{\begingroup\uccode65=#1\uppercase{\gdef\tmp{A}}\endgroup} +\def\strlen#1{\strtmp-2% don't count " " \iw tokens + \expandafter\if\stringP #1\let\next\strIter\strIter #1\iw\fi} +\def\strIter#1{\ifx\iw#1\let\next\relax\else\advance\strtmp by 1\relax + \fi\next} +\def\Flen{\expandafter\strlen\expandafter{\Pa}\return{\number\strtmp}} +\strcat +\def\F$chr${\expandafter\chr\expandafter{\Pa}\return{\tmp}} +\struncat +% first char only: +% \def\Fasc{\expandafter\asc\expandafter{\Pa}\return{\number\strtmp}} +% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% Debugging Definitions +% +\def\debug{\tracingmacros=2} +\def\diw#1{} +\def\Cdebug{\let\diw\iw\tracingmacros=2 \endeval} +\def\Cnodebug{\def\diw##1{}\endeval} +% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% Expression Evaluation +% +\def\expression{\let\afterexpression\afterscan\math} +% +% (math is a misnomer and should -> expr) +% +\newcount\parens\newcount\mathParams +\def\math{\parens=0\mathParams96\mathInit\matheval} +\def\mathRecurse{\advance\parens by 1\relax\mathParams96\mathInit\matheval} +\def\mathInit{\begingroup + \let\mathAcc\empty + \let\mathOpRel\empty + \let\mathOpAdd\empty + \let\mathOpMul\empty + \let\mathlhRef\empty} +% +\def\matheval{\after\mathbranch\scan} +% +\def\mathbranch{\diw{EXPRESS:\expandafter\noexpand\word:} +\let\next\matherr +\ifx\empty\word\let\next\mathHardEnd\else % Expr. end? +\expandafter\if\numberP\word\let\next\mathLiteral\diw{@@}\fi % Number? +\expandafter\if\stringP\word\let\next\mathLiteral\fi % String literal? +\expandafter\if\identifierP\word\let\next\mathIdentifier\fi % Identifier? +\expandafter\if\stringvarP\word\let\next\mathIdentifier\fi % :-( +\expandafter\if\macroP\word\let\next\mathMacro\fi % Macro? +\ifx\word\Oleft\let\next\mathRecurse\fi % Open paren? +\ifx\word\Oright\let\next\mathEndRecurse\fi % Close paren? +\ifx\word\Ocomma\let\next\mathComma\fi % Comma? +% +% Operator? +% +\ifx\word\Oplus\let\next\mathOp\diw{!+}\fi +\ifx\word\Ominus\let\next\mathOp\diw{!-}\fi +\ifx\word\Otimes\let\next\mathOp\diw{!*}\fi +\ifx\word\Odiv\let\next\mathOp\diw{!/}\fi +\ifx\word\Olt\let\next\mathOp\diw{!<}\fi +\ifx\word\Oeq\let\next\mathOp\diw{!=}\fi +\ifx\word\Ogt\let\next\mathOp\diw{!>}\fi +% +\fi\next} +% +\def\Oleft{(}\def\Oright{)}\def\Ocomma{,} +\def\Oplus{+}\def\Ominus{-}\def\Otimes{*}\def\Odiv{/} +\def\Olt{<}\def\Oeq{=}\def\Ogt{>} +% +% There's got to be a better way to do the above.... +% +\def\mathLiteral{\diw{MLIT}\ifx\empty\mathAcc\diw{ACCUMUL:\word:} +\expandafter\def\expandafter\mathAcc\expandafter +{\expandafter\expandafter\expandafter\empty\word} +\else +\diw{ACC has :\mathAcc: and word is :\word:} +\errmessage{Syntax Error: Two values with no operator}\fi\matheval} +% +% Operator stuff: (Need to add string support / error checking) +% +\def\mathAdd{\advance\matha by \mathb} +\def\mathSub{\advance\matha by -\mathb} +\def\mathMul{\multiply\matha by \mathb} +\def\mathDiv{\divide\matha by \mathb} +\def\mathEQ{\ifnum\matha=\mathb\matha-1\else\matha0\fi} +\def\mathGT{\ifnum\matha>\mathb\matha-1\else\matha0\fi} +\def\mathLT{\ifnum\matha<\mathb\matha-1\else\matha0\fi} +% +\def\mathFlushRel{\mathFlushAdd\ifx\empty\mathOpRel\else + \matha=\mathlhRel\relax\mathb=\mathAcc\relax\mathOpRel + \edef\mathAcc{\number\matha}\let\mathOpRel\empty\fi} +% +\def\mathFlushAdd{\mathFlushMul\ifx\empty\mathOpAdd\else + \matha=\mathlhAdd\relax\mathb=\mathAcc\relax\mathOpAdd + \edef\mathAcc{\number\matha}\let\mathOpAdd\empty\fi} +% +\def\mathFlushMul{\mathFlushRef\ifx\empty\mathOpMul\else + \matha=\mathlhMul\relax\mathb=\mathAcc\relax\mathOpMul + \edef\mathAcc{\number\matha}\let\mathOpMul\empty\fi} +% +\def\mathFlushRef{\ifx\empty\mathlhRef\else + \mathParam + \mathlhRef\let\mathlhRef\empty\fi} +% +\def\mathOp{% +\if\word+ + \mathFlushAdd\let\mathlhAdd\mathAcc\let\mathOpAdd\mathAdd\fi +\if\word- + \mathFlushAdd\let\mathlhAdd\mathAcc\let\mathOpAdd\mathSub\fi +\if\word* + \mathFlushMul\let\mathlhMul\mathAcc\let\mathOpMul\mathMul\fi +\if\word/ + \mathFlushMul\let\mathlhMul\mathAcc\let\mathOpMul\mathDiv\fi +\if\word= + \mathFlushRel\let\mathlhRel\mathAcc\let\mathOpRel\mathEQ\fi +\if\word> + \mathFlushRel\let\mathlhRel\mathAcc\let\mathOpRel\mathGT\fi +\if\word< + \mathFlushRel\let\mathlhRel\mathAcc\let\mathOpRel\mathLT\fi +\let\mathAcc\empty +\matheval} +% +\def\mathIdentifier{% +\expandafter\ifx\csname C\word\endcsname\relax +\expandafter\ifx\csname F\word\endcsname\relax +\expandafter\ifx\csname V\word\endcsname\relax +\let\next\matherr\diw{LOSING:\word:} +\else\let\next\mathVariable\fi +\else\let\next\mathFunction\fi +\else\let\next\mathCommand\fi\next} +% +\def\mathVariable{\expandafter\edef\expandafter\word\expandafter +{\csname V\word\endcsname}\mathbranch} +\def\mathCommand{\expandafter\mathHardEnd\word} +\def\mathFunction{\expandafter\let\expandafter\mathlhRef +\csname F\word\endcsname\matheval} +% +\def\mathParam{\advance\mathParams by 1\relax\chr\mathParams + \diw{PARAM:\tmp:\mathAcc:} + \expandafter\edef\csname P\tmp\endcsname{\mathAcc}} +\def\mathComma{\mathEnd\mathParam\mathInit\matheval} +\def\mathEndRecurse{\mathEnd\advance\parens by -1\matheval} +\def\mathEnd{\diw{MATHEND: ACC=\mathAcc:}\mathFlushRel + \xdef\mathtemp{\mathAcc}\endgroup\edef\mathAcc{\mathtemp}} +\def\mathHardEnd{\ifnum\parens>0\errmessage{Insufficient closeparens.}\relax + \let\next\endeval\else\let\next\mathFinal\fi\next} +\def\mathFinal{\mathEnd\let\value\mathAcc\endexpression} +\def\matherr{\errmessage{Syntax error: Unknown symbol \word}} +\def\endexpression{\afterexpression} +% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% Linked List +% +\def\gotofirstline{\edef\lpointer{\csname L0\endcsname}} +\def\foreachline#1{\ifnum\lpointer<99999\edef\word{\lpointer}#1% +\edef\lpointer{\csname L\word\endcsname}\foreachline{#1}\fi} +% +% gotopast{#1} where #1 is a line number, will set \lpointer to +% the least value such that L(lpointer)>#1 +% +\def\gotopast#1{\def\lpointer{0}\def\target{#1}\gotopastloop} +% +\def\gotopastloop{\edef\tmp{\csname L\lpointer\endcsname}% +\ifnum\tmp<\target% +\edef\lpointer{\csname L\lpointer\endcsname}% +\let\next=\gotopastloop\else\let\next=\relax\fi +\next} +% +\flageol\def\addLineToLinkedList#1#2 +{\def#1{#2}\diw{Just stored #2 in \noexpand #1}% +% now put it into linked list... +\expandafter\ifx\csname L\word\endcsname\relax% if it isn't already there, +\gotopast{\word}% \def\lpointer{what-should-point-to-word} +\expandafter\edef\csname L\word\endcsname{\csname L\lpointer\endcsname}% +\expandafter\edef\csname L\lpointer\endcsname{\word}% +\fi\endeval +}\endflageol +\expandafter\def\csname L0\endcsname{99999} +% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% Program Parser +% +\def\evalline{%\iw{EVALLINE :\word:}% +\csname C\word\endcsname} %error-checking? :-) +\def\evalerror{\errmessage{Unkonwn command. Sorry.}} +% +% \mandatory takes one argument and checks to see if the next +% non-whitespace token matches it. If not, an error is generated. +% +\def\mandatory#1{\def\tmp{#1}\mandatest} +\def\mandatest#1{\def\tmpp{#1}\ifx\tmp\tmpp\let\next\afterscan\else +\let\next\manderror\fi\next} +\def\manderror{\errmessage{\tmpp\spc read when \tmp\spc expected.}% +\afterscan} +% +% \parseline gets the first WORD of the next line. If it's a line +% number, \scanandstoreline is called; otherwise the line is executed. +% +\def\parseline{\after\firsttest\scan} +\def\firsttest{\expandafter\if\numberP\word +\let\next\grabandstoreline\else\let\next\evalline\fi\next} +\def\grabandstoreline{\diw{Grabbing line \word.}% +\expandafter\addLineToLinkedList\csname/\word\endcsname} +% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% Syntactic Scanner +% +% The \scan routine reads the next WORD and then calls \afterscan. +% +% As syntactic sugar, one can write \after\foo to set \afterscan to +% \foo. +% +% Here are the rules governing WORD. Initial whitespace is +% discarded. The word is the next single character, unless that +% character is one of the following: +% +% A-Z or a-z: [A-Z,a-z][A-Z,a-z,0-9]*\$? +% 0-9: [0-9]+ +% ": "[^"]*" +% <,=,>: [<=>][<=>]? (one or two; not the same if two) +% +% Note that the string literal ignores spaces but may be abnormally +% terminated by an end-of-line. (I wasn't sure how to express that +% as a regexp). +% +% +\newif\ifscan % shall we continue scanning? +% +\def\scan{\def\word{}\futurelet\q\scanFirst} +% +\def\scanFirst{% Checks the first character to determine type. +\let\next\scanIter +\expandafter\if\spc\noexpand\q % Space -- ignore it + \let\next\scanSpace\else +\if\eol\noexpand\q % End of line -- no word here + \let\next\scanEnd\else +\ifcat A\noexpand\q % Then we have an identifier + \let\scanTest\scanIdentifier\else +\expandafter\if\digit\q + \let\scanTest\scanNumericConstant\else +\if"\noexpand\q + \let\scanTest\scanStringConstant\else +\expandafter\if\relationP\q + \let\scanTest\scanRelation +\else + \let\scanTest\scanfalse +\fi\fi\fi\fi\fi\fi\next} +% +\def\scanIter#1{\expandafter\def\expandafter\word\expandafter{\word #1} + \futurelet\q\scanContinueP} +\def\scanContinueP{\scanTest\ifscan\let\next\scanIter + \else\let\next\scanEnd\fi\next} +% +\def\scanSpace#1{\scan}% If the first char is a space, gobble it and try again. +\def\scanIdentifier{\ifcat A\noexpand\q\scantrue\else +\expandafter\if\digit\q\scantrue +\else\if$\noexpand\q\scantrue + \expandafter\def\expandafter\word\expandafter{\expandafter$\word} + \let\scanTest\scanfalse\else +\scanfalse\fi\fi\fi} +\def\scanEndString{\scanfalse} +\def\scanNumericConstant{\expandafter\if\digit\q\scantrue\else\scanfalse\fi} +\def\scanStringConstant{\scantrue\if"\q\let\scanTest\scanfalse\fi} +\def\scanRelation{\if<\q\scantrue\else\if>\q\scantrue\else\if=\q\scantrue +\else\scanfalse\fi\fi\fi} +% +\def\scanEnd#1{\relax\diw{SCANNED:\word:} +\afterscan #1}% dumps trailing spaces. +\def\after{\let\afterscan}% +% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% Type Tests (Predicates for type determination) +% +\def\relationP#1{tf} % for now, only single-char relations +\def\identifierP#1{\expandafter\identifierTest #1\\} +\def\identifierTest#1#2\\{\ifcat A#1\itstrue\else\itsfalse\fi} +\def\stringvarP#1{\expandafter\stringvarTest #1\\} +\def\stringvarTest#1#2\\{\if$#1\itstrue\else\itsfalse\fi} +\def\stringP#1{\expandafter\stringTest #1\\} +\def\stringTest#1#2\\{\if #1"\itstrue\else\itsfalse\fi} +\def\numberP#1{\expandafter\numberTest #1\\} +\def\numberTest#1#2\\{\expandafter\if\digit #1\itstrue\else\itsfalse\fi} +\def\macroP#1{\expandafter\macroTest #1\\} +\def\macroTest#1#2\\{\expandafter\ifx #1\relax\itstrue\else\itsfalse\fi} +% +% \digit tests its single-token argument and returns tt if true, +% tf otherwise. +% +% +\def\digit#1{% +\if0\noexpand#1\itstrue\else +\if1\noexpand#1\itstrue\else +\if2\noexpand#1\itstrue\else +\if3\noexpand#1\itstrue\else +\if4\noexpand#1\itstrue\else +\if5\noexpand#1\itstrue\else +\if6\noexpand#1\itstrue\else +\if7\noexpand#1\itstrue\else +\if8\noexpand#1\itstrue\else +\if9\noexpand#1\itstrue\else\itsfalse +\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi +% 9 8 7 6 5 4 3 2 1 0 +} +% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% User Utilities. These are the commands that are called by the +% user. We could really use a better section name. :-) +% +% List (one line or all lines, for now) +% +\def\Clist{\after\listmain\scan} +\def\listmain{\isnull{\word}\ifresult\let\next\listalllines +\else\let\next\listoneline\fi\next} +\def\listline{\iw{\word\spc\csname/\word\endcsname}} +\def\listalllines{\gotofirstline\foreachline{\listline}\endeval} +\def\listoneline{\listline\endeval} +% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% Different degrees of ``stop execution'' +% +\def\Csystem{\end} % exits to the system +\def\Cexit{}% \endflageol} % exits to TeX +\flageol% +\def\Cstop#1 +{\iw{Stopped in \lineno.}\cleanstop}% +\def\cleanstop{\diw{CLEANSTOP}\let\endeval\enduserline\endeval +}\endflageol +% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% The command ``rem'' introduces a remark +% +\def\Crem{\endeval}% +% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% The ``let'' command allows variable assignments +% +\def\Clet{\after\letgetequals\scan} +\def\letgetequals{\after\letgetvalue\mandatory{=}} +\def\letgetvalue{\after\letdoit\expression} +\def\letdoit{\expandafter\edef\csname V\word\endcsname{\value}% +\endeval} +% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% The ``print'' command takes a [list of] expression[s] and displays +% it [them]. +% +\def\Cprint{\after\printit\expression} +\def\printit{\iw{\value}\endeval} +% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% The ``if'' command takes an expression, the word ``then,'' and +% another command. If the expression is non-zero, the command is +% executed; otherwise it is ignored. +% +\def\Cif{\after\getift\expression} +\def\Cthen{\errmessage{Syntax error: THEN without IF}} +\def\getift{\after\getifh\mandatory t} +\def\getifh{\after\getife\mandatory h} +\def\getife{\after\getifn\mandatory e} +\def\getifn{\after\consequent\mandatory n} +\def\consequent{\ifnum\value=0\let\next=\endeval\else\let\next=\evalconsq\fi +\next} +\def\evalconsq{\after\evalline\scan} +% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% Functions +% +% Functions may read the counter \mathParams to find out the number +% of the top parameter. Parameters are in Pa Pb Pc etc. +% +\def\return{\expandafter\def\expandafter\mathAcc\expandafter} +% +\def\Finc{\matha=\Pa \advance\matha by 1 +\return{\number\matha}} +% +\def\Fmin{\ifnum\Pa<\Pb\return{\Pa}\else\return{\Pb}\fi} +% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% Program execution control +% +\def\Crun{\let\endeval\endincrline\def\lineno{0}\endeval} +\def\Cgoto{\let\endeval\endgotoline\after\gotomain\scan} +\def\gotomain{\edef\lineno{\word}\endeval} +% +\flageol% +\def\execline{%\message{Executing line \lineno...}% +\edef\theline{\csname/\lineno\endcsname}% +%\message{THE LINE\theline}% +\let\endeval\endincrline\after\evalline\expandafter\scan\theline +}\endflageol +% +% Different varieties of what to do at the end of a command: +% +% get new line from user (enduserline) +% get next line in order (endincrline) +% get line in \lineno (endgotoline) +% keep parsing current line (endcolonline tbi) +% +\flageol% +\def\endincrline#1 +{\diw{ENDINCRLINE}\edef\lineno{\csname L\lineno\endcsname}\execnextline} +% +\def\endgotoline#1 +{\diw{ENDGOTOLINE}\let\endeval\execincrline\execnextline}% +% +\def\execnextline{\diw{Ready to execute line \lineno...}% +\ifnum\lineno<99999\let\next\execline\else\let\next\cleanstop\fi\next}% +% +\def\enduserline #1 +{\diw{ENDUSERLINE}\parseline}\endflageol +% +\let\endeval\enduserline +% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% Start your engines! +% +\iw{This is BaSiX, v0.3, emphasis on the SICK! by amgreene@mit.edu} +\flageol +\catcode32=12 +\endeval diff --git a/macros/generic/basix/paper.tex b/macros/generic/basix/paper.tex new file mode 100644 index 0000000000..77c6a48a73 --- /dev/null +++ b/macros/generic/basix/paper.tex @@ -0,0 +1,533 @@ +%%% GREENE.lkd 30-mar-90 25-apr-90 +%%% GPAM = Guide.Proc.Ann.Mtg.TUG +%%% LKD: Search on %@ for comments, questions, suggestions. + +%%% GREENE.ms 22-mar-90 +%@ 21-Mar-90 11:58:42-EDT,14687;000000000000 +%@ Return-Path: <amgreene@ATHENA.MIT.EDU> +%@ Received: from ATHENA.MIT.EDU by VAX01.AMS.COM via SMTP with TCP; Wed, +%@ 21 Mar 90 11:58:24-EDT +%@ Received: from BILL-THE-CAT.MIT.EDU by ATHENA.MIT.EDU with SMTP id +%@ AA24753; Wed, 21 Mar 90 11:56:49 EST +%@ From: amgreene@ATHENA.MIT.EDU +%@ Received: by BILL-THE-CAT.MIT.EDU (5.61/4.7) id AA02558; Wed, +%@ 21 Mar 90 11:56:36 -0500 +%@ Date: Wed, 21 Mar 90 11:56:36 -0500 +%@ Message-Id: <9003211656.AA02558@BILL-THE-CAT.MIT.EDU> +%@ To: LKD@MATH.AMS.COM +%@ Cc: wsscat%carleton@CORNELLC.CIT.CORNELL.EDU, lkd@VAX01.AMS.COM +%@ In-Reply-To: Lincoln Durst's message of Wed 21 Mar 90 10:35:18-EST +%@ <638033718.0.LKD@MATH.AMS.COM> +%@ Subject: Abstract of your paper +%@ +%@ +%@ Sorry... Here's the current state of things (i.e., I know it needs +%@ more editing): + +\input tugproc.sty + +\preprint % Comment this line out for final version following meeting + +% \let\Now=\null % Uncovering this will remove time stamps on preprints + +\def\BaSiX{B\kern-.18em\lower.45ex\hbox{A}\kern-.15em +S\kern-.1em\lower.45ex\hbox{I}\kern-.1em X} +\def\basic{{\smc Basic}} +\def\ps{{\smc PostScript}} +\Title %@ \BaSiX\ \Dash\ [The whole point is NOT to put a space before +\BaSiX\Dash %@ \dash or \Dash, in order to prevent bad line breaks] + An Interpreter Written in \TeX\endTitle +% \shortTitle {\sl Proceedings\/} +% Guidelines\endshortTitle % for running head + +\Author Andrew Marc Greene\endAuthor +\address MIT Project Athena, E40-342, 77 Massachusetts Avenue, +Cambridge, MA 02139 +\endaddress +\netaddress 617-253-7788.\ Internet:\ amgreene@mit.edu +\endnetaddress + +\Abstract +An interpreter for the \basic\ language is developed entirely in \TeX. +The interpreter presents techniques of scanning and parsing that are +useful in many contexts where data %@ which do not contain formatting +not containing formatting %@ [misuse of "which"] +directives are to be formatted by \TeX. \TeX's expansion rules are +exploited to provide a macro that reads in the rest of the input file +as arguments and which never stops expanding. +\endAbstract + +\article + +\head Introduction \endhead + +It is a basic tenet of the \TeX\ faith that \TeX\ is +Turing-equivalent and that we can write any program in \TeX. + %@ It's more than a tenet of faith; it's a theorem (B\"ohm \& + %@ Jacopini, Comm.ACM, v. 9, no. 5, May, 1966, pp. 366--371): + %@ Any algorithm can be coded in a language which has + %@ (1) sequential execution, (2) conditional execution + %2 [\if..\else..\fi], (3) looping [\loop..\repeat]; if + %@ you've got those three, you have a Turing machine. + %@ A more general form of this theorem (B & J work only with + %@ flow-charts) was known thirty years earlier; see Fitting, + %@ Computability Theory, Semantics, and Logic Programming, + %@ Oxford, 1987, page 162. (Ref: Stephen Kleene, 1936.) + %@ These results are the theoretical basis of the fact that + %@ programmers can live without "goto" and still do their jobs. + %@ For some of these papers and others (including Knuth's kind + %@ words on behalf of goto) see E. N. Yourdon, Classics in + %@ Software Engineering, Yourdon Press, 1979. +%@ +%@ I understand this, but I'm more interested in being +%@ rhetorically interesting in the introduction than in +%@ giving an overview of computability theory. If you +%@ think I ought to include some more of Turings, FSMs, +%@ etc., I can; but I don't see Church's theorem as being +%@ worth discussing explicitly. Not in the introduction +%@ to the paper, at least. :-) +%@ +It is +also widely held that \TeX\ is ``the most idiosyncratic language +known to us.''\footnote{$^1$}{Ward, Stephen~A.\ and +Robert~H.~Halstead,~Jr., {\sl Computation Structures,} MIT Press, 1990} + %@ Do they cite this or say this? Who actually said it? Where? + %@ I have asked around some and, so far, have found no-one who + %@ recalls hearing this, or knows who Ward & Halstead are, or + %@ who disagrees with the claim. Whoever said it first + %@ surely deserves proper credit! +This project is an attempt to provide a simple +programming front end to \TeX. + +{\smc Basic} was selected because it is a widely used +interpreted language. It also features an infix syntax not found in +Lisp or \ps. This makes it a more difficult but more +general problem than either of these others. + +The speed of the \BaSiX\ interpreter is not impressive. It is not +meant to be. The purpose of this interpreter is not to serve as the +{\smc Basic} implementation of choice. Its purpose is to display +useful paradigms of input parsing and advanced \TeX\ programming. + +\head Interaction with \TeX\endhead + +\subhead Associative arrays \endhead + +Using |\csname| it is possible to implement associative arrays in +\TeX. Associative arrays are arrays whose index is not necessarily a +number. As an example, if |\student| has the name of a student, we +might look up the student's grade with +\verbatim +\csname grade.\student\endcsname +\endverbatim +which would be |\grade.Greene| in my case. (In the case of +|\csname|, all characters up to the |\endcsname| are used in the +command sequence regardless of their category code.) + +\BaSiX\ makes extensive use of these arrays. Commands are begun with +|C|; functions with |F|; variables with |V|; program lines with |/|; +and the linked list of lines with |L|. This makes it easy for the +interpreter to look up the value of any of these things, given the +name as perceived by the user. + +One benefit of |\csname|\dots|\endcsname| is that if the resultant +command sequence is undefined, \TeX\ replaces it with |\relax|. This +allows us to check, using |\ifx|, whether the user has specified a +non-existent identifier. This trick is used in exercise 7.7 in \TB. +We use it in \BaSiX\ to check for syntax errors and uninitialized +variables. + +\subhead Token streams \endhead + +The \BaSiX\ interpreter was designed to be run interactively. It is +called by typing |tex basix|; the file ends waiting for the first line of +\basic\ to be entered at \TeX's |*| prompt. This also allows other files +to |\input basix| and immediately follow it with \basic\ code. + +We cannot have the scanner read an entire line at once, since if the +last line of |basix.tex| were a macro that reads a line as a +parameter, we'd get a ``|File ended while scanning use of \getline|'' +error. Instead, we use a method which at first blush seems more +convoluted but which is actually simpler. + +We note that \TeX\ does not make any distinction between the tokens +that make up our interpreter and the tokens that form the \basic\ +code. The \BaSiX\ interpreter is carefully constructed so that each +macro ends by calling another macro (which may read parameters). +Thus, expansion is never completed, but the interpreter can continue +to absorb individual characters that follow it. These characters +affect the direction of the expansion; it is this behaviour that +allows us to implement a \basic\ interpreter in \TeX. + +\subhead Category codes \endhead + +Normally, \TeX\ distinguishes between sixteen categories of +characters. To avoid unwanted side effects, the \BaSiX\ interpreter +reassigns category codes of all non-letters to category 12, ``other''. +One undocumented feature of \TeX\ is that it will never let you strand +yourself without an ``active'' character (which is normally the +backslash); if you try to reassign the category of your only active +character (with, {\it e.g.,} |\catcode`\\=12|), it will fail silently. +To allow us to use every typeable character in \BaSiX, we first make +|\catcode31=0|, which then allows us to reassign the catcode of the +backslash without stranding ourselves. (Of course, the \BaSiX\ +interpreter provides an escape back to \TeX\ which restores the normal +category codes.) + +We also change the category code of |^^M|, the end-of-line character, +to ``active''. This lets us detect end-of-line errors that may crop +up. + +\subhead etc. \endhead %@ ?????? New section coming here? + +%@ Yeah -- internal representation of data, for instance + +\head Semantics \endhead + +\subhead Words \endhead + +A {\it word\/} is a collection of one or more characters that meet +requirements based on the first character. The following table +describes these rules using {\it regular expression} notation.% +\footnote{$^2$}{In this notation, [A-Z,a-z] means ``any character +falling between A and Z or between a and z, inclusive.'' An asterisk +means ``repeat the preceding specification as many times as needed, or +never.'' A plus means ``repeat the preceeding specification as many +times as needed, at least once.'' A question mark means ``repeat the +preceeding specification zero or one times.'' A dot means ``any +character.''} These rules are: + +\medskip\begingroup\ninepoint %@ Much too wide @ 10pt +\halign{\tt#\hfil&\ \tt#\hfil&\ #\hfil\cr +\rm First &\rm Regular \cr +\noalign{\vskip-2pt} +\rm Character &\rm Expression &\rm Meaning \cr +\noalign{\vskip2pt\hrule\vskip2pt} +[A-Z,a-z] & [A-Z,a-z][A-Z,a-z,0-9]*\$? & Identifier \cr +[0-9] & [0-9]+ & Integer \cr %@ literal \cr Too +" & "[\^{}"]*[",\^{}\^{}M] & String \cr %@ literal \cr Wide +\rm Other & . & Symbol \cr}\endgroup +\medskip + +\noindent +An end-of-line at the end of a string literal is converted to a |"|. + +Everything in \BaSiX\ is one of these four types. Line numbers are +integer literals, and both variables and commands are identifiers. + +The |\scan| macro is used in \BaSiX\ to read the next word. It uses +|\futurelet| to look at the next token and determine whether it should +be part of the current word; {\it i.e.}, whether it matches the +regular expression of the current type. If so, then it is +read in and appended; otherwise |\scan| returns, leaving this next +token in the input stream. The word is returned in the macro |\word|. + +The peculiar way |\scan| operates gives rise to new problems, however. +We can't say +\verbatim +\def\Cgoto{\scan\lineno=\word} +\endverbatim + +\noindent +because |\scan| looks at the tokens which follow it, which in this +case are |\lineno=\word|. We need some way to define the |goto| +command %@ such +so %@ [?] + that the |\scan| is at the end of the macro; this will +take the next tokens from the input stream. We therefore have |\scan| +``return'' to its caller by breaking the caller into two parts; the +first part ends with |\scan| and the second part contains the code +which should follow. The second macro is stored in |\afterscan|, and +|\scan| ends with |\afterscan|. As syntactic sugar, |\after| has been +defined as |\let\afterscan|. This allows |\Cgoto| to be coded as + +\verbatim +\def\Cgoto{\after\gotoPartTwo\scan} +\def\gotoPartTwo{\lineno=\word} +\endverbatim + +\noindent +(Actually, the |goto| code is slightly more complicated than this; but +the scanner is the important point here.) This trick is used +throughout the \BaSiX\ interpreter to read in the next tokens from the +user's input without interrupting the expansion of the \TeX\ macros +that comprise the interpreter. + +\subhead Expressions \endhead + +An {\it expression} is a sequence of words that, roughly speaking, +alternates between {\it values} and {\it operators}. A value is +%@ %@ either [exclusive or does strange things with more than 2 items] +%@ +%@ >webster either +%@ ...lines omitted... +%@ 3. either cj : - used as a function word before two or more coordinate +%@ words, phrases, or clauses joined usu. by or to indicate that what +%@ immediately follows is the first of two or more alternatives +%@ ^^^^^^^ +%@ one of three things:\ %@ +either +a literal, an identifier, or a parenthesized expression. An +operator is one of less-than, more-than, equality, addition, +subtraction, multiplication, division, or reference. (Reference is an +implicit operator that is inserted between a function identifier and +its parameters.) + +Expressions are evaluated in an approach similar to that used in +the scanner. +A word is scanned using |\scan| and its type is determined. +``Left-hand'' values are stored for relatives, additives, +multiplicatives, and references. Using \TeX's grouping operations the +evaluator is reentrant, permitting parenthesized expressions to be +recursively evaluated. + +In order to achieve a functionality similar to that of +|\futurelet|, we exit the evaluator by +\hbox{|\expandafter\aftereval\word|,} %@ [prevent hyphenation] +where the macro \hbox{|\aftereval|} +is analogous to |\afterscan|. Since |\word| will +contain neither macros nor tokens whose category codes need changing, +this is as good as |\futurelet|. + +\head Structure of the Interpreter \endhead + +The file |basix.tex|, which appears as an appendix to this paper, +defines all the macros that are needed to run the +interpreter. The last line of this file is |\endeval|, which is +usually called when the interpreter has finished evaluating a line. +In this case, it calls |\enduserline|, which, in turn, calls +|\parseline|. + +The |\parseline| macro is part of the {\it Program Parser} section of +the interpreter. It starts by calling |\scan| to get the first +word of the next line. If |\word| is an integer literal, it is +treated as a line number and the rest of the input line is stored in +the appropriate variable without interpretation. If |\word| is +not an integer literal, it is treated as a command. + +Each command is treated with an {\it ad hoc} routine near the bottom +of |basix.tex|. However, most of them call on a set of utilities that +appear earlier in the file. + +\subhead Character-string calls \endhead + +There is a simple library of macros that convert between ASCII codes +and character tokens, test for string equality, take subsections of +strings, and deal with concatenation. + +\subhead Debugging definitions \endhead + +The macro |\diw| is a debugging-mode-only |\immediate\write16| (hence +the name |\diw|). It is toggled by the user commands |debug| and +|nodebug|. + +\subhead Expression evaluation \endhead + +The expression evaluator has a calling structure similar +to that of the scanner. Calling routines are split in twain, with + +\verbatim +\def\foo{\after\fooPartTwo\expression} +\def\fooPartTwo{\etc} +\endverbatim + +\noindent +being a prototype of the calling convention. The evaluator will +|\scan| as many words as it can that make sense; in contrast to the +scanner, however, it evaluates each instead of merely +accumulating them. This process is described +above. + +\subhead Linked list \endhead + +The \BaSiX\ interpreter maintains a linked list of line numbers. The +macro + +\everyverbatim{\enablemetacode} +\verbatim +\csname L<current line number>\endcsname +\endverbatim + +\noindent +contains the next line number. These macros will follow the linked +list (for the |list| command); they also can insert a new line or +return the number of the next line. + +\subhead Program parser \endhead + +This section contains a number of critical routines. |\evalline| is +the macro that does the dispatching based on the user's command. +|\mandatory| specifies what the next character must be (for example, +the character after the identifier in a |let| statement must be |=|). +|\parseline| has already been described. + +\subhead Syntactic scanner \endhead + +This is the section containing |\scan| and its support macros, which +are described above. + +\subhead Type tests \endhead + +These routines take an argument and determine whether it is an +identifier, a string variable, a string literal, an integer literal, a +macro, or a digit. The normal way of calling these routines is + +\verbatim +\expandafter\if\stringP\word +\endverbatim + +\noindent +These predicates expand into either |tt| (true) or |tf| (false). +Syntactic sugar is provided in the form of |\itstrue| and |\itsfalse|. +|\ifstring\word| doesn't work because of the way \TeX\ matches |\if| +and |\fi| tokens\Dash\ only |\if|-style primitives are recognized. + +\subhead User Utilities \endhead + +This is the section of the interpreter in which most of the user +commands are defined. Commands are preceded by |\C| ({\it e.g.}, +|\Clist| is the macro called when the user types |list|). Functions +are preceded by |\F|. + +\head Limitations of this implementation \endhead + +\BaSiX\ is a minimal \basic\ interpreter. There are enough pieces to +show how things work, but not enough to do anything practical. Here +is a description of the capabilities of this interpreter, so that the +reader can play with it. Error recovery is virtually non-existant, so +getting the syntax right and not calling non-existent functions is +critical. + +\subhead Entering programs \endhead + +Lines beginning with an integer literal are stored verbatim. Lines +are stored in ascending order, and if two or more lines are entered +with the same number, only the last is retained. + +\subhead Immediate commands \endhead + +Lines not beginning with an integer are executed immediately. Colons +are not supported, so only one command may appear on a line. (When a +program line is executed, its line number is stripped and the +remainder is executed as though it were an immediate command.) + +\subhead Commands \endhead + +The following commands are implemented in some form: |goto|, |run|, +|list|, |print|, |let|, |if|, |debug|, |nodebug|, |rem|, |system|, +|exit|, and |stop| (but not |cont|). The interpreter is case +sensitive (although with an appropriate application of |\uppercase| it +needn't be; I was lazy), so these must be entered in lowercase. + +The following tables list the commands with no parameters, the +commands that take one parameter, and the two commands (|let| and |if|) +that take special forms. + +The commands with no parameters are: + +\medskip{\ninepoint\halign{\tt #\hfil&\ #\hfil\cr +run & Starts execution at the lowest line number. \cr +& Does {\it not} clear variables. \cr +stop & Stops execution immediately. \cr +list & Lists all lines in order. \cr +debug & Useful information sent to terminal. \cr +nodebug & Stop debugging mode. \cr +rem & Rest of line is ignored. \cr +system & Exit \TeX. \cr +exit & Exit \BaSiX\ to \TeX. \cr +}} + +\medskip +The commands with one parameter are: +\medskip + +{\ninepoint\halign{\tt #\hfil&\ #\hfil\cr +goto & Starts execution at the given line number. \cr +list & Lists the given line. \cr +print & Displays the given argument. \cr +}} + +\medskip\noindent +(Any of these arguments may be an expression.) + +The |let| and |if| commands take special forms. Variable assignments +require an explicit |let| command: +||let <identifier> = <expression>|| +Conditionals do not have an |else| clause, and |goto| is not implied +by |then|: +||if <expression> then <new command>|| +The new command is treated as its own line. + +\subhead Expressions \endhead + +Expressions are defined explicitly above. The operators are |+|, |-|, +|*|, |/|, {\tt <}, |=|, and {\tt >}. Parentheses may be used for +grouping. Variables may not be referenced before being set. (Unlike +in traditional \basic, variables are not assumed to be |0| if never +referenced, and they aren't cleared when |run| is encountered). + +Functions are invoked with +||[\lastoption]<function name>(<param>,<param>,...)|| +The parameters are implicitly-delimited expressions that are passed to +|\matheval| (which is simply called |\eval| in the table below to save +space). The following functions are defined: + +{\ninepoint\halign{\tt #\hfil&\ #\hfil\cr +len(string) & Returns number of characters \cr +& \quad in the string. \cr +chr\$(expr) & Returns the character with the \cr +& \quad given ascii value. \cr +inc(expr) & Returns $\hbox{\tt\char`\\eval}(\hbox{\it expr})+1$. \cr +min(expr1,expr2) & Returns the lesser of two {\tt\char`\\eval}s. \cr +}} + +\head Generalization \endhead + +The \BaSiX\ interpreter can easily be generalized to serve other +needs. These other needs might be to interpret Lisp or \ps\ code +[Anyone want to write a \ps\ interpreter in \TeX?]; or to take source +code in a given language and pretty-print it. + +The definition of a ``word'' can be changed by modifying the |\scan| +macro. It selects a definition for |\scantest| based on the first +character; \hbox{|scantest|} %@ prevent hyphenation +is what determines if a given token matches the selected +regular expression. The |\scantest| macro is allowed to redefine +itself. + +The evaluation of expressions can be extended or changed by modifying +the |\math| code. Floating-point (or even fixed-point) numbers could +be dealt with, although the period would need to pass the |\digitP| +test in some cases and not in others. + +The method of dealing with newlines is easily removed for languages +such as \ps\ or Lisp for which all whitespace is the same. + +\head Obtaining copies of basix.tex \endhead + +The source code to this paper and the \BaSiX\ interpreter are +available by anonymous ftp from |gevalt.mit.edu|, which is at IP +address 18.72.1.4. I will also mail out copies to anyone without ftp +abilities. + +\head Summary \endhead + +Using a number of \TeX\ tricks, some more devious than others, a +\basic\ interpreter can be written in \TeX. While \TeX\ macros will +often be less efficient than, for example, |awk| paired with \TeX, +solutions using only \TeX\ will be more portable. A less general +macro package than \BaSiX\ could be written that uses these routines +as paradigms and that is very efficient at parsing a specific input +format. + +\appendix Listing of {\tt basix.tex}\endappendix + +\everyverbatim{} %@ disable this metacode garbage :-) - AMG +\verbfile +{/afs/athena.mit.edu/user/a/amgreene/TeXhax/basix.tex}[\numbered][\smallcode] +\endverbatim + + + +\bye +------- |