diff options
Diffstat (limited to 'pkg/utilities/nttools/texpand')
-rw-r--r-- | pkg/utilities/nttools/texpand/dbgrules.x | 164 | ||||
-rw-r--r-- | pkg/utilities/nttools/texpand/lexer.x | 114 | ||||
-rw-r--r-- | pkg/utilities/nttools/texpand/lexoper.h | 29 | ||||
-rw-r--r-- | pkg/utilities/nttools/texpand/mkpkg | 21 | ||||
-rw-r--r-- | pkg/utilities/nttools/texpand/mkrules.x | 48 | ||||
-rw-r--r-- | pkg/utilities/nttools/texpand/movelem.x | 113 | ||||
-rw-r--r-- | pkg/utilities/nttools/texpand/movtbrow.x | 43 | ||||
-rw-r--r-- | pkg/utilities/nttools/texpand/parser.com | 6 | ||||
-rw-r--r-- | pkg/utilities/nttools/texpand/parser.x | 283 | ||||
-rw-r--r-- | pkg/utilities/nttools/texpand/pushstack.x | 226 | ||||
-rw-r--r-- | pkg/utilities/nttools/texpand/span.x | 97 | ||||
-rw-r--r-- | pkg/utilities/nttools/texpand/texpand.x | 94 | ||||
-rw-r--r-- | pkg/utilities/nttools/texpand/userules.x | 286 | ||||
-rw-r--r-- | pkg/utilities/nttools/texpand/x_texpand.x | 3 |
14 files changed, 1527 insertions, 0 deletions
diff --git a/pkg/utilities/nttools/texpand/dbgrules.x b/pkg/utilities/nttools/texpand/dbgrules.x new file mode 100644 index 00000000..eeffb8e0 --- /dev/null +++ b/pkg/utilities/nttools/texpand/dbgrules.x @@ -0,0 +1,164 @@ +include <tbset.h> + +define INT_DEFLEN 10 +define REAL_DEFLEN 14 +define DBL_DEFLEN 24 + +# DBGRULES -- Write the non-null rows in a table to a debug file +# +# B.Simon 25-Apr-88 Original + +procedure dbg_rules (tp, title, row1, row2, dbg) + +pointer tp # i: Table descriptor +char title[ARB] # i: Title to print above table +int row1 # i: First row to print +int row2 # i: Last row to print +int dbg # i: File descriptor of debug file +#-- +bool nullflg +double dblval +int pwidth, ncol, irow, icol, jcol, collen, totlen, intval +pointer sp, col,strval, colname, colptr, typptr, lenptr +real realval + +int tbpsta(), tbcnum(), tbcigi(), envgeti(), strlen() + +begin + # First, make sure there is something to print + + if (row2 < row1 || dbg == NULL) + return + + # Allocate dynamic memory for strings + + call smark (sp) + call salloc (strval, SZ_LINE, TY_CHAR) + call salloc (colname, SZ_COLNAME, TY_CHAR) + + # Allocate dynamic memory for column arrays + + ncol = tbpsta (tp, TBL_NCOLS) + call salloc (typptr, ncol, TY_INT) + call salloc (colptr, ncol, TY_INT) + call salloc (lenptr, ncol, TY_INT) + + # Get width of terminal screen + + pwidth = envgeti ("ttyncols") + + # Print title + + call fprintf (dbg, "%s\n") + call pargstr (title) + + # Compute width of each column in output + + jcol = 0 + totlen = 0 + do icol = 1, ncol { + + # Check to see if this column is excluded from the output + + col = tbcnum (tp, icol) + call tbrgtt (tp, col, Memc[strval], nullflg, SZ_LINE, 1, row1) + + if (row1 != row2 || ! nullflg) { + jcol = jcol + 1 + + call tbcigt (col, TBL_COL_NAME, Memc[colname], SZ_COLNAME) + Memi[colptr+jcol-1] = col + Memi[typptr+jcol-1] = tbcigi (col, TBL_COL_DATATYPE) + + # Set column width to default for its type + + switch (Memi[typptr+jcol-1]) { + case TY_SHORT, TY_INT, TY_LONG: + collen = INT_DEFLEN + case TY_REAL: + collen = REAL_DEFLEN + case TY_DOUBLE: + collen = DBL_DEFLEN + default: + collen = - Memi[typptr+jcol-1] + } + + # Adjust width to allow room for column titles + + collen = max (collen, strlen (Memc[colname])) + totlen = totlen + collen + 1 + + # Write the column titles + + if (jcol > 1 && totlen > pwidth) + call fprintf (dbg, "\n") + + if (Memi[typptr+jcol-1] > 0) { + call fprintf (dbg, " %*s") + call pargi (collen) + } else { + call fprintf (dbg, " %*s") + call pargi (-collen) + } + call strupr (Memc[colname]) + call pargstr (Memc[colname]) + + # Set sign to indicate start of new line + + if (jcol > 1 && totlen > pwidth) { + totlen = collen + 1 + Memi[lenptr+jcol-2] = - Memi[lenptr+jcol-2] + } + + Memi[lenptr+jcol-1] = collen + } + } + + # Recompute number of columns and force newline at end of title row + + ncol = jcol + if (ncol > 0) + Memi[lenptr+ncol-1] = - Memi[lenptr+ncol-1] + call fprintf (dbg, "\n") + + # Read the data from the database and write the data to STDOUT + + do irow = row1, row2 { + do jcol = 1, ncol { + + col = Memi[colptr+jcol-1] + collen = abs (Memi[lenptr+jcol-1]) + + switch(Memi[typptr+jcol-1]) { + case TY_SHORT, TY_INT, TY_LONG: + call tbegti (tp, col, irow, intval) + call fprintf (dbg, " %*d") + call pargi (collen) + call pargi (intval) + case TY_REAL: + call tbegtr (tp, col, irow, realval) + call fprintf (dbg, " %*.7g") + call pargi (collen) + call pargr (realval) + case TY_DOUBLE: + call tbegtd (tp, col, irow, dblval) + call fprintf (dbg, " %*.16g") + call pargi (collen) + call pargd (dblval) + default: + call tbegtt (tp, col, irow, Memc[strval], SZ_LINE) + call fprintf (dbg, " %*s") + call pargi (-collen) + call pargstr (Memc[strval]) + } + + if (Memi[lenptr+jcol-1] < 0) + call fprintf (dbg, "\n") + + } + } + + call fprintf (dbg, "\n\n") + call sfree (sp) + +end diff --git a/pkg/utilities/nttools/texpand/lexer.x b/pkg/utilities/nttools/texpand/lexer.x new file mode 100644 index 00000000..cb4d5d7c --- /dev/null +++ b/pkg/utilities/nttools/texpand/lexer.x @@ -0,0 +1,114 @@ +include "lexoper.h" + +define start_ 90 + +# LEXER -- Lexically analyze a rule base +# +# B.Simon 25-Apr-88 Original + +procedure lexer (rb, oper, value, maxch) + +pointer rb # i: Pointer to descriptor of rule base +int oper # o: Operator type found +char value[ARB] # o: Text of operator +int maxch # i: Maximum length of string +#-- +char dic_text[2] +int junk, old_index, dic_index, dic_oper[5] +pointer sp, ch, blanks + +data dic_oper /SEPOPR, IMPOPR, OROPR, ANDOPR, EQOPR/ +string dict "/;/=>/||/&&/=/" + +bool streq() +int getline(), ctowrd(), span(), nospan(), strdic() + +begin + # Allocate an array to hold whitespace + + call smark (sp) + call salloc (blanks, SZ_LINE, TY_CHAR) + + # Skip over leading whitespace + +start_ junk = span (" \t", RB_LINE(rb), RB_INDEX(rb), Memc[blanks], SZ_LINE) + + # Branch on first non-white character + + ch = RB_CHARPTR(rb) + + # End of line or beginning of comment + + if (Memc[ch] == '\n' || Memc[ch] == '#' || Memc[ch] == EOS) { + if (getline (RB_FILE(rb), RB_LINE(rb)) == EOF) { + oper = ENDOPR + value[1] = EOS + } else { + RB_NLINE(rb) = RB_NLINE(rb) + 1 + RB_INDEX(rb) = 1 + goto start_ + } + + # Quoted identifier + + } else if (Memc[ch] == '\'' || Memc[ch] == '"') { + junk = ctowrd (RB_LINE(rb), RB_INDEX(rb), value, maxch) + oper = IDOPR + + # Unquoted identifier + + } else if (nospan ("=&|; \t\n", RB_LINE(rb), RB_INDEX(rb), + value, maxch) > 0 ) { + oper = IDOPR + + # Other operator + + } else { + old_index = RB_INDEX(rb) + junk = span ("=>&|;", RB_LINE(rb), RB_INDEX(rb), value, 2) + dic_index = strdic (value, dic_text, 2, dict) + if (dic_index > 0 && streq (value, dic_text)) { + oper = dic_oper[dic_index] + } else { + RB_INDEX(rb) = old_index + junk = ctowrd (RB_LINE(rb), RB_INDEX(rb), value, maxch) + oper = IDOPR + } + } + + call sfree (sp) +end + +# LEXINIT -- Initialize the lexical analyzer + +procedure lexinit (rbase, rb) + +char rbase[ARB] # i: Name of rule base file +pointer rb # o: Pointer to rule base descriptor +#-- + +int open() +errchk calloc, open + +begin + call malloc (rb, RB_LENGTH, TY_INT) + + RB_FILE(rb) = open (rbase, READ_ONLY, TEXT_FILE) + RB_INDEX(rb) = 1 + RB_NLINE(rb) = 0 + RB_LINE(rb) = EOS +end + +#LEXCLOSE -- Close the lexical analyzer + +procedure lexclose (rb) + +pointer rb # i: Pointer to rule base descriptor +#-- + +errchk close, mfree + +begin + call close (RB_FILE(rb)) + call mfree (rb, TY_INT) +end diff --git a/pkg/utilities/nttools/texpand/lexoper.h b/pkg/utilities/nttools/texpand/lexoper.h new file mode 100644 index 00000000..a4011143 --- /dev/null +++ b/pkg/utilities/nttools/texpand/lexoper.h @@ -0,0 +1,29 @@ + +# LEXOPER.H -- Operators and identifiers used by the lexical analyzer + +# The value of the operator type is also its priority + +define ENDOPR 1 +define SEPOPR 2 +define IMPOPR 3 +define OROPR 4 +define ANDOPR 5 +define EQOPR 6 +define IDOPR 7 + +# Pseudo-identifiers placed on the id stack + +define NAME 1 # Any identifier +define NO_IDENT 0 # No identifier on stack +define PHRASE -1 # idents joined by equals or ands +define CLAUSE -2 # idents joined by equals, ands, or ors + +# Rule base data structure + +define RB_LENGTH (SZ_LINE / SZ_INT32 + 5) + +define RB_FILE Memi[$1] +define RB_NLINE Memi[$1+1] +define RB_INDEX Memi[$1+2] +define RB_LINE Memc[P2C($1+3)] +define RB_CHARPTR (P2C($1+3) + RB_INDEX($1) - 1) diff --git a/pkg/utilities/nttools/texpand/mkpkg b/pkg/utilities/nttools/texpand/mkpkg new file mode 100644 index 00000000..241203bf --- /dev/null +++ b/pkg/utilities/nttools/texpand/mkpkg @@ -0,0 +1,21 @@ +# Update the texpand application code in the ttools package library +# Author: B.Simon, 20-APR-1989 + +$checkout libpkg.a ../ +$update libpkg.a +$checkin libpkg.a ../ +$exit + +libpkg.a: + dbgrules.x <tbset.h> + lexer.x "lexoper.h" + mkrules.x + movelem.x <tbset.h> + movtbrow.x <tbset.h> + parser.x "lexoper.h" + pushstack.x <tbset.h> + span.x + texpand.x + userules.x <tbset.h> + ; + diff --git a/pkg/utilities/nttools/texpand/mkrules.x b/pkg/utilities/nttools/texpand/mkrules.x new file mode 100644 index 00000000..c1dd3aad --- /dev/null +++ b/pkg/utilities/nttools/texpand/mkrules.x @@ -0,0 +1,48 @@ +define SZ_COLVAL SZ_LINE + +# MKRULES -- Add a new rule to the target and action tables +# +# B.Simon 25-Apr-88 Original + +procedure mkrules (work, target, action) + +pointer work # i: Table containing parser results +pointer target # i: Table containing patterns to be matched +pointer action # i: Table containing possible expansions +#-- +int nwork, naction, ntarget, iwork, iaction + +int numstack() + +errchk movtbrow, putstacki + +begin + # Check for null rules + + nwork = numstack (work) + if (nwork <= 0) + return + + # Move the first row from the work table to the target table + + call pushstack (target) + naction = numstack (action) + ntarget = numstack (target) + + call movtbrow (work, 1, target, ntarget) + call putstacki (target, "_FIRST", naction+1) + call putstacki (target, "_LAST", naction+nwork-1) + call putstacki (target, "_USED", NO) + + # Move the remaining rows to the action table + + iaction = naction + do iwork = 2, nwork { + call pushstack (action) + iaction = iaction + 1 + call movtbrow (work, iwork, action, iaction) + } + + call tbrdel (work, 1, nwork) + +end diff --git a/pkg/utilities/nttools/texpand/movelem.x b/pkg/utilities/nttools/texpand/movelem.x new file mode 100644 index 00000000..e9d1f8b4 --- /dev/null +++ b/pkg/utilities/nttools/texpand/movelem.x @@ -0,0 +1,113 @@ +include <tbset.h> + +# MOV_ELEM -- Move an element in one row from one table to another +# +# B.Simon 15-Jan-99 Original +# B.Simon 27-Jan-99 Renamed + +procedure mov_elem (rtp, rcp, rrow, wtp, wcp, wrow) + +pointer rtp # i: Table descriptor of table read from +pointer rcp # i: Column descriptor of column read from +int rrow # i: Row number of table read from +pointer wtp # i: Table descriptor of table written to +pointer wcp # i: Column descriptor of column written to +int wrow # i: Row number of table written to +#-- +int type, nelem, sz_elem, nlen +pointer sp, buf + +int tbcigi(), tbagtb(), tbagtt(), tbagti(), tbagtr(), tbagtd(), tbagts() + +begin + # First, get the type and number of elements in the column + + nelem = tbcigi (rcp, TBL_COL_LENDATA) + type = tbcigi (rcp, TBL_COL_DATATYPE) + + if (type < 0) { + sz_elem = - type + type = TY_CHAR + } else { + sz_elem = 0 + } + + # Allocate buffer to hold values passed between tables + + call smark (sp) + call salloc (buf, nelem*(sz_elem+1), type) + + # Copy the values according to their actual type + + if (nelem == 1) { + # Do not copy null scalar values + + switch (type) { + case TY_BOOL: + call tbegtb (rtp, rcp, rrow, Memb[buf]) + call tbeptb (wtp, wcp, wrow, Memb[buf]) + + case TY_CHAR: + call tbegtt (rtp, rcp, rrow, Memc[buf], sz_elem) + if (Memc[buf] != EOS) + call tbeptt (wtp, wcp, wrow, Memc[buf]) + + case TY_SHORT: + call tbegts (rtp, rcp, rrow, Mems[buf]) + if (! IS_INDEFS (Mems[buf])) + call tbepts (wtp, wcp, wrow, Mems[buf]) + + case TY_INT, TY_LONG: + call tbegti (rtp, rcp, rrow, Memi[buf]) + if (! IS_INDEFI (Memi[buf])) + call tbepti (wtp, wcp, wrow, Memi[buf]) + + case TY_REAL: + call tbegtr (rtp, rcp, rrow, Memr[buf]) + if (! IS_INDEFR (Memr[buf])) + call tbeptr (wtp, wcp, wrow, Memr[buf]) + + case TY_DOUBLE: + call tbegtd (rtp, rcp, rrow, Memd[buf]) + if (! IS_INDEFD (Memd[buf])) + call tbeptd (wtp, wcp, wrow, Memd[buf]) + } + + } else { + # Don't copy zero length arrays + + switch (type) { + case TY_BOOL: + nlen = tbagtb (rtp, rcp, rrow, Memb[buf], 1, nelem) + call tbaptb (wtp, wcp, wrow, Memb[buf], 1, nlen) + + case TY_CHAR: + nlen = tbagtt (rtp, rcp, rrow, Memc[buf], sz_elem, 1, nelem) + if (Memc[buf] != EOS) + call tbaptt (wtp, wcp, wrow, Memc[buf], sz_elem, 1, nlen) + + case TY_SHORT: + nlen = tbagts (rtp, rcp, rrow, Mems[buf], 1, nelem) + if (! IS_INDEFS (Mems[buf])) + call tbapts (wtp, wcp, wrow, Mems[buf], 1, nlen) + + case TY_INT, TY_LONG: + nlen = tbagti (rtp, rcp, rrow, Memi[buf], 1, nelem) + if (! IS_INDEFI (Memi[buf])) + call tbapti (wtp, wcp, wrow, Memi[buf], 1, nlen) + + case TY_REAL: + nlen = tbagtr (rtp, rcp, rrow, Memr[buf], 1, nelem) + if (! IS_INDEFR (Memr[buf])) + call tbaptr (wtp, wcp, wrow, Memr[buf], 1, nlen) + + case TY_DOUBLE: + nlen = tbagtd (rtp, rcp, rrow, Memd[buf], 1, nelem) + if (! IS_INDEFD (Memd[buf])) + call tbaptd (wtp, wcp, wrow, Memd[buf], 1, nlen) + } + } + + call sfree (sp) +end + diff --git a/pkg/utilities/nttools/texpand/movtbrow.x b/pkg/utilities/nttools/texpand/movtbrow.x new file mode 100644 index 00000000..9f9bb3f1 --- /dev/null +++ b/pkg/utilities/nttools/texpand/movtbrow.x @@ -0,0 +1,43 @@ +include <tbset.h> + +# MOVTBROW -- Move columns from one table to another where not null +# +# B.Simon 25-Apr-88 Original +# B.Simon 15-Jan-99 now calls mov_elem + +procedure movtbrow (rtp, rrow, wtp, wrow) + +pointer rtp # i: Table descriptor of table read from +int rrow # i: Row number of table read from +pointer wtp # i: Table descriptor of table written to +int wrow # i: Row number of table written to +#-- +int ncol, icol +pointer sp, rcp, wcp, colname + +pointer tbpsta(), tbcnum() + +begin + call smark (sp) + call salloc (colname, SZ_COLNAME, TY_CHAR) + + ncol = tbpsta (rtp, TBL_NCOLS) + do icol = 1, ncol { + + rcp = tbcnum (rtp, icol) + call tbcigt (rcp, TBL_COL_NAME, Memc[colname], SZ_COLNAME) + call tbcfnd (wtp, Memc[colname], wcp, 1) + +# Column names beginning with an underscore are for internal +# use by the program and do not contain actual data + + if (Memc[colname] != '_' && wcp != NULL) { + + # Copy the row and column in its native type + + call mov_elem (rtp, rcp, rrow, wtp, wcp, wrow) + } + } + + call sfree (sp) +end diff --git a/pkg/utilities/nttools/texpand/parser.com b/pkg/utilities/nttools/texpand/parser.com new file mode 100644 index 00000000..6dba2f6c --- /dev/null +++ b/pkg/utilities/nttools/texpand/parser.com @@ -0,0 +1,6 @@ +# PARSER.COM -- Common block containing pointer to temporary tables + +common / stkptr / ptgt, pact, pwrk + +pointer ptgt, pact, pwrk + diff --git a/pkg/utilities/nttools/texpand/parser.x b/pkg/utilities/nttools/texpand/parser.x new file mode 100644 index 00000000..2dcba75e --- /dev/null +++ b/pkg/utilities/nttools/texpand/parser.x @@ -0,0 +1,283 @@ +include <tbset.h> +include "lexoper.h" + +define MAXSTACK 100 +define SZ_VALSTACK 3*SZ_LINE + +# PARSER -- Parse a rule base file +# +# This procedure uses a simple operator precedence parser. Every token +# retrieved from the file is either an identifier or an operator. +# Identifiers are pushed onto an identifier stack. Operators are +# pushed onto a separate operator stack. When an operator is read +# whose priority is less than that of the operator on top of the +# operator stack, the operator on the stack is popped and passed to +# a procedure which performs the appropriate action, using the +# identifiers on the identifier stack. This continues until all +# operators of higher priority have been processed, or the stack is +# empty. Syntax checking is done by checking that the identifier +# stack contains the correct number and type of identifier and that +# identifiers and operators alternate in the input. The priority of +# each operator is implicit in the integer which is used to represent +# it. For more information on operator precedence parsers, see "Writing +# Interactive Compilers and Interpreters" by P.J Brown, pp. 149-151. +# +# B.Simon 25-Apr-88 Original +# B.Simon 15-Jan-99 Skip rules with columns not in table + +procedure parser (rbase, itp, dbg, target, action) + +char rbase[ARB] # i: Rule base name +pointer itp # i: Input table descriptor +int dbg # i: Debug file descriptor +pointer target # o: Target table descriptor +pointer action # o: Action table descriptor +#-- +include "parser.com" + +bool done, expect_id +int idtop, optop, oper, tabtop, missing +int opstack[MAXSTACK] +pointer sp, rb, work, value, valstack, nxtval, colname, colval +pointer idstack[MAXSTACK] + +string find_error "Column name or type mismatch" +string stack_error "Stack overflow" +string oper_error "Operator expected" +string ident_error "Identifier expected" + +string wrkname "The parser changed the work table to the following:" + +int gstrcpy(), putstackt(), numstack() +pointer initstack() + +errchk initstack, lexinit, lexer, lexclose, syntax, typecheck, mkrules + +begin + # Allocate dynamic memory for strings + + call smark (sp) + call salloc (value, SZ_LINE, TY_CHAR) + call salloc (valstack, SZ_VALSTACK, TY_CHAR) + + # Initialize the lexical analyzer + + call lexinit (rbase, rb) + + # Create tables used by parser + + target = initstack (itp, "_FIRST,_LAST,_USED") + action = initstack (itp, "") + work = initstack (itp, "") + + # Save copy of table pointers in common block + + ptgt = target + pact = action + pwrk = work + + # Initialize stack pointers + + idtop = 0 + optop = 0 + nxtval = valstack + + missing = NO + done = false + expect_id = true + + repeat { + + # Get next operator from rule base + + call lexer (rb, oper, Memc[value], SZ_LINE) + + # First case: operator is identifier, push on id stack + + if (oper == IDOPR) { + if (expect_id) { + idtop = idtop + 1 + if (idtop > MAXSTACK) + call syntax (rb, stack_error) + + idstack[idtop] = nxtval + nxtval = gstrcpy (Memc[value], Memc[nxtval], SZ_LINE) + + nxtval + 1 + } else { + call syntax (rb, oper_error) + } + + # Second case: operator is not identifier + + } else { + if (oper != ENDOPR && expect_id) + call syntax (rb, ident_error) + + # Process all operators whose priorities are >= + # the operator just read from the rule base + + repeat { + if (optop == 0) + break + if (oper > opstack[optop]) + break + + # Perform semantic actions associated with operators + + switch (opstack[optop]) { + case ENDOPR: + call typecheck (rb, idstack, idtop, NO_IDENT, NO_IDENT) + done = true + case SEPOPR: + call typecheck (rb, idstack, idtop, NO_IDENT, NO_IDENT) + case IMPOPR: + call typecheck (rb, idstack, idtop, PHRASE, CLAUSE) + if (missing == NO) { + call mkrules (work, target, action) + } else { + missing = NO + tabtop = numstack (work) + call tbrdel (work, 1, tabtop) + } + idtop = idtop - 2 + case OROPR: + call typecheck (rb, idstack, idtop, CLAUSE, CLAUSE) + idtop = idtop - 1 + idstack[idtop] = CLAUSE + case ANDOPR: + call typecheck (rb, idstack, idtop, PHRASE, PHRASE) + if (missing == NO) + call andstack (work) + + idtop = idtop - 1 + idstack[idtop] = PHRASE + case EQOPR: + call typecheck (rb, idstack, idtop, NAME, NAME) + colval = idstack[idtop] + colname = idstack[idtop-1] + nxtval = colname + call pushstack (work) + if (putstackt (work, Memc[colname], Memc[colval])== NO) + missing = YES + + idtop = idtop - 1 + idstack[idtop] = PHRASE + } + + optop = optop - 1 + + # Debug prints + + tabtop = numstack (work) + call dbg_rules (work, wrkname, 1, tabtop, dbg) + + } until (done) + + # Push the operator just read on the operator stack + + optop = optop + 1 + if (optop > MAXSTACK) + call syntax (rb, stack_error) + opstack[optop] = oper + } + + # Operators and identifiers should alternate in the input + + expect_id = ! expect_id + + } until (done) + + call freestack (work) + call lexclose (rb) + call sfree (sp) +end + +# TYPECHECK -- Check the number and type of identifiers on the stack + +procedure typecheck (rb, idstack, idtop, type1, type2) + +pointer rb # i: Rule base descriptor +pointer idstack[ARB] # i: Identifier stack +int idtop # i: Top of identifier stack +pointer type1 # i: Type expected for one below stack top +pointer type2 # i: Type expected for stack top +#-- +int itype +pointer id, type[2] + +string bad_type "Operator out of order" +string too_few "Missing identifier" +string too_many "Unexpected end of rule" + +begin + type[1] = type1 + type[2] = type2 + + do itype = 1, 2 { + switch (type[itype]) { + case CLAUSE: + + if (idtop < itype) + call syntax (rb, too_few) + id = idstack[idtop+itype-2] + + # a phrase is also a clause + + if (!(id == PHRASE || id == CLAUSE)) + call syntax (rb, bad_type) + + case PHRASE: + + if (idtop < itype) + call syntax (rb, too_few) + id = idstack[idtop+itype-2] + if (id != PHRASE) + call syntax (rb, bad_type) + + case NO_IDENT: + + if (idtop >= itype) + call syntax (rb, too_many) + + case NAME: + + if (idtop < itype) + call syntax (rb, too_few) + id = idstack[idtop+itype-2] + if (id <= 0) + call syntax (rb, bad_type) + + } + } + +end + +# SYNTAX -- Print a syntax error message + +procedure syntax (rb, errmsg) + +pointer rb # i: Rule base descriptor +char errmsg[ARB] # i: Error message +#-- +include "parser.com" + +begin + # Remove temporary tables + + call freestack (ptgt) + call freestack (pact) + call freestack (pwrk) + + # Print the line where the error was detected + + call eprintf ("Syntax error on line %d\n%s%*t^\n") + call pargi (RB_NLINE(rb)) + call pargstr (RB_LINE(rb)) + call pargi (RB_INDEX(rb)) + + # Close the rules file and send the error message + + call lexclose (rb) + call error (ERR, errmsg) + +end diff --git a/pkg/utilities/nttools/texpand/pushstack.x b/pkg/utilities/nttools/texpand/pushstack.x new file mode 100644 index 00000000..58d8b797 --- /dev/null +++ b/pkg/utilities/nttools/texpand/pushstack.x @@ -0,0 +1,226 @@ +include <tbset.h> + +define SZ_COLVAL SZ_LINE + +# The following procedures treat a table as if it were a stack, that is, +# all reading and writing is done at the end of the table. The end of the +# table is indicated by TB_NROWS. +# +# B.Simon 25-Apr-88 Original +# B.Simon 27-Jan-98 Drop temporary tables + +# PUSHSTACK -- Push a null row on the top of a table stack + +procedure pushstack (tp) + +pointer tp # i: Table descriptor +#-- +int top +int tbpsta() + +begin + top = tbpsta (tp, TBL_NROWS) + 1 + call tbtwer (tp, top) +end + +# POPSTACK -- Pop the top row from a table stack + +procedure popstack (tp) + +pointer tp # i: Table descriptor +#-- +int top +int tbpsta() + +begin + top = tbpsta (tp, TBL_NROWS) + if (top > 0) + call tbrdel (tp, top, top) +end + +# NUMSTACK -- Return the number of rows in a table stack + +int procedure numstack (tp) + +pointer tp # i: Table descriptor +#-- +int tbpsta() + +begin + return (tbpsta (tp, TBL_NROWS)) +end + +# INITSTACK -- Initialize a table stack and return its descriptor + +pointer procedure initstack (tp, extra) + +pointer tp # i: Table to use as a template for the table stack +char extra[ARB] # i: Extra columns to add to the table stack +#-- +char comma +int ic, jc +pointer sp, cp, stack, colname, colunits, colfmt, tmproot, tmpfile + +int stridx() +pointer tbtopn() + +errchk tbtopn, tbtcre + +begin + # Set up arrays in dynamic memory + + call smark (sp) + call salloc (colname, SZ_COLNAME, TY_CHAR) + call salloc (colunits, SZ_COLUNITS, TY_CHAR) + call salloc (colfmt, SZ_COLFMT, TY_CHAR) + call salloc (tmproot, SZ_FNAME, TY_CHAR) + call salloc (tmpfile, SZ_FNAME, TY_CHAR) + + # Create the stack table + + call mktemp ("tmp$stk", Memc[tmproot], SZ_FNAME) + call tbtext (Memc[tmproot], Memc[tmpfile], SZ_FNAME) + stack = tbtopn (Memc[tmpfile], NEW_COPY, tp) + + # Set up column information that will not vary across columns + + Memc[colunits] = EOS + Memc[colfmt] = EOS + + # Add column names from the extra string + + ic = 1 + comma = ',' + repeat { + + # Copy the next comma delimeted column name + + jc = stridx (comma, extra[ic]) + if (jc == 0) + call strcpy (extra[ic], Memc[colname], SZ_COLNAME) + else + call strcpy (extra[ic], Memc[colname], jc-1) + ic = ic + jc + + # Create the new column + + if (Memc[colname] != EOS) + call tbcdef (stack, cp, Memc[colname], Memc[colunits], + Memc[colfmt], TY_INT, 1, 1) + + } until (jc == 0) + + # Return the stack table descriptor + + call tbtcre (stack) + call sfree (sp) + + return (stack) +end + +# FREESTACK -- Close and delete a table stack + +procedure freestack (tp) + +pointer tp # i: Table descriptor +#-- +pointer sp, table + +begin + call smark (sp) + call salloc (table, SZ_FNAME, TY_CHAR) + + call tbtnam (tp, Memc[table], SZ_FNAME) + call tbtclo (tp) + + call delete (Memc[table]) + call sfree (sp) +end + +# PUTSTACKT -- Put a text string in the top row of a table stack + +int procedure putstackt (tp, colname, colval) + +pointer tp # i: Table descriptor +char colname[ARB] # i: Column name +char colval[ARB] # i: Column value +#-- +int top, found +pointer cp + +int tbpsta() + +begin + top = tbpsta (tp, TBL_NROWS) + call tbcfnd (tp, colname, cp, 1) + + found = NO + if (cp != NULL) { + ifnoerr { + call tbrptt (tp, cp, colval, ARB, 1, top) + } then { + found = YES + } + } + + return (found) +end + +# PUTSTACKI -- Put an integer in the top row of a table stack + +procedure putstacki (tp, colname, colval) + +pointer tp # i: Table descriptor +char colname[ARB] # i: Column name +int colval # i: Column value +#-- +int top +pointer cp + +int tbpsta() + +begin + top = tbpsta (tp, TBL_NROWS) + + call tbcfnd (tp, colname, cp, 1) + call tbepti (tp, cp, top, colval) + +end + +# ANDSTACK -- Combine the top two rows of the table stack + +procedure andstack (tp) + +pointer tp # i: Table descriptor +#-- +int top +int tbpsta() + +begin + top = tbpsta (tp, TBL_NROWS) + + call movtbrow (tp, top, tp, top-1) + call tbrdel (tp, top, top) +end + +# MOVSTACK -- Move the top row of one table stack to another + +procedure movstack (rtp, wtp) + +pointer rtp # i: Table descriptor of table read from +pointer wtp # i: Table descriptor of table written to +#-- +int rtop, wtop + +int tbpsta() + +begin + call pushstack (wtp) + + rtop = tbpsta (rtp, TBL_NROWS) + wtop = tbpsta (wtp, TBL_NROWS) + + call movtbrow (rtp, rtop, wtp, wtop) + call tbrdel (rtp, rtop, rtop) + +end diff --git a/pkg/utilities/nttools/texpand/span.x b/pkg/utilities/nttools/texpand/span.x new file mode 100644 index 00000000..b8d69141 --- /dev/null +++ b/pkg/utilities/nttools/texpand/span.x @@ -0,0 +1,97 @@ +# SPAN -- Copy characters while they match a set +# +# B.Simon 25-Apr-88 Original + +int procedure span (set, str, ic, outstr, maxch) + +char set[ARB] # i: Set of characters used in matching +char str[ARB] # i: Input string +int ic # io: Index to input string character +char outstr[ARB] # o: Output string +int maxch # i: Maximum length of output string +#-- +bool match +int jc, kc, setlen + +int strlen() + +begin + # Loop over characters in the input string + + setlen = strlen (set) + for (jc = 1; str[ic] != EOS && jc <= maxch; ic = ic + 1) { + + # See if the current character in the input string + # matches the characters in the set + + match = false + do kc = 1, setlen { + if (str[ic] == set[kc]) { + match = true + break + } + } + + # Copy character to the output string if it matches + + if (! match) + break + + outstr[jc] = str[ic] + jc = jc + 1 + + } + + # Return number of characters in output string + + outstr[jc] = EOS + return (jc - 1) +end + +# NOSPAN -- Copy characters while they do not match a set + +int procedure nospan (set, str, ic, outstr, maxch) + +char set[ARB] # i: Set of characters used in matching +char str[ARB] # i: Input string +int ic # io: Index to input string character +char outstr[ARB] # o: Output string +int maxch # i: Maximum length of output string +#-- +bool match +int jc, kc, setlen + +int strlen() + +begin + # Loop over characters in the input string + + setlen = strlen (set) + for (jc = 1; str[ic] != EOS && jc <= maxch; ic = ic + 1) { + + # See if the current character in the input string + # matches the characters in the set + + match = false + do kc = 1, setlen { + if (str[ic] == set[kc]) { + match = true + break + } + } + + # Copy character to the output string if it does not match + + if (match) + break + + outstr[jc] = str[ic] + jc = jc + 1 + + } + + # Return number of characters in output string + + outstr[jc] = EOS + return (jc - 1) +end diff --git a/pkg/utilities/nttools/texpand/texpand.x b/pkg/utilities/nttools/texpand/texpand.x new file mode 100644 index 00000000..c89075c1 --- /dev/null +++ b/pkg/utilities/nttools/texpand/texpand.x @@ -0,0 +1,94 @@ +include <fset.h> + +# TEXPAND -- Expand the rows of a table according to a set of rules +# +# B.Simon 25-Apr-88 Original +# Phil Hodge 4-Oct-95 Use table name template routines tbnopenp, etc. + +procedure texpand () + +#-- +pointer ilist # Input file name template +pointer olist # Output file name template +pointer rbase # Name of file containing expansion rules +pointer debug # Debug file name +bool verbose # Diagnostic message flag + +int junk, dbg +pointer sp, itp, otp, input, output, target, action + +bool clgetb() +int open(), tbnlen(), tbnget() +pointer tbnopenp(), tbtopn() + +begin + # Allocate dynamic memory for strings + + call smark (sp) + call salloc (input, SZ_FNAME, TY_CHAR) + call salloc (output, SZ_FNAME, TY_CHAR) + call salloc (rbase, SZ_FNAME, TY_CHAR) + call salloc (debug, SZ_FNAME, TY_CHAR) + + # Read the parameter file + + ilist = tbnopenp ("input") + olist = tbnopenp ("output") + call clgstr ("rbase", Memc[rbase], SZ_FNAME) + call clgstr ("debug", Memc[debug], SZ_FNAME) + verbose = clgetb ("verbose") + + # Open debug file + + if (Memc[debug] == ' ' || Memc[debug] == EOS) + dbg = NULL + else + dbg = open (Memc[debug], NEW_FILE, TEXT_FILE) + + # Check to see that input & output templates + # have same number of files + + if (tbnlen (ilist) != tbnlen (olist)) + call error (ERR, "Number of input and output tables do not match") + + while (tbnget (ilist, Memc[input], SZ_FNAME) != EOF) { + + junk = tbnget (olist, Memc[output], SZ_FNAME) + + # Open input and output tables + + itp = tbtopn (Memc[input], READ_ONLY, NULL) + otp = tbtopn (Memc[output], NEW_COPY, itp) + call tbtcre (otp) + call tbhcal (itp, otp) + + # Create target and action tables from the rule base + + call parser (Memc[rbase], itp, dbg, target, action) + + # Expand the rows of the input table using the rules + # encoded in the target and action tables + + call use_rules (itp, otp, target, action, dbg, verbose) + + # Print diagnostic message and close tables + + if (verbose) { + call tbtnam (itp, Memc[input], SZ_FNAME) + call tbtnam (otp, Memc[output], SZ_FNAME) + + call printf ("%s -> %s\n") + call pargstr (Memc[input]) + call pargstr (Memc[output]) + call flush (STDOUT) + } + + call tbtclo (itp) + call tbtclo (otp) + } + + call close (dbg) + call tbnclose (ilist) + call tbnclose (olist) + call sfree (sp) +end diff --git a/pkg/utilities/nttools/texpand/userules.x b/pkg/utilities/nttools/texpand/userules.x new file mode 100644 index 00000000..6195b148 --- /dev/null +++ b/pkg/utilities/nttools/texpand/userules.x @@ -0,0 +1,286 @@ +include <tbset.h> + +# USE_RULES -- Use the rules to expand the input table rows +# +# B.Simon 25-Apr-88 Original +# B.Simon 21-Jan-99 Modified to handle empty target tables + +procedure use_rules (itp, otp, target, action, dbg, verbose) + +pointer itp # i: Input table +pointer otp # i: Output table +pointer target # u: Table of rule targets +pointer action # u: Table of rule actions +int dbg # i: Debug file descriptor +bool verbose # i: Print diagnostic message +#-- +int top, nrow, irow +pointer work + +int tbpsta() +int initstack(), numstack(), find_rule(), apply_rule() + +string tgtname "The following is the target table:" +string actname "The following is the action table:" +string isstart "The following row is read from the input table:" +string isdone "The following row is moved to the output table:" + +begin + # Do straight copy if target table is empty + + top = numstack (target) + if (top == 0) { + call no_rule (itp, otp) + return + } + + # Print target and action tables + + call dbg_rules (target, tgtname, 1, top, dbg) + + top = numstack (action) + call dbg_rules (action, actname, 1, top, dbg) + + # Create a work table, which is used to store + # intermediate results + + work = initstack (itp, "_TARGET,_INDEX") + + # Loop over each row in the input table + + nrow = tbpsta (itp, TBL_NROWS) + do irow = 1, nrow { + + call dbg_rules (itp, isstart, irow, irow, dbg) + + # Push the next row from the input table + # into the work table. If it does not match + # any rule, write it to the output table. + + call pushstack (work) + call movtbrow (itp, irow, work, 1) + if (find_rule (target, work) == 0) { + top = numstack (work) + call dbg_rules (work, isdone, top, top, dbg) + call movstack (work, otp) + } + + # Apply the next instance of the rule to the + # row on top of the stack. If the result of the + # application of the rule does not match any other + # rule, write it to the output table. + + while (numstack (work) > 0) { + if (apply_rule (target, action, work, dbg) == 0) { + top = numstack (work) + call dbg_rules (work, isdone, top, top, dbg) + call movstack (work, otp) + if (verbose && mod (numstack (otp), 25) == 0) { + call printf ("\r%d rows written to output table") + call pargi (numstack (otp)) + call flush (STDOUT) + } + } + } + } + + if (verbose) { + call printf ("\r%39w\r") + call flush (STDOUT) + } + + call freestack (target) + call freestack (action) + call freestack (work) +end + +# APPLY_RULE -- Expand the top work table row according to a rule + +int procedure apply_rule (target, action, work, dbg) + +pointer target # i: Table of rule targets +pointer action # i: Table of rule actions +pointer work # i: Table of intermediate results +int dbg # i: Debug file descriptor +#-- +int wrow, trow, arow, last, rule +pointer tgt_ptr, idx_ptr, lst_ptr, use_ptr + +string isrule "The following rule is applied:" +string notdone "To produce the row:" + +int numstack(), find_rule() + +begin + # Get column pointers of special columns + + call tbcfnd (work, "_TARGET", tgt_ptr, 1) + call tbcfnd (work, "_INDEX", idx_ptr, 1) + call tbcfnd (target, "_LAST", lst_ptr, 1) + + # Get the current row numbers for the work, target, + # and action tables + + wrow = numstack (work) + call tbegti (work, tgt_ptr, wrow, trow) + call tbegti (work, idx_ptr, wrow, arow) + call tbegti (target, lst_ptr, trow, last) + + # If the action row number is greater than the last action + # associated with the target, all the expansions for this + # rule have been performed. Pop the work table and mark the + # target row as unused. + + if (arow > last) { + call popstack (work) + call tbcfnd (target, "_USED", use_ptr, 1) + call tbepti (target, use_ptr, trow, NO) + rule = trow + + # Otherwise, duplicate the top row of the work table and + # overwrite the appropriate columns with the values stored + # in the action row. Increment the action row for next time. + # Initialize the special columns in the new row of the work + # table. + + } else { + call pushstack (work) + call movtbrow (work, wrow, work, wrow+1) + call movtbrow (action, arow, work, wrow+1) + call tbepti (work, idx_ptr, wrow, arow+1) ## should be wrow+1 ?? + call dbg_rules (target, isrule, trow, trow, dbg) + call dbg_rules (work, notdone, wrow+1, wrow+1, dbg) + rule = find_rule (target, work) + } + + return (rule) +end + +# FIND_RULE -- Find the target row which matches the top work table row + +int procedure find_rule (target, work) + +pointer target # i: Table of rule targets +pointer work # i: Table of intermediate results +#-- +bool match, nullflg +int icol, jcol, tcol, wcol, trow, irow, wrow, used, first +pointer sp, tarptr, wrkptr, colname, tarval, wrkval +pointer use_ptr, fst_ptr, tgt_ptr, idx_ptr, iw + +bool strne() +int tbpsta(), strlen() +pointer tbcnum(), numstack() + +begin + # Get number of columns in tables + + tcol = tbpsta (target, TBL_NCOLS) + wcol = tbpsta (work, TBL_NCOLS) + + # Allocate dynamic memory + + call smark (sp) + call salloc (tarptr, tcol, TY_INT) + call salloc (wrkptr, tcol, TY_INT) + call salloc (colname, SZ_COLNAME, TY_CHAR) + call salloc (tarval, SZ_LINE, TY_CHAR) + call salloc (wrkval, SZ_LINE, TY_CHAR) + + # Create arrays of corresponding column pointers + # in the target and work tables + + jcol = 0 + do icol = 1, tcol { + Memi[tarptr+jcol] = tbcnum (target, icol) + call tbcigt (Memi[tarptr+jcol), TBL_COL_NAME, + Memc[colname], SZ_COLNAME) + call tbcfnd (work, Memc[colname], Memi[wrkptr+jcol], 1) + if (Memc[colname] != '_' && Memi[wrkptr+jcol] != NULL) + jcol = jcol + 1 + } + + # Get pointers to special columns + + call tbcfnd (target, "_USED", use_ptr, 1) + call tbcfnd (target, "_FIRST", fst_ptr, 1) + call tbcfnd (work, "_TARGET", tgt_ptr,1) + call tbcfnd (work, "_INDEX", idx_ptr, 1) + + # Search for a match in the target table + # with the top row of the work table + + match = false + wrow = numstack (work) + trow = tbpsta (target, TBL_NROWS) + do irow = 1, trow { + + call tbegti (target, use_ptr, irow, used) + if (used == NO) { + + # Compare each non-null column of the target row + # to the work row + + match = true + do icol = 1, jcol { + call tbrgtt (target, Memi[tarptr+icol-1], Memc[tarval], + nullflg, SZ_LINE, 1, irow) + + if (! nullflg) { + call tbegtt (work, Memi[wrkptr+icol-1], wrow, + Memc[wrkval], SZ_LINE) + + iw = strlen (Memc[wrkval]) + wrkval - 1 + while (Memc[iw] == ' ') + iw = iw - 1 + Memc[iw+1] = EOS + + if (strne (Memc[tarval], Memc[wrkval])) { + match = false + break + } + } + } + + # If the rows match, mark the target row as used + # and initialize the special columns in the work row + + if (match) { + + call tbepti (target, use_ptr, irow, YES) + + call tbegti (target, fst_ptr, irow, first) + call tbepti (work, idx_ptr, wrow, first) + call tbepti (work, tgt_ptr, wrow, irow) + + break + } + } + } + + call sfree (sp) + + # If a match was found, return the target row number matched + + if (match) + return (irow) + else + return (0) +end + +# NO_RULE -- Do a straight copy when ther are no expansion rules + +procedure no_rule (itp, otp) + +pointer itp # i: Input table +pointer otp # i: Output table +#-- +int irow, nrow +int tbpsta() + +begin + nrow = tbpsta (itp, TBL_NROWS) + + do irow = 1, nrow + call tbrcpy (itp,otp, irow, irow) +end diff --git a/pkg/utilities/nttools/texpand/x_texpand.x b/pkg/utilities/nttools/texpand/x_texpand.x new file mode 100644 index 00000000..37d7f51e --- /dev/null +++ b/pkg/utilities/nttools/texpand/x_texpand.x @@ -0,0 +1,3 @@ +# X_TEXPAND -- Dummy main routine for texpand + +task texpand = texpand |