Mercurial > ~dholland > hg > ag > index.cgi
comparison tests/agcl/oldagsrc/dsl.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 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:13d2b8934445 |
---|---|
1 { // C Prologue | |
2 /* | |
3 AnaGram, a System for Syntax Directed Programming | |
4 | |
5 A Dos Script Language | |
6 | |
7 Copyright (c) 1993, Parsifal Software. | |
8 All Rights Reserved. | |
9 | |
10 */ | |
11 | |
12 | |
13 #include "stack.h" | |
14 #include "charsink.h" | |
15 #include "strdict.h" | |
16 #include "array.h" | |
17 #include "symbol.h" | |
18 #include "query.h" | |
19 #include <conio.h> | |
20 | |
21 | |
22 // Define stacks for temporary storage | |
23 | |
24 stack <action_pointer> as(25); // Stack actions | |
25 stack <int> is(100); // Stack string indices | |
26 stack <char *> ps(1000,20); // Stack parameter strings | |
27 stack <query_item> qs(23); // Stack query items | |
28 | |
29 | |
30 // Define data structures for symbol table | |
31 | |
32 #define N_STRINGS 2000 | |
33 | |
34 string_accumulator sa(64000U,500); | |
35 string_dictionary sd(N_STRINGS); | |
36 array <symbol_table_entry> st(N_STRINGS); | |
37 | |
38 } // End of C Prologue | |
39 | |
40 | |
41 // Character Set Definitions | |
42 | |
43 digit = '0-9' | |
44 eof = 0 + ^Z | |
45 letter = 'a-z' + 'A-Z' + '_' | |
46 not double quote = ~eof - ('"' + '\\' + '\n') | |
47 not eol = ~(eof + '\n') | |
48 not paren = ~(eof + '(' + ')') | |
49 not single quote = ~eof - ('\'' + '\\' + '\n') | |
50 operator = '#' + '=' + '<' + '>' + '|' | |
51 punctuation = '(' + ')' + '{' + '}' + '[' + ']' + '"' + '\n' | |
52 text char = ~(eof + operator + white + punctuation + '@') | |
53 white = ' ' + '\t' + '\v' + '\f' + '\r' | |
54 | |
55 | |
56 // Configuration Section | |
57 | |
58 [ | |
59 ~allow macros | |
60 line numbers | |
61 pointer input | |
62 context type = action_pointer | |
63 test file mask = "*.dsl" | |
64 distinguish keywords {letter + digit} | |
65 sticky {name} | |
66 far tables | |
67 | |
68 disregard ws | |
69 lexeme {literal, integer constant, string literal, paren string, | |
70 character constant, eol, literals} | |
71 | |
72 subgrammar {word, literals} | |
73 parser file name = "#.cpp" | |
74 ] | |
75 | |
76 | |
77 // White Space Definitions | |
78 | |
79 ws | |
80 -> white | comment | |
81 | |
82 comment | |
83 -> comment head, "*/" | |
84 | |
85 comment head | |
86 -> "/*" | |
87 -> comment head, ~eof | |
88 | |
89 // Comment out one of the following two productions to determine whether | |
90 // comments nest or not | |
91 | |
92 comment head | |
93 -> comment head, comment // comments nest | |
94 | |
95 /* | |
96 comment | |
97 -> comment head, comment // comments do not nest | |
98 */ | |
99 | |
100 eol | |
101 -> '\n' | |
102 -> "//", not eol?..., '\n' // C++ style comments | |
103 | |
104 | |
105 | |
106 // Script File Description | |
107 | |
108 script file $ | |
109 -> [execution block | declaration | eol]..., eof | |
110 | |
111 | |
112 // Dos Command and Parameter Recognition | |
113 | |
114 word | |
115 -> paren string | |
116 -> string literal | |
117 -> literal =lookup(); | |
118 -> word, '[', !sa << '[';, | |
119 parameter string, ']' =concat(sa) << ']', lookup(); | |
120 | |
121 string | |
122 -> word | |
123 -> string, '#', word =concat(sa); | |
124 | |
125 parameter string | |
126 -> param word | |
127 -> parameter string, '#', | |
128 param word =concat(sa); | |
129 | |
130 literal | |
131 -> text char + '@':c =++sa << c; | |
132 -> literal, text char:c =sa << c; | |
133 | |
134 param word | |
135 -> word | |
136 -> action text =action_string(); | |
137 | |
138 | |
139 // Gather, but do not execute, the text of an action block | |
140 | |
141 action text | |
142 -> action text head, '}' | |
143 | |
144 action text head | |
145 -> '{' =as << CONTEXT; | |
146 -> action text head, word =--sa; | |
147 -> action text head, eol | |
148 -> action text head, action text ={action_pointer a; as >> a;} | |
149 -> action text head, operator | |
150 | |
151 | |
152 /***** | |
153 | |
154 Parenthesized string | |
155 | |
156 May contain any characters inside balanced parentheses. If parentheses | |
157 are included, they must balance. Outer parentheses are stripped before | |
158 use. | |
159 | |
160 *****/ | |
161 | |
162 paren string | |
163 -> paren string chars, ')' | |
164 | |
165 paren string chars | |
166 -> '(' =++sa; | |
167 -> paren string chars, paren string char | |
168 | |
169 paren string char | |
170 -> not paren:c =sa << c; | |
171 -> !sa << '(';, paren string chars, ')' =concat(sa) << ')'; | |
172 | |
173 | |
174 /***** | |
175 | |
176 String Literal | |
177 | |
178 Follows the same rules as for string literals in C and C++ | |
179 | |
180 *****/ | |
181 | |
182 string literal | |
183 -> string chars, '"' | |
184 | |
185 string chars | |
186 -> '"' =++sa; | |
187 -> string chars, string char | |
188 | |
189 string char | |
190 -> not double quote:c =sa << c; | |
191 -> escape sequence:c =sa << c; | |
192 | |
193 (int) escape sequence | |
194 -> "\\a" ='\a'; | |
195 -> "\\b" ='\b'; | |
196 -> "\\f" ='\f'; | |
197 -> "\\n" ='\n'; | |
198 -> "\\r" ='\r'; | |
199 -> "\\t" ='\t'; | |
200 -> "\\v" ='\v'; | |
201 -> "\\\\" ='\\'; | |
202 -> "\\?" = '\?'; | |
203 -> "\\'" ='\''; | |
204 -> "\\\"" ='"'; | |
205 -> octal escape | |
206 -> hex escape | |
207 | |
208 (int) octal escape | |
209 -> one octal | two octal | three octal | |
210 | |
211 (int) one octal | |
212 -> '\\', '0-7':d =d-'0'; | |
213 | |
214 (int) two octal | |
215 -> one octal:n, '0-7':d =8*n + d-'0'; | |
216 | |
217 (int) three octal | |
218 -> two octal:n, '0-7':d =8*n + d-'0'; | |
219 | |
220 (int) hex escape | |
221 -> "\\x", hex number:n =(int) n; | |
222 | |
223 (long) hex number | |
224 -> hex digit | |
225 -> hex number:n, hex digit:d =16*n + d; | |
226 | |
227 [ | |
228 sticky {one octal, two octal, hex number} | |
229 ] | |
230 | |
231 | |
232 /***** | |
233 | |
234 Command Line Interpretation | |
235 | |
236 The identifier may be the name of a DOS command, internal or external, | |
237 a path name of an arbitrary executable, or an internal commmand of the | |
238 scripting language. It may appear literally, or may be the result of | |
239 string concatenation and substitution. | |
240 | |
241 command is used in the program logic section, below. | |
242 | |
243 *****/ | |
244 | |
245 command | |
246 -> identifier, parameters? =exec(); | |
247 -> identifier, parameters?, | |
248 '<', parameter string =exec_redirect_in(); | |
249 -> piped command:file, '|', | |
250 identifier, parameters? =exec_pipe_in(file); | |
251 -> piped command:file, '>', | |
252 parameter string =grab_output(file); | |
253 -> piped command:file, ">>", | |
254 parameter string =append_output(file); | |
255 | |
256 (char *) piped command | |
257 -> identifier, parameters? =exec_pipe_out(); | |
258 -> identifier, parameters?, | |
259 '<', parameter string =exec_redirect_in_pipe_out(); | |
260 -> piped command:file, '|', | |
261 identifier, parameters? =exec_pipe_in_pipe_out(file); | |
262 | |
263 identifier | |
264 -> string =sa << 0, ++ps << sa; | |
265 | |
266 parameters | |
267 -> parameter string =ps << sa, sa << 0; | |
268 -> parameters, parameter string =ps << sa, sa << 0; | |
269 | |
270 | |
271 /***** | |
272 | |
273 Program logic. | |
274 | |
275 This section of syntax controls the interpretation of a sequence | |
276 of commands enclosed within braces. | |
277 | |
278 *****/ | |
279 | |
280 execution block | |
281 -> '{', eol?...,[command sequence, eol?... | if sequence, eol?...], '}' | |
282 | |
283 | |
284 /***** | |
285 | |
286 A command sequence is any sequence of statements and | |
287 if statements that ends with a statement. | |
288 | |
289 *****/ | |
290 | |
291 command sequence | |
292 -> statement | |
293 -> command sequence, eol..., statement | |
294 -> if sequence, eol..., statement | |
295 -> if sequence:pc, eol?..., | |
296 "else", action text =do_if(pc,1); | |
297 | |
298 /***** | |
299 | |
300 An if sequence is any direct sequence of statements and if statements | |
301 that ends with an if statement. The difference between an "if sequence" and | |
302 a "command sequence" is that an else clause may follow the "if sequence". | |
303 | |
304 *****/ | |
305 | |
306 (int) if sequence | |
307 -> if statement | |
308 -> if sequence, eol..., if statement:cc =cc; | |
309 -> command sequence, eol..., if statement:cc =cc; | |
310 -> if sequence:pc, eol?..., "else", eol?..., | |
311 if condition:cc, action text =do_if(pc,cc!=0); | |
312 | |
313 (int) if condition | |
314 -> "if", | |
315 '(', conditional exp:cc, ')' =(int) cc; | |
316 | |
317 (int) if statement | |
318 -> if condition:cc, action text =do_if(0,cc != 0); | |
319 | |
320 /***** | |
321 | |
322 A statement is any command that isn't an if or else statement. | |
323 The iteration on the while statement is a ruse. | |
324 | |
325 *****/ | |
326 | |
327 statement | |
328 -> command | |
329 -> assignment | |
330 -> for statement | |
331 -> declaration | |
332 -> screen description | |
333 -> while statement... | |
334 | |
335 | |
336 /***** | |
337 | |
338 Assignment statements | |
339 | |
340 There are four varieties of assignment statement depending on whether | |
341 or how the variable on the left hand side has been previously declared. | |
342 | |
343 *****/ | |
344 | |
345 assignment | |
346 -> undeclared variable:v, '=', | |
347 parameter string =assign_value(v); | |
348 -> integer variable:v, '=', | |
349 conditional exp:x, ';'? =st[v].data.integer = (int) x; | |
350 -> string variable:v, '=', | |
351 string exp, ';'? =st[v].data.text = copy(sa--); | |
352 -> string variable:v, '@', | |
353 primary exp:n, '=', | |
354 conditional exp:x, ';'? =st[v].data.text[(unsigned)n] = (int) x; | |
355 | |
356 | |
357 /***** | |
358 | |
359 Semantically determined production to determine treatment of variable | |
360 on left side of assignment statement. | |
361 | |
362 *****/ | |
363 | |
364 (unsigned) integer variable, | |
365 string variable, | |
366 undeclared variable | |
367 -> literal =check_integer(); | |
368 | |
369 | |
370 /***** | |
371 | |
372 While Statement | |
373 | |
374 The While statement loops by simply resetting the input pointer for | |
375 the parser back to the beginning of the while loop. This is the reason | |
376 for the iteration of the while statement in the production for "simple | |
377 command". | |
378 | |
379 *****/ | |
380 | |
381 while statement | |
382 -> "while", '(', conditional exp:cc, ')', | |
383 action text =do_while(cc != 0); | |
384 | |
385 | |
386 /***** | |
387 | |
388 | |
389 | |
390 For Statement | |
391 | |
392 This for statement corresponds to the for statement in the DOS batch | |
393 programming language, not the for statement in C. | |
394 | |
395 *****/ | |
396 | |
397 for statement | |
398 -> "for", name, // !++sa << '(';, | |
399 "in", parameter string, | |
400 "do"?, action text =do_for_loop(); | |
401 | |
402 | |
403 /***** | |
404 | |
405 Declaration statements | |
406 | |
407 *****/ | |
408 | |
409 declaration | |
410 -> "action", literals:n, | |
411 action text =define_action(n); | |
412 -> "int", | |
413 name, '=', conditional exp:x, ';'? =define_integer(sa--, x); | |
414 -> "string", | |
415 name, '=', string exp, ';'? =define_string(); | |
416 | |
417 (int) literals | |
418 -> literal =0; | |
419 -> literals:n, ws..., literal =n+1; | |
420 | |
421 | |
422 name | |
423 -> letter:c =++sa << c; | |
424 -> name, letter:c =sa << c; | |
425 -> name, digit:c =sa << c; | |
426 | |
427 | |
428 /***** | |
429 | |
430 Integer and String Expression Logic | |
431 | |
432 The syntax for expressions is essentially that of C, with the addition | |
433 of string comparison. The only missing operators are ++, --, and comma. | |
434 | |
435 *****/ | |
436 | |
437 | |
438 (long) conditional exp | |
439 -> logical or exp | |
440 -> logical or exp:c, '?', conditional exp:x, ':', | |
441 conditional exp:y = c != 0 ? x : y; | |
442 | |
443 (long) logical or exp | |
444 -> logical and exp | |
445 -> logical or exp:x, "||", | |
446 logical and exp:y =x != 0 || y!=0; | |
447 | |
448 (long) logical and exp | |
449 -> inclusive or exp | |
450 -> logical and exp:x, "&&", | |
451 inclusive or exp:y =x != 0 && y !=0; | |
452 | |
453 (long) inclusive or exp | |
454 -> exclusive or exp | |
455 -> inclusive or exp:x, '|', | |
456 exclusive or exp:y =x | y; | |
457 | |
458 (long) exclusive or exp | |
459 -> and exp | |
460 -> exclusive or exp:x, '^', and exp:y =x ^ y; | |
461 | |
462 (long) and exp | |
463 -> equality exp | |
464 -> and exp:x, '&', equality exp:y =x & y; | |
465 | |
466 (long) equality exp | |
467 -> relational exp | |
468 -> equality exp:x, "==", relational exp:y =x == y; | |
469 -> equality exp:x, "!=", relational exp:y =x != y; | |
470 -> string exp, "==", string exp =string_comp() == 0; | |
471 -> string exp, "!=", string exp =string_comp() != 0; | |
472 | |
473 | |
474 (long) relational exp | |
475 -> shift exp | |
476 -> relational exp:x, '<', shift exp:y =x < y; | |
477 -> relational exp:x, '>', shift exp:y =x > y; | |
478 -> relational exp:x, "<=", shift exp:y =x <= y; | |
479 -> relational exp:x, ">=", shift exp:y =x >= y; | |
480 -> string exp, '<', string exp =string_comp() < 0; | |
481 -> string exp, '>', string exp =string_comp() > 0; | |
482 -> string exp, "<=", string exp =string_comp() <= 0; | |
483 -> string exp, ">=", string exp =string_comp() >= 0; | |
484 | |
485 (long) shift exp | |
486 -> additive exp | |
487 -> shift exp:x, "<<", additive exp:y =x << y; | |
488 -> shift exp:x, ">>", additive exp:y =x >> y; | |
489 | |
490 (long) additive exp | |
491 -> multiplicative exp | |
492 -> additive exp:x, '+', | |
493 multiplicative exp:y =x + y; | |
494 -> additive exp:x, '-', | |
495 multiplicative exp:y =x - y; | |
496 | |
497 (long) multiplicative exp | |
498 -> unary exp | |
499 -> multiplicative exp:x, '*', unary exp:y =x * y; | |
500 -> multiplicative exp:x, '/', nonzero:y =x / y; | |
501 -> multiplicative exp:x, '%', nonzero:y =x % y; | |
502 | |
503 (long) nonzero | |
504 -> unary exp: x ={ | |
505 assert(x); | |
506 return x; | |
507 } | |
508 | |
509 (long) unary exp | |
510 -> primary exp | |
511 -> '+', unary exp:x =x; | |
512 -> '-', unary exp:x =-x; | |
513 -> '~', unary exp:x =~x; | |
514 -> '!', unary exp:x =!x; | |
515 | |
516 (long) primary exp | |
517 -> integer constant | |
518 -> character constant | |
519 -> string term,'@', primary exp:n =((unsigned char *) sa--)[(unsigned) n]; | |
520 -> '#', string element ={ | |
521 long temp; | |
522 sscanf(sa--, "%ld", &temp); | |
523 return temp; | |
524 } | |
525 -> numeric name | |
526 -> '(', conditional exp:x, ')' =x; | |
527 -> built_in name:x, built_in argument =(*st[(unsigned)x].data.func)(); | |
528 | |
529 built_in argument | |
530 -> '(', parameter string, ')' | |
531 | |
532 (long) numeric name, | |
533 string name, | |
534 built_in name, | |
535 undefined name | |
536 -> name =name_type(); | |
537 | |
538 | |
539 /***** | |
540 | |
541 String Expressions | |
542 | |
543 *****/ | |
544 | |
545 string exp | |
546 -> string term | |
547 -> string exp, '#', string term =concat(sa); | |
548 | |
549 string term | |
550 -> string element | |
551 -> string term, '@', '(', | |
552 conditional exp:first, "..", | |
553 conditional exp:last, ')' =extract((unsigned)first, (unsigned) last); | |
554 -> string term, '[', !sa << '[';, | |
555 parameter string, ']' =concat(sa) << ']', lookup(); | |
556 | |
557 string element | |
558 -> string literal | |
559 -> string name:x =++sa << st[(unsigned)x].data.text; | |
560 -> undefined name:x =++sa << sd[(unsigned)x]; | |
561 -> action text =action_string(); | |
562 -> '=', primary exp:x =++sa,sa.printf("%ld",x); | |
563 -> '(', string exp, ')' | |
564 | |
565 /***** | |
566 | |
567 Integer constants | |
568 | |
569 The syntax for integer constants is identical to that in C. | |
570 | |
571 *****/ | |
572 | |
573 integer constant | |
574 -> hex constant | |
575 -> octal constant | |
576 -> decimal constant | |
577 | |
578 (long) hex constant | |
579 -> {"0x" | "0X"} =0; | |
580 -> hex constant:x, hex digit:d =16*x + d-'0'; | |
581 | |
582 (long) hex digit | |
583 -> '0-9' | |
584 -> 'a-f' + 'A-F':d =(d&7) + 9; | |
585 | |
586 (long) octal constant | |
587 -> '0' =0; | |
588 -> octal constant:n, '0-7':d =8*n + d-'0'; | |
589 | |
590 (long) decimal constant | |
591 -> '1-9':d =d-'0'; | |
592 -> decimal constant:n, '0-9':d =10*n + d-'0'; | |
593 | |
594 | |
595 /***** | |
596 | |
597 Character Constant | |
598 | |
599 The rules for character constant are the same as in C. | |
600 | |
601 *****/ | |
602 | |
603 (int) character constant | |
604 -> '\'', char constant element:c, '\'' =c; | |
605 | |
606 (int) char constant element | |
607 -> not single quote | |
608 -> escape sequence | |
609 | |
610 | |
611 /***** | |
612 | |
613 Screen Display | |
614 | |
615 *****/ | |
616 | |
617 screen description | |
618 -> screen items:scd, '}' =display_queries(scd); | |
619 | |
620 (screen_descriptor *) screen items | |
621 -> "screen", '{' =reset(qs), new screen_descriptor; | |
622 -> screen items, eol | |
623 -> screen items:scd, | |
624 "title", '=', | |
625 formula, eol =scd->title = formula(), scd; | |
626 -> screen items:scd, | |
627 color spec:c, eol =scd->color = c, scd; | |
628 -> screen items:scd, | |
629 "entry", color spec:c, eol =scd->entry_color = c, scd; | |
630 -> screen items:scd, | |
631 "highlight", color spec:c, eol =scd->highlight_color = c, scd; | |
632 -> screen items:scd, | |
633 "size", '=', conditional exp:w, | |
634 ',', conditional exp:h =scd->width = (unsigned)w, scd->height = (unsigned) h, scd; | |
635 -> screen items:scd, | |
636 "location", '=', conditional exp:x, | |
637 ',', conditional exp:y =scd->pos.x = (unsigned) x,scd->pos.y = (unsigned) y, scd; | |
638 -> screen items:scd, | |
639 query line:q, '}', eol =qs << *q, delete q, scd; | |
640 -> screen items:scd, | |
641 button line:q, '}', eol =qs << *q, delete q, scd; | |
642 | |
643 (int) color spec | |
644 -> "color", '=', conditional exp:fg, | |
645 ',', conditional exp:bg =COLOR((unsigned)fg,(unsigned)bg); | |
646 | |
647 | |
648 (query_item *) query line | |
649 -> "field", '{' =clear(new query_item); | |
650 -> query line, eol | |
651 -> query line:q, | |
652 "variable", '=', | |
653 literal, eol =q->id = sd << sa--, q; | |
654 -> query line:q, | |
655 "default", '=', | |
656 formula, eol =q->value = formula(), q; | |
657 -> query line:q, | |
658 "prompt", '=', | |
659 formula, eol =q->prompt = formula(), q; | |
660 -> query line:q, | |
661 "explanation", '=', | |
662 formula, eol =q->explanation = formula(),q; | |
663 | |
664 (query_item *) button line | |
665 -> "button", '{' =clear(new query_item); | |
666 -> button line, eol | |
667 -> button line:q, | |
668 "prompt", '=', formula, eol =q->prompt = formula(), q; | |
669 -> button line:q, | |
670 "explanation", '=', | |
671 formula, eol =q->explanation = formula(),q; | |
672 -> button line:q, | |
673 action text, eol =q->action = copy_action(), q; | |
674 | |
675 formula | |
676 -> formula element =reset(is) << (sd << sa--); | |
677 -> formula, '#', formula element =is << (sd << sa--); | |
678 | |
679 formula element | |
680 -> paren string | |
681 -> string literal | |
682 -> literal | |
683 -> formula element, '[', !sa << '[';, | |
684 parameter string, ']' =concat(sa) << ']'; | |
685 | |
686 { | |
687 | |
688 #include <process.h> | |
689 #include <stdlib.h> | |
690 #include <ctype.h> | |
691 #include <sys/stat.h> | |
692 #include <fcntl.h> | |
693 #include <io.h> | |
694 #include <conio.h> | |
695 #include <dir.h> | |
696 #include <dos.h> | |
697 #include <time.h> | |
698 #include "assert.h" | |
699 | |
700 #include "edit.h" | |
701 | |
702 | |
703 #include "screen.h" | |
704 #include "util.h" | |
705 #include "redirect.h" | |
706 | |
707 #define GET_CONTEXT CONTEXT.pointer = PCB.pointer;\ | |
708 CONTEXT.line=PCB.line;\ | |
709 CONTEXT.column = PCB.column; | |
710 | |
711 | |
712 int debug_switch = 0; | |
713 char *error_msg = NULL; | |
714 unsigned errorlevel_index; | |
715 int errorlevel; | |
716 int exitcode = 0; | |
717 int exitflag = 0; | |
718 int first_line = 1; | |
719 int first_column = 1; | |
720 unsigned stderr_index; | |
721 | |
722 void display_queries(screen_descriptor *); | |
723 | |
724 #define FIRST_LINE first_line | |
725 #define FIRST_COLUMN first_column | |
726 | |
727 | |
728 /***** | |
729 | |
730 Internal Functions | |
731 | |
732 *****/ | |
733 | |
734 long file_exists(void) { | |
735 FILE *f = fopen(sa--,"r"); | |
736 if (f != NULL) fclose(f); | |
737 return f != NULL; | |
738 } | |
739 | |
740 long directory_exists(void) { | |
741 struct ffblk ff; | |
742 int result; | |
743 | |
744 sa << "\\*.*"; | |
745 result = findfirst(sa--,&ff,FA_DIREC); | |
746 return result == 0; | |
747 } | |
748 | |
749 long string_length(void) { | |
750 return size(sa--); | |
751 } | |
752 | |
753 long get_file_length(void) { | |
754 int handle = open(sa--, O_RDONLY); | |
755 long length; | |
756 if (handle < 0) return 0; | |
757 length = filelength(handle); | |
758 close(handle); | |
759 return length; | |
760 } | |
761 | |
762 long disk_space(void) { | |
763 struct dfree free; | |
764 int drive = toupper(*(char *)sa--) - 64; | |
765 long avail; | |
766 | |
767 getdfree(drive, &free); | |
768 avail = (long) free.df_avail * (long) free.df_bsec * (long) free.df_sclus; | |
769 return avail; | |
770 } | |
771 | |
772 long file_time(void) { | |
773 int handle = open(sa--, O_RDONLY); | |
774 struct ftime ft; | |
775 struct tm t; | |
776 | |
777 if (handle < 0) return 0; | |
778 getftime(handle, &ft); | |
779 close(handle); | |
780 t.tm_year = ft.ft_year + 70; | |
781 t.tm_mon = ft.ft_month; | |
782 t.tm_mday = ft.ft_day; | |
783 t.tm_hour = ft.ft_hour; | |
784 t.tm_min = ft.ft_min; | |
785 t.tm_sec = ft.ft_tsec*2; | |
786 return mktime(&t); | |
787 } | |
788 | |
789 | |
790 // Support for reduction procecures | |
791 | |
792 // Compare top strings on string accumulator | |
793 | |
794 /* | |
795 pops top two strings from string accumulator using strcmp | |
796 and returns | |
797 -1 if first string is less than top string | |
798 0 if strings match | |
799 +1 if top string is greater than first string | |
800 */ | |
801 | |
802 int string_comp(void) { | |
803 int n = size(sa); | |
804 array<char> right_string(sa--, n+1); | |
805 return strcmp(sa--,right_string); | |
806 } | |
807 | |
808 /* | |
809 replace the top string on the stack, with a substring where the index | |
810 of the first character in the substring is given by "first" and the index | |
811 of the last character is given by "last" | |
812 */ | |
813 | |
814 void extract(unsigned first, unsigned last) { | |
815 int n = last - first + 1; | |
816 assert (last >= first); | |
817 array <char> x((char *) sa-- + first, n+1); | |
818 x[n] = 0; | |
819 ++sa << x; | |
820 } | |
821 | |
822 /* | |
823 Look up the top string on the accumulator stack in the string dictionary. | |
824 If it has a value in the symbol table, replace it with the symbol table | |
825 value. If the value is numeric, convert it to integer. Otherwise, leave the | |
826 string untouched on the stack. | |
827 */ | |
828 | |
829 void lookup(void) { | |
830 unsigned index = sd[sa]; | |
831 if (index == 0) return; | |
832 switch (st[index].type) { | |
833 case string_type: | |
834 case value_type: { | |
835 --sa; // discard name | |
836 ++sa << st[index].data.text; // stack value | |
837 break; | |
838 } | |
839 case integer_type: { | |
840 --sa; // discard name | |
841 (++sa).printf("%ld", st[index].data.integer); // convert to ascii | |
842 break; | |
843 } | |
844 } | |
845 } | |
846 | |
847 /* | |
848 Find the data type of a symbol and change the reduction accordingly. | |
849 Return the dictionary index for strings, and the value itself for integers. | |
850 */ | |
851 | |
852 long name_type(void) { | |
853 unsigned index = sd << sa--; | |
854 switch (st[index].type) { | |
855 case value_type: | |
856 case string_type: { | |
857 CHANGE_REDUCTION(string_name); | |
858 return index; | |
859 } | |
860 case built_in_function_type: { | |
861 CHANGE_REDUCTION(built_in_name); | |
862 return index; | |
863 } | |
864 case undefined_type: { | |
865 CHANGE_REDUCTION(undefined_name); | |
866 return index; | |
867 } | |
868 case integer_type: return st[index].data.integer; | |
869 } | |
870 return 0; | |
871 } | |
872 | |
873 /* | |
874 Store a string formula. A string formula is a sequence of string identifiers | |
875 the values of which are to be concatenated. The parser has accumulated the | |
876 identifiers on the integer_stack, is. The formula is terminated by a zero | |
877 entry. | |
878 */ | |
879 | |
880 int *formula(void) { | |
881 int n = size(is << 0); | |
882 int *f = new int[n]; | |
883 while (n--) is >> f[n]; | |
884 return f; | |
885 } | |
886 | |
887 /* | |
888 Make a copy of an action that has been identified in the text stream. | |
889 An action pointer was stacked at the beginning of the action text on the | |
890 action stack, as. | |
891 */ | |
892 | |
893 action_pointer copy_action(void) { | |
894 action_pointer ap; | |
895 as >> ap; // pop action descriptor | |
896 unsigned length = (unsigned) (PCB.pointer - ap.pointer); | |
897 unsigned char *action = memdup(ap.pointer,length + 1); | |
898 action[length] = 0; | |
899 ap.pointer = action; | |
900 return ap; | |
901 } | |
902 | |
903 | |
904 // Internal Commands | |
905 | |
906 int echo(int n_args, char *args[]) { | |
907 int i; | |
908 char *cs = ""; | |
909 for (i = 1; args[i]; i++) printf("%s%s", cs, args[i]), cs = " "; | |
910 printf("\n"); | |
911 return 0; | |
912 } | |
913 | |
914 int pause(int n_args, char *args[]) { | |
915 int c; | |
916 while (kbhit()) getch(); // Empty buffer | |
917 printf("Press any key to continue . . .\n"); | |
918 c = getch(); | |
919 if (c == 3) exit(1); | |
920 return c; | |
921 } | |
922 | |
923 int exit_script(int n_args, char *args[]) { | |
924 if (n_args > 1) sscanf(args[1], "%ld", &exitcode); | |
925 exit(exitcode); | |
926 return exitcode; | |
927 } | |
928 | |
929 /* | |
930 int return_script(int n_args, char *args[]) { | |
931 if (n_args > 1) sscanf(args[1], "%ld", &exitcode); | |
932 PCB.exit_flag = AG_SUCCESS_CODE; | |
933 return exitcode; | |
934 } | |
935 */ | |
936 | |
937 int subdirs(int n_args, char *args[]) { | |
938 ffblk file_block; | |
939 int flag; | |
940 int length = strlen(args[1]); | |
941 array <char> name(args[1],length + 5); | |
942 | |
943 strcat(name, "\\*.*"); | |
944 for(flag = findfirst(name, &file_block, FA_DIREC); | |
945 flag == 0; flag = findnext(&file_block)) { | |
946 if ((file_block.ff_attrib & FA_DIREC) == 0) continue; | |
947 if (strcmp(file_block.ff_name, ".") == 0) continue; | |
948 if (strcmp(file_block.ff_name, "..") == 0) continue; | |
949 puts(file_block.ff_name); | |
950 } | |
951 return 0; | |
952 } | |
953 | |
954 int files(int n_args, char *args[]) { | |
955 ffblk file_block; | |
956 int flag; | |
957 int length = strlen(args[1]); | |
958 array<char> name(args[1],length + 5); | |
959 | |
960 strcat(name, "\\*.*"); | |
961 for(flag = findfirst(name, &file_block, 0); | |
962 flag == 0; flag = findnext(&file_block)) { | |
963 puts(file_block.ff_name); | |
964 } | |
965 return 0; | |
966 } | |
967 | |
968 | |
969 /***** | |
970 | |
971 Execute Command Line | |
972 | |
973 *****/ | |
974 | |
975 | |
976 void perform_action(action_pointer ap) { | |
977 dsl_pcb_type save_pcb = PCB; | |
978 | |
979 PCB.pointer = ap.pointer; | |
980 first_line = ap.line; | |
981 first_column = ap.column; | |
982 dsl(); | |
983 exitflag = PCB.exit_flag != AG_SUCCESS_CODE; | |
984 PCB = save_pcb; | |
985 if (exitflag) PCB.exit_flag = AG_SEMANTIC_ERROR_CODE; | |
986 } | |
987 | |
988 void exec(void) { | |
989 int n = size(ps << (char *) NULL); | |
990 int n_args = n - 1; | |
991 unsigned index; | |
992 char *cs; | |
993 int i; | |
994 | |
995 array <char *> args(n); | |
996 while (n--) ps >> args[n]; | |
997 | |
998 cs = args[0]; | |
999 for (i = 0; cs[i]; i++) cs[i] = toupper(cs[i]); | |
1000 if (debug_switch) { | |
1001 for (i = 0; args[i]; i++) fprintf(stderr, "%s ", args[i]); | |
1002 fprintf(stderr,"\nPress any key to continue\n"); | |
1003 while (!kbhit()); | |
1004 getch(); | |
1005 } | |
1006 index = sd[args[0]]; | |
1007 if (n_args == 1 && strlen(cs) == 2 && cs[1] == ':') { | |
1008 errorlevel = system(args[0]); | |
1009 } | |
1010 else if ( *cs && index) switch (st[index].type) { | |
1011 case internal_type: { | |
1012 errorlevel = (*st[index].data.proc)(n_args, args); | |
1013 break; | |
1014 } | |
1015 case dos_type: { | |
1016 int i; | |
1017 for (i = 1; args[i]; i++) args[i][-1] = ' '; | |
1018 errorlevel = system(args[0]); | |
1019 assert(errorlevel >= 0); | |
1020 break; | |
1021 } | |
1022 case action_type: { | |
1023 action_descriptor d = *st[index].data.action; | |
1024 stack <symbol_table_entry> old_entries(d.n_args); | |
1025 for (i = 0; i < d.n_args && args[i+1]; i++) { | |
1026 old_entries << st[d.args[i]]; | |
1027 st[d.args[i]].type = value_type; | |
1028 st[d.args[i]].data.text = memdup(args[i+1], 1 + strlen(args[i+1])); | |
1029 } | |
1030 perform_action(d.ap); | |
1031 for (i = d.n_args; i--;) { | |
1032 release(st[d.args[i]]); | |
1033 old_entries >> st[d.args[i]]; | |
1034 } | |
1035 } | |
1036 } | |
1037 else { | |
1038 errorlevel = spawnvp(P_WAIT, args[0], args); | |
1039 assert(errorlevel >= 0); | |
1040 } | |
1041 st[errorlevel_index].data.integer = errorlevel; | |
1042 while (n_args--) --sa; | |
1043 --ps; | |
1044 if (kbhit()) { | |
1045 int c = getch(); | |
1046 if (c == 3) exit(1); | |
1047 ungetch(c); | |
1048 } | |
1049 } | |
1050 | |
1051 void discard_temp_file(char *file_name) { | |
1052 unlink(file_name); // Delete file | |
1053 delete [] file_name; // Free storage for name | |
1054 } | |
1055 | |
1056 | |
1057 /***** | |
1058 | |
1059 Execute Command with piped input | |
1060 | |
1061 *****/ | |
1062 | |
1063 | |
1064 void exec_pipe_in(char *file_name) { | |
1065 { | |
1066 redirect sin(STDIN, file_name); | |
1067 exec(); | |
1068 } | |
1069 discard_temp_file(file_name); | |
1070 } | |
1071 | |
1072 | |
1073 /***** | |
1074 | |
1075 Execute Command with redirected I/O | |
1076 | |
1077 *****/ | |
1078 | |
1079 void exec_redirect_in(void) { | |
1080 redirect sin(STDIN, sa--); | |
1081 exec(); | |
1082 } | |
1083 | |
1084 char *exec_pipe_out(void) { | |
1085 redirect sout(STDOUT); | |
1086 exec(); | |
1087 return save_file(sout); | |
1088 } | |
1089 | |
1090 char *exec_pipe_in_pipe_out(char *file_name) { | |
1091 char *result; | |
1092 { | |
1093 redirect sin(STDIN, file_name); | |
1094 redirect sout(STDOUT); | |
1095 exec(); | |
1096 result = save_file(sout); | |
1097 } | |
1098 discard_temp_file(file_name); | |
1099 return result; | |
1100 } | |
1101 | |
1102 char *exec_redirect_in_pipe_out(void) { | |
1103 redirect sout(STDOUT); | |
1104 exec_redirect_in(); | |
1105 return save_file(sout); | |
1106 } | |
1107 | |
1108 unsigned check_integer(void) { | |
1109 unsigned index = sd << sa--; | |
1110 if (st[index].type == integer_type) return index; | |
1111 CHANGE_REDUCTION(undeclared_variable); | |
1112 if (st[index].type == string_type) CHANGE_REDUCTION(string_variable); | |
1113 return index; | |
1114 } | |
1115 | |
1116 void assign_value(unsigned index) { | |
1117 char *text = copy(sa--); | |
1118 release(st[index]); | |
1119 st[index].type = value_type; | |
1120 st[index].data.text = text; | |
1121 } | |
1122 | |
1123 void grab_output(char *temp_name) { | |
1124 unlink(sa); // delete old file | |
1125 rename(temp_name, sa--); // rename temp file | |
1126 delete [] temp_name; // discard name string | |
1127 } | |
1128 | |
1129 void append_output(char *temp_name) { | |
1130 redirect sout(STDOUT, sa--, 1); // append to file named on sa | |
1131 redirect sin(STDIN, temp_name); | |
1132 char *buf[2000]; | |
1133 int n; | |
1134 while (1) { | |
1135 n = read(STDIN, buf, 2000); | |
1136 if (n == 0) break; | |
1137 write(STDOUT, buf, n); | |
1138 } | |
1139 unlink(temp_name); | |
1140 delete [] temp_name; | |
1141 } | |
1142 | |
1143 void action_string(void) { | |
1144 action_pointer ap; | |
1145 as >> ap; | |
1146 unsigned length = (unsigned)(PCB.pointer - ap.pointer); | |
1147 array <unsigned char> action(ap.pointer,length + 1); | |
1148 action[length] = 0; | |
1149 redirect sout(STDOUT); | |
1150 char *result; | |
1151 | |
1152 ap.pointer = action; | |
1153 perform_action(ap); | |
1154 result = content(sout); | |
1155 ++sa << result; | |
1156 delete [] result; | |
1157 } | |
1158 | |
1159 | |
1160 // Program Control functions | |
1161 | |
1162 // If/else statement | |
1163 | |
1164 int do_if(int pc, int cc) { | |
1165 action_pointer ap; | |
1166 as >> ap; | |
1167 if (!pc && cc && exitflag == 0) { | |
1168 unsigned length = (unsigned) (PCB.pointer - ap.pointer); | |
1169 array<unsigned char> q(ap.pointer, length+1); | |
1170 q[length] = 0; | |
1171 ap.pointer = q; | |
1172 perform_action(ap); | |
1173 } | |
1174 return pc || cc; | |
1175 } | |
1176 | |
1177 // While statement | |
1178 | |
1179 void do_while(int cc) { | |
1180 unsigned length; | |
1181 action_pointer ap; | |
1182 as >> ap; | |
1183 if (cc == 0) return; | |
1184 length = (unsigned) (PCB.pointer - ap.pointer); | |
1185 array<unsigned char> q(ap.pointer, length+1); | |
1186 q[length] = 0; | |
1187 ap.pointer = q; | |
1188 perform_action(ap); | |
1189 if (exitflag) return; | |
1190 PCB.pointer = CONTEXT.pointer; | |
1191 PCB.line = CONTEXT.line; | |
1192 PCB.column = CONTEXT.column; | |
1193 } | |
1194 | |
1195 | |
1196 // For Statement | |
1197 // Note that this is the for statement in the DOS batch languange for, not C | |
1198 | |
1199 void do_for_loop(void) { | |
1200 int n,k; | |
1201 char *q; | |
1202 char *seps = " \t\v\f\r\n"; | |
1203 action_pointer ap; | |
1204 as >> ap; | |
1205 unsigned length = (unsigned)(PCB.pointer - ap.pointer); | |
1206 array <unsigned char> action(ap.pointer, length + 1); | |
1207 action[length] = 0; | |
1208 | |
1209 ap.pointer = action; | |
1210 n = size(sa); | |
1211 array<char> text(sa--, n + 1); | |
1212 | |
1213 | |
1214 unsigned index = sd << sa--; | |
1215 | |
1216 ++ps; | |
1217 for (q = strtok(text, seps); q != NULL; q = strtok(NULL,seps)) { | |
1218 if (*q == '(') { | |
1219 int k = strlen(q) - 1; | |
1220 assert(q[k] == ')'); | |
1221 q[k] = 0; | |
1222 q++; | |
1223 } | |
1224 else if (*q == '"') { | |
1225 int k = strlen(q) - 1; | |
1226 assert(q[k] == '"'); | |
1227 q[k] = 0; | |
1228 q++; | |
1229 } | |
1230 ps << q; | |
1231 } | |
1232 k = n = size(ps); | |
1233 array<char *> args(n); | |
1234 while (k--) ps >> args[k]; | |
1235 --ps; | |
1236 symbol_table_entry save_table_entry = st[index]; | |
1237 st[index].type = value_type; | |
1238 | |
1239 for (k = 0; k < n && exitflag == 0; k++) { | |
1240 st[index].data.text = args[k]; | |
1241 perform_action(ap); | |
1242 } | |
1243 st[index] = save_table_entry; | |
1244 } | |
1245 | |
1246 void invoke_script(void) { | |
1247 int handle = open(sa, O_TEXT | O_RDONLY); | |
1248 long size; | |
1249 unsigned n; | |
1250 action_pointer ap; | |
1251 | |
1252 if (handle < 0) { | |
1253 fprintf(stderr,"Cannot open %s\n", (char *) sa--); | |
1254 exit(1); | |
1255 } | |
1256 --sa; | |
1257 size = filelength(handle); | |
1258 assert(size < 65536L); | |
1259 array <unsigned char> data((unsigned) size+1); | |
1260 n = (unsigned) read(handle,data,(unsigned) size); | |
1261 data[n] = 0; | |
1262 close(handle); | |
1263 exitflag = 0; | |
1264 ap.pointer = data; | |
1265 ap.line = ap.column = 1; | |
1266 perform_action(ap); | |
1267 st[errorlevel_index].data.integer = exitcode; | |
1268 exitflag = exitcode = 0; | |
1269 return; | |
1270 } | |
1271 | |
1272 internal_commands_descriptor internal_commands[] = { | |
1273 {"ECHO", echo}, | |
1274 {"EXIT", exit_script}, | |
1275 {"FILES", files}, | |
1276 {"PAUSE", pause}, | |
1277 // {"RETURN", return_script}, | |
1278 {"SUBDIRS", subdirs}, | |
1279 {NULL, NULL} | |
1280 }; | |
1281 | |
1282 struct built_ins_descriptor built_ins[] = { | |
1283 {"file_exists", file_exists}, | |
1284 {"directory_exists", directory_exists}, | |
1285 {"string_length", string_length}, | |
1286 {"file_length", get_file_length}, | |
1287 {"disk_space", disk_space}, | |
1288 {"file_time", file_time}, | |
1289 {NULL, NULL} | |
1290 }; | |
1291 | |
1292 void set_extension(char *path, char *e) { | |
1293 char s[MAXPATH]; | |
1294 char drive[MAXDRIVE]; | |
1295 char dir[MAXDIR]; | |
1296 char file[MAXFILE]; | |
1297 char ext[MAXEXT]; | |
1298 | |
1299 fnsplit(path,drive,dir,file,ext); | |
1300 fnmerge(s, drive, dir, file, e); | |
1301 ++sa << s; | |
1302 } | |
1303 | |
1304 /* | |
1305 Note that if this program is called without any arguments, it looks for a | |
1306 script with the same name as the executable. Thus, to make an install | |
1307 program that picks up the install script without any arguments, you simply | |
1308 rename DSL.EXE to INSTALL.EXE. Then when you run it without any arguments | |
1309 it will run the INSTALL.DSL script. | |
1310 */ | |
1311 | |
1312 void main(int argc, char *argv[]) { | |
1313 int arg_number = 0; | |
1314 int i = 1; | |
1315 int j = 0; | |
1316 | |
1317 init_dos_internals(); | |
1318 set_arg(j++, argv[0]); | |
1319 if (argc > i && (argv[i][0] == '/' || argv[i][0] == '-')) { | |
1320 if (toupper(argv[i][1]) != 'D') { | |
1321 printf("Unrecognized switch -- /%s\n",argv[i][1]); | |
1322 return; | |
1323 } | |
1324 debug_switch = 1; | |
1325 i++; | |
1326 } | |
1327 if (argc > i) arg_number = i++; | |
1328 set_extension(argv[arg_number], "DSL"); | |
1329 set_arg(j++,copy(sa)); | |
1330 while (i < argc) set_arg(j++, argv[i++]); | |
1331 define_integer("argc", j); | |
1332 invoke_script(); // Takes file name from sa | |
1333 exit(exitcode); | |
1334 } | |
1335 } // End Embedded C |