Mercurial > ~dholland > hg > ag > index.cgi
diff tests/agcl/oldagsrc/cc-crash.syn @ 0:13d2b8934445
Import AnaGram (near-)release tree into Mercurial.
author | David A. Holland |
---|---|
date | Sat, 22 Dec 2007 17:52:45 -0500 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/agcl/oldagsrc/cc-crash.syn Sat Dec 22 17:52:45 2007 -0500 @@ -0,0 +1,1366 @@ +{ // C Prologue +/* + AnaGram, a System for Syntax Directed Programming + + A Dos Script Language + + Copyright (c) 1993, 1996 Parsifal Software. + All Rights Reserved. + +*/ + + +#include "stack.h" +#include "charsink.h" +#include "strdict.h" +#include "array.h" +#include "symbol.h" +#include "query.h" +#include <conio.h> + +#ifdef __BCPLUSPLUS__ + #define ARGS ((char **) args) + + extern unsigned _stklen = 0x4000; // set stack size + +#else + #define ARGS ((char const * const *) (char **) args) +#endif + + +// Define stacks for temporary storage + +stack <action_pointer> as(25); // Stack actions +stack <int> is(100); // Stack string indices +stack <char *> ps(1000,20); // Stack parameter strings +stack <query_item> qs(23); // Stack query items + + +// Define data structures for symbol table + +#define N_STRINGS 2000 + +string_accumulator sa(64000U,500); +string_dictionary sd(N_STRINGS); +array <symbol_table_entry> st(N_STRINGS); + +} // End of C Prologue + + +// Character Set Definitions + +digit = '0-9' +eof = 0 + ^Z +letter = 'a-z' + 'A-Z' + '_' +not double quote = ~eof - ('"' + '\\' + '\n') +not eol = ~(eof + '\n') +not paren = ~(eof + '(' + ')') +not single quote = ~eof - ('\'' + '\\' + '\n') +operator = '#' + '=' + '<' + '>' + '|' +punctuation = '(' + ')' + '{' + '}' + '[' + ']' + '"' + '\n' +text char = ~(eof + operator + white + punctuation + '@') +white = ' ' + '\t' + '\v' + '\f' + '\r' + + +// Configuration Section + +[ + // White space control + disregard ws + lexeme {literal, integer constant, string literal, paren string, + character constant, eol, literals} + distinguish lexemes + + // parser configuration + pointer input + context type = action_pointer + distinguish keywords {letter + digit} + parser file name = "#.cpp" + + // Debugging options + line numbers + test file mask = "*.dsl" +] + + +// White Space Definitions + +ws + -> white | comment + +comment + -> comment head, "*/" + +comment head + -> "/*" + -> comment head, ~eof + +// Comment out one of the following two productions to determine whether +// comments nest or not + +comment head + -> comment head, comment // comments nest + +/* +comment + -> comment head, comment // comments do not nest +*/ + +eol + -> '\n' + -> "//", not eol?..., '\n' // C++ style comments + + + +// Script File Description + +script file $ + -> [execution block | declaration | eol]..., eof + + +// Dos Command and Parameter Recognition + +word + -> paren string + -> string literal + -> undeclared variable:v =++sa << sd[v], lookup(); + -> word, '[', !sa << '[';, + parameter string, ']' =concat(sa) << ']', lookup(); + +string + -> word + -> string, '#', word =concat(sa); + +parameter string + -> param word + -> parameter string, '#', + param word =concat(sa); + +literal + -> text char:c =++sa << c; + -> literal, text char:c =sa << c; + +param word + -> word + -> action text =action_string(); + + +// Gather, but do not execute, the text of an action block + +action text + -> action text head, '}' + +action text head + -> '{' =as << CONTEXT; + -> action text head, action word + -> action text head, eol + -> action text head, action text ={action_pointer a; as >> a;} + -> action text head, operator + + +action word + -> paren string + -> string literal + -> literal + -> action word, '[', parameter string, ']' + +/***** + + Parenthesized string + + May contain any characters inside balanced parentheses. If parentheses + are included, they must balance. Outer parentheses are stripped before + use. + +*****/ + +paren string + -> paren string chars, ')' + +paren string chars + -> '(' =++sa; + -> paren string chars, paren string char + +paren string char + -> not paren:c =sa << c; + -> !sa << '(';, paren string chars, ')' =concat(sa) << ')'; + + +/***** + + String Literal + + Follows the same rules as for string literals in C and C++ + +*****/ + +string literal + -> string chars, '"' + +string chars + -> '"' =++sa; + -> string chars, string char + +string char + -> not double quote:c =sa << c; + -> escape sequence:c =sa << c; + +(int) escape sequence + -> "\\a" ='\a'; + -> "\\b" ='\b'; + -> "\\f" ='\f'; + -> "\\n" ='\n'; + -> "\\r" ='\r'; + -> "\\t" ='\t'; + -> "\\v" ='\v'; + -> "\\\\" ='\\'; + -> "\\?" = '\?'; + -> "\\'" ='\''; + -> "\\\"" ='"'; + -> octal escape + -> hex escape + +(int) octal escape + -> one octal | two octal | three octal + +(int) one octal + -> '\\', '0-7':d =d-'0'; + +(int) two octal + -> one octal:n, '0-7':d =8*n + d-'0'; + +(int) three octal + -> two octal:n, '0-7':d =8*n + d-'0'; + +(int) hex escape + -> "\\x", hex number:n =(int) n; + +(long) hex number + -> hex digit + -> hex number:n, hex digit:d =16*n + d; + +[ + sticky {one octal, two octal, hex number} +] + + +/***** + + Command Line Interpretation + + The identifier may be the name of a DOS command, internal or external, + a path name of an arbitrary executable, or an internal commmand of the + scripting language. It may appear literally, or may be the result of + string concatenation and substitution. + + command is used in the program logic section, below. + +*****/ + +command + -> identifier, parameters? =exec(); + -> identifier, parameters?, + '<', parameter string =exec_redirect_in(); + -> piped command:file, '|', + identifier, parameters? =exec_pipe_in(file); + -> piped command:file, '>', + parameter string =grab_output(file); + -> piped command:file, ">>", + parameter string =append_output(file); + +(char *) piped command + -> identifier, parameters? =exec_pipe_out(); + -> identifier, parameters?, + '<', parameter string =exec_redirect_in_pipe_out(); + -> piped command:file, '|', + identifier, parameters? =exec_pipe_in_pipe_out(file); + +identifier + -> string =sa << 0, ++ps << sa; + +parameters + -> parameter string =ps << sa, sa << 0; + -> parameters, parameter string =ps << sa, sa << 0; + + +/***** + + Program logic. + + This section of syntax controls the interpretation of a sequence + of commands enclosed within braces. + +*****/ + +execution block + -> '{', eol?...,[command sequence, eol?... | if sequence, eol?...], '}' + + +/***** + + A command sequence is any sequence of statements and + if statements that ends with a statement. + +*****/ + +command sequence + -> statement + -> command sequence, eol..., statement + -> if sequence, eol..., statement + -> if sequence:pc, eol?..., + "else", action text =do_if(pc,1); + +/***** + + An if sequence is any direct sequence of statements and if statements + that ends with an if statement. The difference between an "if sequence" and + a "command sequence" is that an else clause may follow the "if sequence". + +*****/ + +(int) if sequence + -> if statement + -> if sequence, eol..., if statement:cc =cc; + -> command sequence, eol..., if statement:cc =cc; + -> if sequence:pc, eol?..., "else", eol?..., + if condition:cc, action text =do_if(pc,cc!=0); + +(int) if condition + -> "if", + '(', conditional exp:cc, ')' =(int) cc; + +(int) if statement + -> if condition:cc, action text =do_if(0,cc != 0); + +/***** + + A statement is any command that isn't an if or else statement. + The iteration on the while statement is a ruse. + +*****/ + +statement + -> command + -> assignment + -> for statement + -> declaration + -> screen description + -> while statement... + + +/***** + + Assignment statements + + There are four varieties of assignment statement depending on whether + or how the variable on the left hand side has been previously declared. + +*****/ + +assignment + -> undeclared variable:v, '=', + parameter string =assign_value(v); + -> integer variable:v, '=', + conditional exp:x, ';'? =st[v].data.integer = (int) x; + -> string variable:v, '=', + string exp, ';'? =st[v].data.text = copy(sa--); + -> string variable:v, '@', + primary exp:n, '=', + conditional exp:x, ';'? =st[v].data.text[(unsigned)n] = (char) x; + + +/***** + + Semantically determined production to determine treatment of variable + on left side of assignment statement. + +*****/ + +(unsigned) integer variable, + string variable, + undeclared variable + -> literal =check_integer(); + + +/***** + + While Statement + + The While statement loops by simply resetting the input pointer for + the parser back to the beginning of the while loop. This is the reason + for the iteration of the while statement in the production for "simple + command". + +*****/ + +while statement + -> "while", '(', conditional exp:cc, ')', + action text =do_while(cc != 0); + + +/***** + + + + For Statement + + This for statement corresponds to the for statement in the DOS batch + programming language, not the for statement in C. + +*****/ + +for statement + -> "for", name, // !++sa << '(';, + "in", parameter string, + "do"?, action text =do_for_loop(); + + +/***** + + Declaration statements + +*****/ + +declaration + -> "action", literals:n, + action text =define_action(n); + -> "int", + name, '=', conditional exp:x, ';'? =define_integer(sa--, x); + -> "string", + name, '=', string exp, ';'? =define_string(); + +(int) literals + -> literal =0; + -> literals:n, ws..., literal =n+1; + + +name + -> letter:c =++sa << c; + -> name, letter:c =sa << c; + -> name, digit:c =sa << c; + + +/***** + + Integer and String Expression Logic + + The syntax for expressions is essentially that of C, with the addition + of string comparison. The only missing operators are ++, --, and comma. + +*****/ + + +(long) conditional exp + -> logical or exp + -> logical or exp:c, '?', conditional exp:x, ':', + conditional exp:y = c != 0 ? x : y; + +(long) logical or exp + -> logical and exp + -> logical or exp:x, "||", + logical and exp:y =x != 0 || y!=0; + +(long) logical and exp + -> inclusive or exp + -> logical and exp:x, "&&", + inclusive or exp:y =x != 0 && y !=0; + +(long) inclusive or exp + -> exclusive or exp + -> inclusive or exp:x, '|', + exclusive or exp:y =x | y; + +(long) exclusive or exp + -> and exp + -> exclusive or exp:x, '^', and exp:y =x ^ y; + +(long) and exp + -> equality exp + -> and exp:x, '&', equality exp:y =x & y; + +(long) equality exp + -> relational exp + -> equality exp:x, "==", relational exp:y =x == y; + -> equality exp:x, "!=", relational exp:y =x != y; + -> string exp, "==", string exp =string_comp() == 0; + -> string exp, "!=", string exp =string_comp() != 0; + + +(long) relational exp + -> shift exp + -> relational exp:x, '<', shift exp:y =x < y; + -> relational exp:x, '>', shift exp:y =x > y; + -> relational exp:x, "<=", shift exp:y =x <= y; + -> relational exp:x, ">=", shift exp:y =x >= y; + -> string exp, '<', string exp =string_comp() < 0; + -> string exp, '>', string exp =string_comp() > 0; + -> string exp, "<=", string exp =string_comp() <= 0; + -> string exp, ">=", string exp =string_comp() >= 0; + +(long) shift exp + -> additive exp + -> shift exp:x, "<<", additive exp:y =x << (int) y; + -> shift exp:x, ">>", additive exp:y =x >> (int) y; + +(long) additive exp + -> multiplicative exp + -> additive exp:x, '+', + multiplicative exp:y =x + y; + -> additive exp:x, '-', + multiplicative exp:y =x - y; + +(long) multiplicative exp + -> unary exp + -> multiplicative exp:x, '*', unary exp:y =x * y; + -> multiplicative exp:x, '/', nonzero:y =x / y; + -> multiplicative exp:x, '%', nonzero:y =x % y; + +(long) nonzero + -> unary exp: x ={ + assert(x); + return x; + } + +(long) unary exp + -> primary exp + -> '+', unary exp:x =x; + -> '-', unary exp:x =-x; + -> '~', unary exp:x =~x; + -> '!', unary exp:x =!x; + +(long) primary exp + -> integer constant + -> character constant + -> string term,'@', primary exp:n =((unsigned char *) sa--)[(unsigned) n]; + -> '#', string element ={ + long temp; + sscanf(sa--, "%ld", &temp); + return temp; + } + -> numeric name + -> '(', conditional exp:x, ')' =x; + -> built_in name:x, built_in argument =(*st[(unsigned)x].data.func)(); + +built_in argument + -> '(', parameter string, ')' + +(long) numeric name, + string name, + built_in name, + undefined name + -> name =name_type(); + + +/***** + + String Expressions + +*****/ + +string exp + -> string term + -> string exp, '#', string term =concat(sa); + +string term + -> string element + -> string term, '@', '(', + conditional exp:first, "..", + conditional exp:last, ')' =extract((unsigned)first, (unsigned) last); + -> string term, '[', !sa << '[';, + parameter string, ']' =concat(sa) << ']', lookup(); + +string element + -> string literal + -> string name:x =++sa << st[(unsigned)x].data.text; + -> undefined name:x =++sa << sd[(unsigned)x]; + -> action text =action_string(); + -> '=', primary exp:x =++sa,sa.printf("%ld",x); + -> '(', string exp, ')' + +/***** + + Integer constants + + The syntax for integer constants is identical to that in C. + +*****/ + +integer constant + -> hex constant + -> octal constant + -> decimal constant + +(long) hex constant + -> {"0x" | "0X"} =0; + -> hex constant:x, hex digit:d =16*x + d-'0'; + +(long) hex digit + -> '0-9' + -> 'a-f' + 'A-F':d =(d&7) + 9; + +(long) octal constant + -> '0' =0; + -> octal constant:n, '0-7':d =8*n + d-'0'; + +(long) decimal constant + -> '1-9':d =d-'0'; + -> decimal constant:n, '0-9':d =10*n + d-'0'; + + +/***** + + Character Constant + + The rules for character constant are the same as in C. + +*****/ + +(int) character constant + -> '\'', char constant element:c, '\'' =c; + +(int) char constant element + -> not single quote + -> escape sequence + + +/***** + + Screen Display + +*****/ + +screen description + -> screen items:scd, '}' =display_queries(scd); + +(screen_descriptor *) screen items + -> "screen", '{' =reset(qs), new screen_descriptor; + -> screen items, eol + -> screen items:scd, + "title", '=', + formula, eol =scd->title = formula(), scd; + -> screen items:scd, + color spec:c, eol =scd->color = (char) c, scd; + -> screen items:scd, + "entry", color spec:c, eol =scd->entry_color = (char) c, scd; + -> screen items:scd, + "highlight", color spec:c, eol =scd->highlight_color = (char) c, scd; + -> screen items:scd, + "size", '=', conditional exp:w, + ',', conditional exp:h =scd->width = (unsigned)w, scd->height = (unsigned) h, scd; + -> screen items:scd, + "location", '=', conditional exp:px, + ',', conditional exp:py =scd->pos.x = (unsigned) px,scd->pos.y = (unsigned) py, scd; + -> screen items:scd, + query line:q, '}', eol =qs << *q, delete q, scd; + -> screen items:scd, + button line:q, '}', eol =qs << *q, delete q, scd; + +(int) color spec + -> "color", '=', conditional exp:fg, + ',', conditional exp:bg =COLOR((unsigned)fg,(unsigned)bg); + + +(query_item *) query line + -> "field", '{' =clear(new query_item); + -> query line, eol + -> query line:q, + "variable", '=', + literal, eol =q->id = sd << sa--, q; + -> query line:q, + "default", '=', + formula, eol =q->value = formula(), q; + -> query line:q, + "prompt", '=', + formula, eol =q->prompt = formula(), q; + -> query line:q, + "explanation", '=', + formula, eol =q->explanation = formula(),q; + +(query_item *) button line + -> "button", '{' =clear(new query_item); + -> button line, eol + -> button line:q, + "prompt", '=', formula, eol =q->prompt = formula(), q; + -> button line:q, + "explanation", '=', + formula, eol =q->explanation = formula(),q; + -> button line:q, + action text, eol =q->action = copy_action(), q; + +formula + -> formula element =reset(is) << (sd << sa--); + -> formula, '#', formula element =is << (sd << sa--); + +formula element + -> paren string + -> string literal + -> literal + -> formula element, '[', !sa << '[';, + parameter string, ']' =concat(sa) << ']'; + +{ + +#include <process.h> +#include <stdlib.h> +#include <ctype.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <io.h> +#include <conio.h> +#include <dos.h> +#include <time.h> +#include "assert.h" + +#include "edit.h" + + +#include "screen.h" +#include "util.h" +#include "redirect.h" + +#define GET_CONTEXT CONTEXT.pointer = PCB.pointer;\ + CONTEXT.line=PCB.line;\ + CONTEXT.column = PCB.column; + + +int debug_switch = 0; +char *error_msg = NULL; +unsigned errorlevel_index; +int errorlevel; +int exitcode = 0; +int exitflag = 0; +int first_line = 1; +int first_column = 1; +unsigned stderr_index; + +void display_queries(screen_descriptor *); + +#define FIRST_LINE first_line +#define FIRST_COLUMN first_column + + +/***** + + Internal Functions + +*****/ + +long file_exists(void) { + FILE *f = fopen(sa--,"r"); + if (f != NULL) fclose(f); + return f != NULL; +} + +long directory_exists(void) { + struct find_t ff; + int result; + + sa << "\\*.*"; + result = _dos_findfirst(sa--,_A_SUBDIR,&ff); + return result == 0; +} + +long string_length(void) { + return size(sa--); +} + +long get_file_length(void) { + int handle = open(sa--, O_RDONLY); + long length; + if (handle < 0) return 0; + length = filelength(handle); + close(handle); + return length; +} + +long disk_space(void) { + struct diskfree_t free; + int drive = toupper(*(char *)sa--) - 64; + long avail; + + _dos_getdiskfree(drive, &free); + avail = (long) free.avail_clusters + * (long) free.bytes_per_sector + * (long) free.sectors_per_cluster; + return avail; +} + +long file_time(void) { + int handle = open(sa--, O_RDONLY); +#ifdef __BCPLUSPLUS__ + unsigned date, time; +#else + unsigned short date, time; +#endif + struct tm t; + + if (handle < 0) return 0; + _dos_getftime(handle, &date, &time); + close(handle); + t.tm_year = ((date & 0xfe00) >> 9) + 80; + t.tm_mon = ((date & 0x1e00) >> 5) - 1; + t.tm_mday = date & 0x001f; + ; + t.tm_hour = (time & 0xf800) >> 11; + t.tm_min = (time & 0x07e0) >> 5; + t.tm_sec = (time & 0x001f) << 1; + return mktime(&t); +} + + +// Support for reduction procecures + +// Compare top strings on string accumulator + +/* + pops top two strings from string accumulator using strcmp + and returns + -1 if first string is less than top string + 0 if strings match + +1 if top string is greater than first string +*/ + +int string_comp(void) { + int n = size(sa); + array<char> right_string(sa--, n+1); + return strcmp(sa--,right_string); +} + +/* + replace the top string on the stack, with a substring where the index + of the first character in the substring is given by "first" and the index + of the last character is given by "last" +*/ + +void extract(unsigned first, unsigned last) { + int n = last - first + 1; + assert (last >= first); + array <char> x((char *) sa-- + first, n+1); + x[n] = 0; + ++sa << x; +} + +/* + Look up the top string on the accumulator stack in the string dictionary. + If it has a value in the symbol table, replace it with the symbol table + value. If the value is numeric, convert it to integer. Otherwise, leave the + string untouched on the stack. +*/ + +void lookup(void) { + unsigned index = sd[sa]; + if (index == 0) return; + switch (st[index].type) { + case string_type: + case value_type: { + --sa; // discard name + ++sa << st[index].data.text; // stack value + break; + } + case integer_type: { + --sa; // discard name + (++sa).printf("%ld", st[index].data.integer); // convert to ascii + break; + } + } +} + +/* + Find the data type of a symbol and change the reduction accordingly. + Return the dictionary index for strings, and the value itself for integers. +*/ + +long name_type(void) { + unsigned index = sd << sa--; + switch (st[index].type) { + case value_type: + case string_type: { + CHANGE_REDUCTION(string_name); + return index; + } + case built_in_function_type: { + CHANGE_REDUCTION(built_in_name); + return index; + } + case undefined_type: { + CHANGE_REDUCTION(undefined_name); + return index; + } + case integer_type: return st[index].data.integer; + } + return 0; +} + +/* + Store a string formula. A string formula is a sequence of string identifiers + the values of which are to be concatenated. The parser has accumulated the + identifiers on the integer_stack, is. The formula is terminated by a zero + entry. +*/ + +int *formula(void) { + int n = size(is << 0); + int *f = new int[n]; + while (n--) is >> f[n]; + return f; +} + +/* + Make a copy of an action that has been identified in the text stream. + An action pointer was stacked at the beginning of the action text on the + action stack, as. +*/ + +action_pointer copy_action(void) { + action_pointer ap; + as >> ap; // pop action descriptor + unsigned length = (unsigned) (PCB.pointer - ap.pointer); + unsigned char *action = memdup(ap.pointer,length + 1); + action[length] = 0; + ap.pointer = action; + return ap; +} + + +// Internal Commands + +int echo(int, char *args[]) { + int i; + char *cs = ""; + for (i = 1; args[i]; i++) printf("%s%s", cs, args[i]), cs = " "; + printf("\n"); + fflush(stdout); + return 0; +} + +int pause(int, char *[]) { + int c; + while (kbhit()) getch(); // Empty buffer + printf("Press any key to continue . . .\n"); + c = getch(); + if (c == 3) exit(1); + return c; +} + +int exit_script(int n_args, char *args[]) { + if (n_args > 1) sscanf(args[1], "%ld", &exitcode); + exit(exitcode); + return exitcode; +} + +/* +int return_script(int n_args, char *args[]) { + if (n_args > 1) sscanf(args[1], "%ld", &exitcode); + PCB.exit_flag = AG_SUCCESS_CODE; + return exitcode; +} +*/ + +int subdirs(int, char *args[]) { + struct find_t file_block; + int flag; + int length = strlen(args[1]); + array <char> name(args[1],length + 5); + + strcat(name, "\\*.*"); + for(flag = _dos_findfirst(name, _A_SUBDIR, &file_block); + flag == 0; flag = _dos_findnext(&file_block)) { + if ((file_block.attrib & _A_SUBDIR) == 0) continue; + if (strcmp(file_block.name, ".") == 0) continue; + if (strcmp(file_block.name, "..") == 0) continue; + puts(file_block.name); + } + return 0; +} + +int files(int, char *args[]) { + struct find_t file_block; + int flag; + int length = strlen(args[1]); + array<char> name(args[1],length + 5); + + strcat(name, "\\*.*"); + for(flag = _dos_findfirst(name, 0, &file_block); + flag == 0; flag = _dos_findnext(&file_block)) { + puts(file_block.name); + } + return 0; +} + + +/***** + + Execute Command Line + +*****/ + + +void perform_action(action_pointer ap) { + dsl_pcb_type save_pcb = PCB; + + PCB.pointer = ap.pointer; + first_line = ap.line; + first_column = ap.column; + dsl(); + exitflag = PCB.exit_flag != AG_SUCCESS_CODE; + PCB = save_pcb; + if (exitflag) PCB.exit_flag = AG_SEMANTIC_ERROR_CODE; +} + +void exec(void) { + int n = size(ps << (char *) NULL); + int n_args = n - 1; + unsigned index; + int i; + + array <char *> args(n); + while (n--) ps >> args[n]; + + strupr(args[0]); + if (debug_switch) { + for (i = 0; args[i]; i++) fprintf(stderr, "%s ", args[i]); + fprintf(stderr,"\nPress any key to continue\n"); + while (!kbhit()); + getch(); + } + index = sd[args[0]]; + if (n_args == 1 && strlen(args[0]) == 2 && args[0][1] == ':') { + errorlevel = system(args[0]); + } + else if ( *args[0] && index) switch (st[index].type) { + case internal_type: { + errorlevel = (*st[index].data.proc)(n_args, args); + break; + } + case dos_type: { + int i; + for (i = 1; args[i]; i++) args[i][-1] = ' '; + errorlevel = system(args[0]); + assert(errorlevel >= 0); + break; + } + case action_type: { + action_descriptor d = *st[index].data.action; + stack <symbol_table_entry> old_entries(d.n_args); + for (i = 0; i < d.n_args && args[i+1]; i++) { + old_entries << st[d.args[i]]; + st[d.args[i]].type = value_type; + st[d.args[i]].data.text = memdup(args[i+1], 1 + strlen(args[i+1])); + } + perform_action(d.ap); + for (i = d.n_args; i--;) { + release(st[d.args[i]]); + old_entries >> st[d.args[i]]; + } + } + } + else { + errorlevel = spawnvp(P_WAIT,args[0],ARGS); + assert(errorlevel >= 0); + } + st[errorlevel_index].data.integer = errorlevel; + while (n_args--) --sa; + --ps; + if (kbhit()) { + int c = getch(); + if (c == 3) exit(1); + ungetch(c); + } +} + +void discard_temp_file(char *file_name) { + unlink(file_name); // Delete file + delete [] file_name; // Free storage for name +} + + +/***** + + Execute Command with piped input + +*****/ + + +void exec_pipe_in(char *file_name) { + { + redirect sin(STDIN, file_name); + exec(); + } + discard_temp_file(file_name); +} + + +/***** + + Execute Command with redirected I/O + +*****/ + +void exec_redirect_in(void) { + redirect sin(STDIN, sa--); + exec(); +} + +char *exec_pipe_out(void) { + fflush(stdout); + redirect sout(STDOUT); + exec(); + fflush(stdout); + return save_file(sout); +} + +char *exec_pipe_in_pipe_out(char *file_name) { + char *result; + { + redirect sin(STDIN, file_name); + fflush(stdout); + redirect sout(STDOUT); + exec(); + fflush(stdout); + result = save_file(sout); + } + discard_temp_file(file_name); + return result; +} + +char *exec_redirect_in_pipe_out(void) { + fflush(stdout); + redirect sout(STDOUT); + exec_redirect_in(); + fflush(stdout); + return save_file(sout); +} + +unsigned check_integer(void) { + unsigned index = sd << sa--; + if (st[index].type == integer_type) return index; + CHANGE_REDUCTION(undeclared_variable); + if (st[index].type == string_type) CHANGE_REDUCTION(string_variable); + return index; +} + +void assign_value(unsigned index) { + char *text = copy(sa--); + release(st[index]); + st[index].type = value_type; + st[index].data.text = text; +} + +void grab_output(char *temp_name) { + unlink(sa); // delete old file + rename(temp_name, sa--); // rename temp file + delete [] temp_name; // discard name string +} + +void append_output(char *temp_name) { + fflush(stdout); + redirect sout(STDOUT, sa--, 1); // append to file named on sa + redirect sin(STDIN, temp_name); + char buf[2000]; + int n; + while (1) { + n = read(STDIN, buf, 2000); + if (n == 0) break; + write(STDOUT, buf, n); + } + fflush(stdout); + unlink(temp_name); + delete [] temp_name; +} + +void action_string(void) { + action_pointer ap; + as >> ap; + unsigned length = (unsigned)(PCB.pointer - ap.pointer); + array <unsigned char> action(ap.pointer,length + 1); + action[length] = 0; + fflush(stdout); + redirect sout(STDOUT); + char *result; + + ap.pointer = action; + perform_action(ap); + fflush(stdout); + result = content(sout); + ++sa << result; + delete [] result; +} + + +// Program Control functions + +// If/else statement + +int do_if(int pc, int cc) { + action_pointer ap; + as >> ap; + if (!pc && cc && exitflag == 0) { + unsigned length = (unsigned) (PCB.pointer - ap.pointer); + array<unsigned char> q(ap.pointer, length+1); + q[length] = 0; + ap.pointer = q; + perform_action(ap); + } + return pc || cc; +} + +// While statement + +void do_while(int cc) { + unsigned length; + action_pointer ap; + as >> ap; + if (cc == 0) return; + length = (unsigned) (PCB.pointer - ap.pointer); + array<unsigned char> q(ap.pointer, length+1); + q[length] = 0; + ap.pointer = q; + perform_action(ap); + if (exitflag) return; + PCB.pointer = CONTEXT.pointer; + PCB.line = CONTEXT.line; + PCB.column = CONTEXT.column; +} + + +// For Statement +// Note that this is the for statement in the DOS batch languange for, not C + +void do_for_loop(void) { + int n,k; + char *q; + char *seps = " \t\v\f\r\n"; + action_pointer ap; + as >> ap; + unsigned length = (unsigned)(PCB.pointer - ap.pointer); + array <unsigned char> action(ap.pointer, length + 1); + action[length] = 0; + + ap.pointer = action; + n = size(sa); + array<char> text(sa--, n + 1); + + + unsigned index = sd << sa--; + + ++ps; + for (q = strtok(text, seps); q != NULL; q = strtok(NULL,seps)) { + if (*q == '(') { + int k = strlen(q) - 1; + assert(q[k] == ')'); + q[k] = 0; + q++; + } + else if (*q == '"') { + int k = strlen(q) - 1; + assert(q[k] == '"'); + q[k] = 0; + q++; + } + ps << q; + } + k = n = size(ps); + array<char *> args(n); + while (k--) ps >> args[k]; + --ps; + symbol_table_entry save_table_entry = st[index]; + st[index].type = value_type; + + for (k = 0; k < n && exitflag == 0; k++) { + st[index].data.text = args[k]; + perform_action(ap); + } + st[index] = save_table_entry; +} + +void invoke_script(void) { + int handle = open(sa, O_TEXT | O_RDONLY); + long size; + unsigned n; + action_pointer ap; + + if (handle < 0) { + fprintf(stderr,"Cannot open %s\n", (char *) sa--); + exit(1); + } + --sa; + size = filelength(handle); + assert(size < 65536L); + array <unsigned char> data((unsigned) size+1); + n = (unsigned) read(handle,data,(unsigned) size); + data[n] = 0; + close(handle); + exitflag = 0; + ap.pointer = data; + ap.line = ap.column = 1; + perform_action(ap); + st[errorlevel_index].data.integer = exitcode; + exitflag = exitcode = 0; + return; +} + +internal_commands_descriptor internal_commands[] = { + {"ECHO", echo}, + {"EXIT", exit_script}, + {"FILES", files}, + {"PAUSE", pause}, +// {"RETURN", return_script}, + {"SUBDIRS", subdirs}, + {NULL, NULL} +}; + +struct built_ins_descriptor built_ins[] = { + {"file_exists", file_exists}, + {"directory_exists", directory_exists}, + {"string_length", string_length}, + {"file_length", get_file_length}, + {"disk_space", disk_space}, + {"file_time", file_time}, + {NULL, NULL} +}; + +void set_extension(char *path, char *e) { + char s[_MAX_PATH]; + char drive[_MAX_DRIVE]; + char dir[_MAX_DIR]; + char file[_MAX_FNAME]; + char ext[_MAX_EXT]; + + _splitpath(path,drive,dir,file,ext); + _makepath(s, drive, dir, file, e); + ++sa << s; +} + +/* + Note that if this program is called without any arguments, it looks for a + script with the same name as the executable. Thus, to make an install + program that picks up the install script without any arguments, you simply + rename DSL.EXE to INSTALL.EXE. Then when you run it without any arguments + it will run the INSTALL.DSL script. +*/ + +void main(int argc, char *argv[]) { + int arg_number = 0; + int i = 1; + int j = 0; + + if (argv[0][0] == '.') argv[0] = "\\agex\\dsl\\wat32\\dsl.exe"; + init_dos_internals(); + set_arg(j++, argv[0]); + if (argc > i && (argv[i][0] == '/' || argv[i][0] == '-')) { + if (toupper(argv[i][1]) != 'D') { + printf("Unrecognized switch -- /%s\n",argv[i][1]); + return; + } + debug_switch = 1; + i++; + } + if (argc > i) arg_number = i++; + set_extension(argv[arg_number], "DSL"); + set_arg(j++,copy(sa)); + while (i < argc) set_arg(j++, argv[i++]); + define_integer("argc", j); + invoke_script(); // Takes file name from sa + exit(exitcode); +} +} // End Embedded C