* Expand; A semi-universal string expander * Phil Budne @DEC, Feb 5, 1982 * From IOTST by Chris Smith * MAX_N_NT DEFINES THE MAXIMUM NUMBER OF NON_TERMINALS WE CAN DEAL WITH MAX_N_NT = 10 * MAX_N_T DEFINES THE NUMBER OF TERMINALS ANY GIVEN NON_TERM CAN HAVE MAX_N_T = 20 * IF SEC_INP IS NON-EMPTY; IT WILL CONTAIN THE FILENAME OPENED ON I3 * AS THE 'SECONDAY' INPUT SEC_INP = * IF SEC_END IS EVER NON-NULL; SEC_INP HAS HIT EOF SEC_END = * NUMBER OF NONTERMINALS WE HAVE TO REPLACE N_NON_T = 0 * ZERO THE TOTAL OF 'TERMINALS READ TOT_T = 0 * INPUT PATTERN FOR A NON-TERMINAL N_T_PAT = POS(0) "<" ARB . TKN ">" RPOS(0) * PATTERN FOR 'SYSTEM' TOKEN PREFIXES PFX = '$' | '\' * DEFINE SOME ASCII CONSTANTS TAB = ASCII(11) CRLF = ASCII(15) ASCII(12) COMMT = ";" TAB * QUIT UNTIL RUNTIME EXIT(-1) * **************** START HERE AT RUNTIME **************** * ARRAY FROM 1 TO N_NON_T OF TOKENS TO REPLACE NON_TERMS = ARRAY(MAX_N_NT) * ARRAY OF NUMBER OF TERMINALS FOR EACH ELEMENT IN NON_TERMS NUM_TERMS = ARRAY(MAX_N_NT) * ARRAY OF ARRAYS OF TERMINALS FOR EACH ELEMENT IN NON_TERMS TERMS = ARRAY(MAX_N_NT) * ***************************************************************** * * * * * EXPAND SUBROUTINE * * * (MY HERO!) * * * * * ***************************************************************** DEFINE('EXPAND(S)T,N_T,T2,T3,TAB') :(END_EXPAND) EXPAND NCALLS = NCALLS + 1 * LOOP N_T FROM 1 TO N_NON_T * GET THE CORRESPONDING NON TERMINAL & TEST FOR ANY OCCURANCES N_T = 0 EX_LOP N_T = N_T + 1 TOT_T = TOT_T + 1 GT(N_T,N_NON_T) :S(EXPOUT) T2 = NON_TERMS S T2 :F(EX_LOP) TAB = TERMS * TAB HAS ARRAY OF NONTERMS; LOOP FOR ALL ASSOCIATED TERMINALS * REPLACE ALL FIRST OCCURANCE OF NON-TERM AND RECURSE FOR * ALL OF THIS NON TERMINALS TERMINALS T3 = 0 REP_LOP T3 = T3 + 1 GT(T3,NUM_TERMS) :S(RETURN) EXPAND((T = S) ? T2 = TAB) :(REP_LOP) * HERE WHEN NO NON TERMINALS LEFT IN STRING * AOS THE COUNT OF OUTPUTS AND REPLACE ANY * 'PREDEFINED' TOKENS EXPOUT O = PRE_DEF(S) IDENT(SEC_INP) :S(E_INC) O2 = DIFFER(SEC_LINE) PRE_DEF(SEC_LINE) E_INC NUMB = NUMB + 1 OLINES = OLINES + 1 :(RETURN) END_EXPAND * SUBROUTINE TO REPLACE 'SYSTEM' TOKENS; * ::= '$' | '\' * ::= 'n' | 'N' | '#' | '1' DEFINE("PRE_DEF(STR)") :(PRE_END) * TRY "NEWLINE" TOKEN PRE_DEF PRE_DEF = STR PRE_DEF (PFX "n") = CRLF :S(PRE_DEF) PRE_D.1 PRE_DEF (PFX "N") = CRLF :S(PRE_D.1) * TRY "#" INSERTER PRE_D.2 PRE_DEF (PFX "#") = "#" :S(PRE_D.2) * TRY THE MAGIG 'NUMBER' TERMINAL PRE_D.N PRE_DEF (PFX '1') = NUMB :S(PRE_D.N) :(RETURN) PRE_END DEFINE('READ_IN()STR,TKN,TKN2,T1,TARR') :(READ_END) * SUBROUTINE TO INPUT PATTERNS READ_IN TKN2 = TKN = * READ STRINGS AND STUFF THEM AWAY AS TERMINALS. * UNLESS THEY LOOK LIKE * IGNORE LINES THAT START WITH A HASH MARK (#). * ERROR TO NOT GET A TOKEN ON FIRST NON BLANK/COMMENT LINE RD_LOP STR = I :F(RD_EOF) STR (POS(0) "#") :S(RD_LOP) TKN2 = TKN STR N_T_PAT :S(RD_NT) IDENT(TKN2) :S(RD_ERR) T1 = T1 + 1 TARR = STR :(RD_LOP) * HERE WITH A NEW NON TERM. IF THIS IS OUR * FIRST; SKIP A FEW STEPS; ELSE STOW AWAY THE GOODIES RD_NT IDENT(TKN2) :S(RD_1ST) TERMS = TARR NUM_TERMS = T1 * HERE TO GENERATE A NEW NON-TERMIANL SLOT RD_1ST N_NON_T = N_NON_T + 1 NON_TERMS = TKN TARR = ARRAY(MAX_N_T) T1 = 0 :(RD_LOP) * HERE ON TOKEN FILE EOF RD_EOF IDENT(TKN) :S(RD_NIL) TERMS = TARR NUM_TERMS = T1 RD_NIL :S(RETURN) RD_ERR IDENT(STR) :S(RD_LOP) TTY = '? Pattern input error; Terminals input before Non-Terminal' :(FRETURN) READ_END * *************** MAIN PROGRAM **************** * OPEN TTY: IN "TTY" MODE (NO CRLF ON OUTPUT) OUTPUT(.TT,"TTY:","T") * ZERO COUNTERS FOR; CALLS TO EXPAND, LIES OUTPUT, LINES INPUT NCALLS = 0 OLINES = 0 ILINES = 0 * *************** OPEN FILES **************** * FETCH A TOKEN FILE INP TT = "Token input ?" INFILE = TTY :F(END) FILE(INFILE) :F(INP) INPUT(.I,INFILE) :F(INP) * READ IN TOKENS READ_IN() :F(END) INP.2 TT = "Template input ?" F_FILE = TTY :F(END) FILE(F_FILE) :F(INP.2) INPUT(.I2,F_FILE) :F(INP.2) INP.3 TT = "Second input ?" SEC_INP = TTY :F(END) FILE(SEC_INP) :F(INP.3) INPUT(.I3,SEC_INP) :F(INP.3) OUP TT = "Output ?" OUTFILE = TTY :F(END) OUTFILE = IDENT(OUTFILE) "NUL:" TTY = FILE(OUTFILE) DIFFER(OUTFILE) "%Superseding existing file" OUTPUT(.O,OUTFILE) :F(OUP) IDENT(SEC_INP) :S(L.1) OUP2 TT = "Second output ?" SEC_OUT = TTY :F(END) TTY = FILE(SEC_OUT) "%Superseding existing file" OUTPUT(.O2,SEC_OUT) :F(OUP2) L.1 TT = "$1 Initial value ?" NUMB = TTY - 0 :F(END) * **************** MAIN LOOP **************** * LOOP ON THE TEMPLATE (PATTERN) INPUT L.2 FOO = I2 :F(DONE) ILINES = ILINES + 1 * DO SECONDARY INPUT TOO DIFFER(SEC_END) :S(L.3) SEC_LINE = I3 :S(L.3) SEC_END = '*EOF*' TTY = DIFFER(SEC_INP) + "% Secondary input (" SEC_INP ") ran out on line " ILINES L.3 EXPAND(FOO) :(L.2) * BE CUTE DONE TTY = COMMT "EXPAND Run statistics:" TTY = ';' TTY = COMMT N_NON_T " non terminals from: " TAB INFILE TTY = COMMT ILINES " Lines input from:" TAB F_FILE TTY = COMMT OLINES " Lines output to:" TAB OUTFILE TTY = ';' IDENT(SEC_INP) :S(NO_SEC) TTY = COMMT "Secondary input:" TAB SEC_INP TTY = COMMT "Secondary output:" TAB SEC_OUT TTY = ';' NO_SEC TTY = COMMT "Calls to EXPAND:" TAB NCALLS TTY = COMMT "$1 Final value:" TAB TAB NUMB - 1 END