home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / unix / volume26 / celllr20 / part03 < prev    next >
Encoding:
Text File  |  1993-04-02  |  81.3 KB  |  2,648 lines

  1. Newsgroups: comp.sources.unix
  2. From: dana@rucs.faculty.cs.runet.edu (J Dana Eckart)
  3. Subject: v26i090: cellular-2.0 - a cellular automata language, Part03/03
  4. Sender: unix-sources-moderator@vix.com
  5. Approved: paul@vix.com
  6.  
  7. Submitted-By: dana@rucs.faculty.cs.runet.edu (J Dana Eckart)
  8. Posting-Number: Volume 26, Issue 90
  9. Archive-Name: cellular-2.0/part03
  10.  
  11. #! /bin/sh
  12. # This is a shell archive.  Remove anything before this line, then unpack
  13. # it by saving it into a file and typing "sh file".  To overwrite existing
  14. # files, type "sh file -c".  You can also feed this as standard input via
  15. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  16. # will see the following message at the end:
  17. #        "End of archive 3 (of 3)."
  18. # Contents:  compiler/semantic.c tutorial.tex
  19. # Wrapped by vixie@gw.home.vix.com on Sat Apr  3 01:27:39 1993
  20. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  21. if test -f 'compiler/semantic.c' -a "${1}" != "-c" ; then 
  22.   echo shar: Will not clobber existing file \"'compiler/semantic.c'\"
  23. else
  24. echo shar: Extracting \"'compiler/semantic.c'\" \(50650 characters\)
  25. sed "s/^X//" >'compiler/semantic.c' <<'END_OF_FILE'
  26. X/* semantic.c
  27. X   Copyright (C) 1992  J Dana Eckart
  28. X  
  29. X   This program is free software; you can redistribute it and/or modify
  30. X   it under the terms of the GNU General Public License as published by
  31. X   the Free Software Foundation; either version 1, or (at your option)
  32. X   any later version.
  33. X  
  34. X   This program is distributed in the hope that it will be useful,
  35. X   but WITHOUT ANY WARRANTY; without even the implied warranty of
  36. X   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  37. X   GNU General Public License for more details.
  38. X  
  39. X   You should have received a copy of the GNU General Public License
  40. X   along with CELLULAR-2.0; see the file COPYING.  If not, write to the 
  41. X   Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  42. X*/
  43. X
  44. X/* This file contains the semantic routines (and their respective
  45. X   support functions) for checking static semantics and generating 
  46. X   the intermediate representation (C code).
  47. X
  48. X   The names of variables are preceeded by an underscore ("_") in the C 
  49. X   code for the rule set of the cellular automata.  All other variables 
  50. X   generated by the compiler (and not appearing in the rule set of the 
  51. X   input) are NOT preceeded by a "_" (underscore); thus guaranteeing no 
  52. X   name conflicts (defines are given in capitals to prevent name conflicts).
  53. X
  54. X   NOTE: The comments given for semantic routines give the items that
  55. X     the routine expects and leaves on the semantic stack.  In both
  56. X     cases, the top of the stack is the leftmost item given.
  57. X*/
  58. X
  59. X#include <stdio.h>
  60. X#include <string.h>
  61. X#include <limits.h>
  62. X#include "boolean.h"
  63. X#include "error.h"
  64. X#include "semantic.h"
  65. X#include "attribute.h"
  66. X#include "symtable.h"
  67. X#include "stack.h"
  68. X
  69. X/* The following declarations determine how many dimensions the cellular
  70. X   universe can have and how many fields each cell is allowed.
  71. X*/
  72. X#include "size.h"
  73. X
  74. XFILE *file_h = NULL;        /* Denotes the C header output stream. */
  75. XFILE *file_c = NULL;        /* Denotes the C code output stream. */
  76. X
  77. X#define MAX_STRING_LENGTH    256
  78. X
  79. boolean semantic_error = false;    /* Indicates if a semantic error has occured. */
  80. X
  81. X#define MAX_STACK_SIZE     25    /* Size of the semantic stack. */
  82. X
  83. stack_entry stack[MAX_STACK_SIZE];    /* The semantic stack. */
  84. int top = -1;                /* Current top of semantic stack. */
  85. X
  86. X/* SUPPORT ROUTINE
  87. X      ACTION - Increments top.  This provides checking so that pushes
  88. X           onto the semantic stack are checked to insure that an
  89. X           overflow does not occur.
  90. X*/
  91. void new_entry() {
  92. X    if (top == MAX_STACK_SIZE - 1) {
  93. X        fprintf(stderr, "INTERNAL ERROR: Semantic stack overflow.\n");
  94. X        exit(1);
  95. X    }
  96. X    top++;
  97. X}
  98. X
  99. X/************************************************************************/
  100. X
  101. X/* SUPPORT ROUTINE
  102. X      ACTION - Prints an error message using the provided format
  103. X           and input string, preceeded by the current line
  104. X           number of the input stream.  A flag specifing that 
  105. X           a semantic error was encountered is also set to true.
  106. X*/
  107. void error(format, string) char *format, *string; {
  108. X    semantic_error = true;
  109. X    error_prefix();
  110. X    fprintf(stderr, format, string);
  111. X    fprintf(stderr, "\n");
  112. X}
  113. X
  114. X/************************************************************************/
  115. X
  116. X/* Indentation to make the generated C code easier to read is 
  117. X   accomplished by using print_indent.  The amount of indentation
  118. X   is kept in the "indentation" variable, whose value is updated
  119. X   through use of the macros "indent" and "undent".
  120. X*/
  121. X
  122. int indentation = 0;
  123. X
  124. X#define indent    indentation += 3
  125. X#define undent    indentation -= 3
  126. X
  127. X/* SUPPORT ROUTINE
  128. X      ACTION - Prints the current amount of indentation to the 
  129. X           specified file.
  130. X*/
  131. void print_indent() {
  132. X    int i;
  133. X    for (i = 0; i < indentation; i++) fprintf(file_c, " ");
  134. X}
  135. X
  136. X/************************************************************************/
  137. X
  138. X/* SUPPORT ROUTINE
  139. X      ACTION - Checks the top n entries (0 checks NO entries) on 
  140. X           top of the stack and returns true iff at least one 
  141. X           of them is a StackError entry.
  142. X*/
  143. boolean stack_error(n) int n; {
  144. X    int i;
  145. X    if (n-1 > top)
  146. X        error("COMPILER ERROR -- too few entries on semantic stack\n",
  147. X            (char*) NULL);
  148. X    for (i = 0; i < n; i++)
  149. X        if (stack[top-i].kind == StackError) return true;
  150. X    return false;
  151. X}
  152. X
  153. X/************************************************************************/
  154. X
  155. X/* A current count of the number of dimensions. */
  156. int dimension_count = 0;
  157. X
  158. X/* Used to count the number of fields declared for the cells of the universe. */
  159. int field_count;
  160. X
  161. X/* SUPPORT ROUTINE
  162. X      ACTION - Enter the predefined identifiers "time" and "cell" into the
  163. X           symbol table.
  164. X*/
  165. void decl_time_and_cell() {
  166. X    attr_rec attribute;
  167. X
  168. X    /* Enter the predefined symbols "cell" and "time". */
  169. X    attribute.assignable = true;
  170. X    attribute.field_name = false;
  171. X    attribute.structured = field_count > 1;
  172. X    enterid("cell", attribute);
  173. X
  174. X    attribute.assignable = false;
  175. X    attribute.field_name = false;
  176. X    attribute.structured = false;
  177. X    enterid("time", attribute);
  178. X}
  179. X
  180. X/************************************************************************/
  181. X
  182. X/* SEMANTIC ROUTINE
  183. X      EXPECTS - StackExpr
  184. X      LEAVES  - n/a
  185. X      ACTION  - Set the number of dimensions in the cellular automata 
  186. X        universe to that indicated by the top of the stack.
  187. X*/
  188. void set_dimensions() {
  189. X    if (stack_error(1)) {
  190. X        top--;
  191. X        return;
  192. X    }
  193. X    else {
  194. X        dimension_count = atoi(stack[top--].data.expr.addr);
  195. X
  196. X        /* Make sure not too many dimensions are used. */
  197. X        if (dimension_count > MAX_SUPPORTED_DIMENSIONS)
  198. X            error("Sorry, no more than %d dimensions are supported",
  199. X                  (char*) MAX_SUPPORTED_DIMENSIONS);
  200. X    }
  201. X}
  202. X
  203. X/* Holds the field names given in the cell declaration, along with their
  204. X   upper and lower bounds, in the order they were declared.
  205. X*/
  206. struct {
  207. X    char *name;
  208. X    long int lb, ub;
  209. X} field_list[MAX_SUPPORTED_FIELDS];
  210. X
  211. X/* SEMANTIC ROUTINE
  212. X      EXPECTS - n/a
  213. X      LEAVES  - n/a
  214. X      ACTION  - Start the cell type declaration.
  215. X*/
  216. void begin_decl_cells() {
  217. X    field_count = 0;
  218. X
  219. X    /* Begin the cell type declaration. */
  220. X    fprintf(file_c, "typedef struct {\n");
  221. X    indent;
  222. X}
  223. X
  224. X/* SEMANTIC ROUTINE
  225. X      EXPECTS - n/a
  226. X      LEAVES  - n/a
  227. X      ACTION  - Writes code to declare the cell type of the cells which
  228. X        make up the cellular automata universe.
  229. X*/
  230. void end_decl_cells() {
  231. X    int i;
  232. X
  233. X    /* Finish the cell declaration. */
  234. X    undent;
  235. X    print_indent();
  236. X    fprintf(file_c, "} cell_type;\n\n");
  237. X
  238. X    /* Make sure not too many fields are used. */
  239. X    if (field_count > MAX_SUPPORTED_FIELDS)
  240. X        error("Sorry, no more than %d fields are supported",
  241. X              (char*) MAX_SUPPORTED_FIELDS);
  242. X
  243. X
  244. X    /* Write the function definition for "neq". */
  245. X    print_indent();
  246. X    fprintf(file_c, "int neq(x,y) cell_type *x, *y; {\n"); 
  247. X    indent;
  248. X    print_indent();
  249. X    fprintf(file_c, "return (");
  250. X    for (i = 0; i < field_count; i++) {
  251. X        fprintf(file_c, "(x->%s == y->%s)",
  252. X            field_list[i].name, field_list[i].name); 
  253. X        if (i < field_count - 1)
  254. X            fprintf(file_c, "||");
  255. X    }
  256. X    fprintf(file_c, ");\n"); 
  257. X    undent;
  258. X    print_indent();
  259. X    fprintf(file_c, "}\n\n");
  260. X
  261. X    /* Write the function definition for "assign_cell". */
  262. X    print_indent();
  263. X    fprintf(file_c, "void assign_cell(x,y) cell_type *x, *y; {\n"); 
  264. X    indent;
  265. X    for (i = 0; i < field_count; i++) {
  266. X        print_indent();
  267. X        fprintf(file_c, "x->%s = y->%s;\n",
  268. X            field_list[i].name, field_list[i].name); 
  269. X    }
  270. X    undent;
  271. X    print_indent();
  272. X    fprintf(file_c, "}\n\n");
  273. X}
  274. X
  275. X/************************************************************************/
  276. X
  277. X/* SEMANTIC ROUTINE
  278. X      EXPECTS - StackRange, StackToken, ... StackToken, StackMark
  279. X      LEAVES  - n/a
  280. X      ACTION  - Take the list of field identifiers from the stack and
  281. X        delcare them with the given range.  No code is generated.
  282. X*/
  283. void declare_fields() {
  284. X    int mark;
  285. X    range_entry range = stack[top--].data.range;
  286. X
  287. X    /* Go down to the mark. */
  288. X        mark = top;
  289. X    while (stack[mark].kind != StackMark) mark--;
  290. X
  291. X    /* Enter each of the fields into the symbol table. */ 
  292. X    while (++mark <= top) {
  293. X        char *token = stack[mark].data.token;
  294. X    
  295. X        /* Enter into symbol table if necessary. */
  296. X        if (!intable(token, FIELD)) {
  297. X            attr_rec attribute;
  298. X            attribute.assignable = true;
  299. X            attribute.field_name = true;
  300. X            attribute.structured = false;
  301. X            enterid(token, attribute);
  302. X
  303. X            print_indent();
  304. X            fprintf(file_c, "%s %s;\n", FIELD_TYPE, token);
  305. X        }
  306. X        else
  307. X            error("Redeclaration of field, '%s'", token);
  308. X
  309. X        field_list[field_count].name = (char*) malloc(strlen(token) + 1);
  310. X        strcpy(field_list[field_count].name, token);
  311. X        field_list[field_count].lb = range.lower_bound;
  312. X        field_list[field_count].ub = range.upper_bound;
  313. X
  314. X        field_count++;
  315. X    }
  316. X
  317. X    /* Clean stuff off the stack. */
  318. X    while (stack[top].kind != StackMark)
  319. X        free(stack[top--].data.token);
  320. X    top--;
  321. X}
  322. X
  323. X/* SEMANTIC ROUTINE
  324. X      EXPECTS - StackRange
  325. X      LEAVES  - n/a
  326. X      ACTION  - Generate a declaration for cells to be of a single field
  327. X                with the given range.  No code is generated.
  328. X*/
  329. void declare_default_field() {
  330. X    print_indent();
  331. X    fprintf(file_c, "typedef %s cell_type;\n", FIELD_TYPE);
  332. X
  333. X    field_count = 1;
  334. X
  335. X    /* Build appropriate macros for "neq" and "assign_cell". */
  336. X    fprintf(file_c, "#define neq(x,y) ((*(x))!=(*(y)))\n\n");
  337. X    fprintf(file_c, "#define assign_cell(x,y) ((*(x))=(*(y)))\n\n");
  338. X
  339. X    top--;
  340. X}
  341. X
  342. X/************************************************************************/
  343. X
  344. X/* SEMANTIC ROUTINE
  345. X      EXPECTS - StackExpr, StackExpr
  346. X      LEAVES  - StackRange
  347. X      ACTION  - Convert the top two entries on the semantic stack into
  348. X        a single range entry.
  349. X*/
  350. void make_range() {
  351. X    if (stack_error(2)) {
  352. X        if (stack[top].kind != StackError)
  353. X            free(stack[top].data.expr.addr);
  354. X        if (stack[top-1].kind != StackError)
  355. X            free(stack[top-1].data.expr.addr);
  356. X        top--;
  357. X        stack[top].kind = StackError;
  358. X        return;
  359. X    }
  360. X    else {
  361. X        range_entry range;
  362. X
  363. X        /* Build the range entry. */
  364. X        range.upper_bound = atoi(stack[top].data.expr.addr);
  365. X        free(stack[top--].data.expr.addr);
  366. X        range.lower_bound = atoi(stack[top].data.expr.addr);
  367. X        free(stack[top--].data.expr.addr);
  368. X
  369. X        /* Warn if desired range is not supported. */
  370. X        if (range.lower_bound < MAX_RANGE_LB || 
  371. X            range.upper_bound > MAX_RANGE_UB) {
  372. X            error_prefix();
  373. X            fprintf(stderr, "Range [%d..%d] not supported (warning)\n", 
  374. X                range.lower_bound, range.upper_bound);
  375. X        }
  376. X
  377. X        /* Push the range entry onto the stack. */
  378. X        new_entry();
  379. X        stack[top].kind = StackRange;
  380. X        stack[top].data.range = range;
  381. X    }
  382. X}
  383. X
  384. X/************************************************************************/
  385. X
  386. X/* SUPPORT ROUTINE
  387. X      ACTION  - Declare var_name as a variable of type.
  388. X*/
  389. void decl_variable(var_name, type) char *var_name, *type; {
  390. X    attr_rec attribute;
  391. X    
  392. X    /* Enter into symbol table. */
  393. X    attribute.assignable = true;
  394. X    attribute.field_name = false;
  395. X    attribute.structured = (0 == strcmp(type, "cell_type"));
  396. X    enterid(var_name, attribute);
  397. X
  398. X    /* Write code to declare the variable. */
  399. X    fprintf(file_h, "%s _%s;\n", type, var_name);
  400. X}
  401. X
  402. X/* SEMANTIC ROUTINE
  403. X      EXPECTS - StackExpr_2, StackExpr_1
  404. X      LEAVES  - StackExpr
  405. X      ACTION  - Writes code to perform an assignment.  Implicit declarations
  406. X            of variables are made, with the type of the variable being
  407. X            determined by the first right hand side given.
  408. X*/
  409. void do_assign() {
  410. X    if (stack_error(2)) {
  411. X        if (stack[top].kind != StackError)
  412. X            free(stack[top].data.expr.addr);
  413. X        top--;
  414. X        stack[top].kind = StackError;
  415. X        return;
  416. X    }
  417. X    else {
  418. X        char base_addr[MAX_STRING_LENGTH];
  419. X        expr_entry expr_1, expr_2;
  420. X        expr_2 = stack[top--].data.expr;
  421. X        expr_1 = stack[top].data.expr;
  422. X
  423. X        /* Declare the variable if necessary. */
  424. X        if (!intable(expr_1.addr, VARIABLE)) {
  425. X
  426. X            /* Put it in the symbol table. */
  427. X            if (expr_2.unstructured)
  428. X                decl_variable(expr_1.addr, FIELD_TYPE);
  429. X            else
  430. X                decl_variable(expr_1.addr, "cell_type");
  431. X        }
  432. X
  433. X        /* Get the symbol table information for expr_1. */
  434. X        stack[top].data.expr.unstructured = 
  435. X            !(get_attribute(expr_1.addr, VARIABLE)->structured);
  436. X        expr_1 = stack[top].data.expr;
  437. X
  438. X        /* Check for a field of expr_1. */
  439. X        if (expr_1.field) expr_1.unstructured = 1;
  440. X
  441. X        /* The variable "cell" is a special case. */
  442. X        if (strcmp(expr_1.addr, "cell") == 0)
  443. X            sprintf(base_addr, "(*_%s)", expr_1.addr);
  444. X        else
  445. X            sprintf(base_addr, "_%s", expr_1.addr);
  446. X
  447. X        print_indent();
  448. X
  449. X        if (expr_1.unstructured && expr_2.unstructured) {
  450. X            fprintf(file_c, "(%s)", base_addr);
  451. X            if (expr_1.field != (char*) NULL)
  452. X                fprintf(file_c, ".%s", expr_1.field);
  453. X            fprintf(file_c, " = %s;\n", expr_2.addr);
  454. X        }
  455. X        else if (!expr_1.unstructured && !expr_2.unstructured)
  456. X            fprintf(file_c, "assign_cell(&(%s), &(%s));\n", 
  457. X                base_addr, expr_2.addr);
  458. X        else
  459. X{
  460. printf("'%s' and '%s' are incompatible\n", expr_1.addr, expr_2.addr);
  461. X            error("Incompatible assignment", (char*) NULL);
  462. X}
  463. X
  464. X        free(expr_2.addr);
  465. X    }
  466. X}
  467. X
  468. X/* SEMANTIC ROUTINE
  469. X      EXPECTS - StackExpr
  470. X      LEAVES  - n/a
  471. X      ACTION  - Removes the assignable which is on top of the semantic
  472. X        stack, since it is no longer needed.  No code is written.
  473. X*/
  474. void end_assign() {
  475. X    free(stack[top--].data.expr.addr);
  476. X}
  477. X
  478. X/************************************************************************/
  479. X
  480. X/* SEMANTIC ROUTINE
  481. X      EXPECTS - StackToken
  482. X      LEAVES  - StackExpr
  483. X      ACTION  - Converts the entry on top of the stack into an assignable
  484. X        base entry.
  485. X*/
  486. void assignable_base() {
  487. X    char *token = stack[top].data.token;
  488. X
  489. X    /* Convert StackToken entry into a StackExpr entry. */
  490. X    stack[top].kind = StackExpr;
  491. X    stack[top].data.expr.assignable = true;
  492. X    stack[top].data.expr.unstructured = (field_count == 1);
  493. X    stack[top].data.expr.field = (char*) NULL;
  494. X    stack[top].data.expr.addr = token;
  495. X
  496. X    stack[top].data.expr.pre_declared = intable(token, VARIABLE);
  497. X}
  498. X
  499. X/************************************************************************/
  500. X
  501. X/* SEMANTIC ROUTINE
  502. X      EXPECTS - StackExpr
  503. X      LEAVES  - n/a
  504. X      ACTION  - Writes code to conditionally perform a block of statements.
  505. X*/
  506. void jump_if() {
  507. X    if (stack_error(1)) {
  508. X        top--;
  509. X        return;
  510. X    }
  511. X    else {
  512. X        print_indent();
  513. X        fprintf(file_c, "if (%s) {\n", stack[top].data.expr.addr);
  514. X        indent;
  515. X        free(stack[top--].data.expr.addr);
  516. X    }
  517. X}
  518. X
  519. X/* SEMANTIC ROUTINE
  520. X      EXPECTS - StackExpr
  521. X      LEAVES  - n/a
  522. X      ACTION  - Writes code to conditionally perform a block of statements 
  523. X        as an alternative to previous if's and elsif's.
  524. X*/
  525. void jump_elsif() {
  526. X    if (stack_error(1)) {
  527. X        top--;
  528. X        return;
  529. X    }
  530. X    else {
  531. X        undent;
  532. X        print_indent();
  533. X        fprintf(file_c, 
  534. X            "} else if (%s) {\n", stack[top].data.expr.addr);
  535. X        indent;
  536. X        free(stack[top--].data.expr.addr);
  537. X    }
  538. X}
  539. X
  540. X/* SEMANTIC ROUTINE
  541. X      EXPECTS - n/a
  542. X      LEAVES  - n/a
  543. X      ACTION  - Writes code to unconditionally perform a block of 
  544. X        statements as an alternative to previous if's and elsif's.
  545. X*/
  546. void start_else() {
  547. X    undent;
  548. X    print_indent();
  549. X    fprintf(file_c, "} else {\n");
  550. X    indent;
  551. X}
  552. X
  553. X/* SEMANTIC ROUTINE
  554. X      EXPECTS - n/a
  555. X      LEAVES  - n/a
  556. X      ACTION  - Writes code to close off an if statement.
  557. X*/
  558. void end_if() {
  559. X    undent;
  560. X    print_indent();
  561. X    fprintf(file_c, "}\n");
  562. X}
  563. X
  564. X/************************************************************************/
  565. X
  566. X/* SEMANTIC ROUTINE
  567. X      EXPECTS - n/a
  568. X      LEAVES  - StackMark
  569. X      ACTION  - Pushes the StackMark onto the semantic stack.
  570. X*/
  571. void push_mark() { 
  572. X    new_entry();
  573. X    stack[top].kind = StackMark; 
  574. X}
  575. X
  576. X/* SEMANTIC ROUTINE
  577. X      EXPECTS - n/a
  578. X      LEAVES  - StackToken
  579. X      ACTION  - Pushes a string the stack.
  580. X*/
  581. void push(string) char *string; {
  582. X    new_entry();
  583. X    stack[top].kind = StackToken;
  584. X    stack[top].data.token = mymalloc((unsigned int) (strlen(string) + 1));
  585. X    strcpy(stack[top].data.token, string);
  586. X}
  587. X
  588. X/************************************************************************/
  589. X
  590. X/* SEMANTIC ROUTINE
  591. X      EXPECTS - n/a
  592. X      LEAVES  - StackExpr
  593. X      ACTION  - Pushes a StackExpr onto the stack that represents the
  594. X        value of the expression denoted by the literal.
  595. X*/
  596. void process_literal(literal) char *literal; {
  597. X    expr_entry expr;
  598. X    expr.assignable = false;
  599. X    expr.unstructured = true;
  600. X    expr.addr = mymalloc((unsigned int) (strlen(literal) + 1));
  601. X    sprintf(expr.addr, "%s", literal);
  602. X    new_entry();
  603. X    stack[top].kind = StackExpr;
  604. X    stack[top].data.expr = expr;
  605. X}
  606. X
  607. X/************************************************************************/
  608. X
  609. X/* SEMANTIC ROUTINE
  610. X      EXPECTS - StackExpr, StackToken
  611. X      LEAVES  - StackExpr
  612. X      ACTION  - Performs a simplified unary_op operation, building an
  613. X        integer value without () or spaces.  This allows the
  614. X        routine cell_reference to do an atoi call to get the
  615. X        value of the integer and to compare it against the size
  616. X        of the range for a dimension.
  617. X*/
  618. void mk_signed_int() {
  619. X    stack_entry entry_1, entry_2;
  620. X    entry_2 = stack[top--];
  621. X    entry_1 = stack[top];
  622. X    stack[top].kind = StackExpr;
  623. X    stack[top].data.expr.assignable = false;
  624. X    stack[top].data.expr.unstructured = false;
  625. X    if (strcmp(entry_1.data.token, "-") == 0) {
  626. X        stack[top].data.expr.addr = 
  627. X            mymalloc((unsigned int)
  628. X                    (strlen(entry_2.data.token) + 2));
  629. X        sprintf(stack[top].data.expr.addr, 
  630. X            "-%s", entry_2.data.expr.addr);
  631. X        free(entry_2.data.expr.addr);
  632. X    }
  633. X    else {
  634. X        stack[top].data.expr.addr = entry_2.data.expr.addr;
  635. X    }
  636. X    free(entry_1.data.token);
  637. X}
  638. X
  639. X/************************************************************************/
  640. X
  641. X/* SEMANTIC ROUTINE
  642. X      EXPECTS - StackToken
  643. X      LEAVES  - StackExpr
  644. X      ACTION  - Checks to insure that the token has been declared as
  645. X        a variable.  If not an error is generated, if so then
  646. X        the entry is converted into an expression.
  647. X*/
  648. void get_variable() {
  649. X    char *string = stack[top].data.token;
  650. X    if (!intable(string, VARIABLE)) {
  651. X        error("Variable '%s' used before set", string); 
  652. X        free(stack[top].data.token);
  653. X        stack[top].kind = StackError;  
  654. X    }
  655. X    else {
  656. X        attr_rec *attr = get_attribute(string, VARIABLE);
  657. X        unsigned int size = strlen(string) + 2;
  658. X
  659. X        /* Do the conversion into an expression. */
  660. X        stack[top].kind = StackExpr;  
  661. X        stack[top].data.expr.assignable = false; 
  662. X        stack[top].data.expr.unstructured = !attr->structured;
  663. X
  664. X        /* The variable "cell" is a special case. */
  665. X        if (strcmp(string, "cell") == 0) size += 3;
  666. X
  667. X        stack[top].data.expr.addr = mymalloc(size);
  668. X
  669. X        /* The variable "cell" is a special case. */
  670. X        if (strcmp(string, "cell") == 0)
  671. X            sprintf(stack[top].data.expr.addr, "(*_%s)", string);
  672. X        else
  673. X            sprintf(stack[top].data.expr.addr, "_%s", string);  
  674. X
  675. X        free(string);
  676. X    }
  677. X}
  678. X
  679. X/************************************************************************/
  680. X
  681. X/* SEMANTIC ROUTINE
  682. X      EXPECTS - StackExpr, ..., StackExpr, StackMark
  683. X      LEAVES  - StackExpr
  684. X      ACTION  - The number of StackExpr before the StackMark must be
  685. X        equal to the number of dimensions in the cellular
  686. X        universe.  The relative indices (StackExpr's) into the 
  687. X        universe are converted into the proper C array reference 
  688. X        code which uses the current values of the dimension
  689. X        indices and modular arithmetic to guarantee that the 
  690. X        references are legal.  References are made more efficient
  691. X        by not doing any arithmetic if the relative index is 0.
  692. X*/
  693. void cell_reference() {
  694. X    char *new_addr;
  695. X    unsigned int size = strlen("cells[now]") + 1;
  696. X    int mark = top;
  697. X    int tmp_top;
  698. X    int dim_count;
  699. X
  700. X    /* Determine the size of the array reference. */ 
  701. X    dim_count = 0;
  702. X    while (stack[mark].kind != StackMark) {
  703. X        char sub_expr[MAX_STRING_LENGTH];
  704. X        int index_value = atoi(stack[mark].data.expr.addr);
  705. X        dim_count++;
  706. X        if (0 == index_value)
  707. X            sprintf(sub_expr, "[dim_%d]", dim_count);
  708. X        else if (index_value > 0)
  709. X            sprintf(sub_expr, 
  710. X                "[((x=dim_%d+%s)>=DIM_%d_SIZE?x-DIM_%d_SIZE:x)]",
  711. X                dim_count, 
  712. X                stack[mark].data.expr.addr,
  713. X                dim_count, 
  714. X                dim_count
  715. X                );
  716. X        else
  717. X            sprintf(sub_expr, 
  718. X                "[((x=dim_%d%s)<0?x+DIM_%d_SIZE:x)]",
  719. X                dim_count, 
  720. X                stack[mark].data.expr.addr,
  721. X                dim_count
  722. X                );
  723. X        mark--;
  724. X        size = size + strlen(sub_expr);
  725. X    }
  726. X
  727. X    /* The number of dimensions used should match those declared. */
  728. X    if (dimension_count != dim_count)
  729. X        error("Incorrect number of dimensions in cell reference",
  730. X              (char*) NULL);
  731. X    
  732. X    /* Turn the StackMark entry into a StackExpr (the array reference). */
  733. X    stack[mark].kind = StackExpr;
  734. X    stack[mark].data.expr.assignable = false;
  735. X    stack[mark].data.expr.unstructured = (field_count == 1);
  736. X    new_addr = stack[mark].data.expr.addr = mymalloc(size);
  737. X    
  738. X    /* Build the array reference. */
  739. X    dim_count = 0;
  740. X    tmp_top = mark + 1;
  741. X    strcpy(new_addr, "cells[now]");
  742. X    while (tmp_top <= top) {
  743. X        char sub_expr[MAX_STRING_LENGTH];
  744. X        long int index_value = atoi(stack[tmp_top].data.expr.addr);
  745. X
  746. X        dim_count++; 
  747. X
  748. X        if (0 == index_value)
  749. X            sprintf(sub_expr, "[dim_%d]", dim_count);
  750. X        else if (index_value > 0)
  751. X            sprintf(sub_expr, 
  752. X                "[((x=dim_%d+%s)>=DIM_%d_SIZE?x-DIM_%d_SIZE:x)]",
  753. X                dim_count, 
  754. X                stack[tmp_top].data.expr.addr,
  755. X                dim_count, 
  756. X                dim_count
  757. X                );
  758. X        else
  759. X            sprintf(sub_expr, 
  760. X                "[((x=dim_%d%s)<0?x+DIM_%d_SIZE:x)]",
  761. X                dim_count, 
  762. X                stack[tmp_top].data.expr.addr,
  763. X                dim_count
  764. X                );
  765. X
  766. X        free(stack[tmp_top].data.expr.addr);
  767. X        strcat(new_addr, sub_expr);
  768. X        tmp_top++;
  769. X    }
  770. X
  771. X    /* Pop most of the semantic stack. */
  772. X    top = mark;
  773. X}
  774. X
  775. X/* SEMANTIC ROUTINE
  776. X      EXPECTS - StackToken StackExpr
  777. X      LEAVES  - StackExpr
  778. X      ACTION  - The StackToken is used to create a field reference of
  779. X        the StackExpr.
  780. X*/
  781. void field_reference() {
  782. X    if (stack_error(2)) {
  783. X        if (stack[top-1].kind != StackError)
  784. X            free(stack[top-1].data.expr.addr);
  785. X        top--;
  786. X        stack[top].kind = StackError;
  787. X        return;
  788. X    }
  789. X    else {
  790. X        stack_entry field_entry, base_entry;
  791. X        
  792. X        field_entry = stack[top--];
  793. X        base_entry = stack[top];
  794. X
  795. X        if (!base_entry.data.expr.pre_declared &&
  796. X            base_entry.data.expr.assignable) {
  797. X            error("'%s' is not previously declared", 
  798. X                base_entry.data.expr.addr);
  799. X            stack[top].kind = StackError;
  800. X            return;
  801. X        }
  802. X
  803. X        /* Make sure this is really a field. */
  804. X        if (!intable(field_entry.data.token, FIELD))
  805. X            error("'%s' is not a known field", 
  806. X                field_entry.data.token);
  807. X
  808. X        stack[top].kind = StackExpr;
  809. X        stack[top].data.expr.assignable = base_entry.data.expr.assignable;
  810. X        stack[top].data.expr.unstructured = true;
  811. X
  812. X        if (base_entry.data.expr.assignable)
  813. X            stack[top].data.expr.field = field_entry.data.token;
  814. X        else {
  815. X            stack[top].data.expr.addr = 
  816. X                mymalloc((unsigned int)
  817. X                    (strlen(base_entry.data.expr.addr) +
  818. X                         strlen(field_entry.data.token) +
  819. X                         strlen("(.)") + 1));
  820. X            sprintf(stack[top].data.expr.addr, "(%s.%s)",
  821. X                base_entry.data.expr.addr,
  822. X                field_entry.data.token);
  823. X            free(base_entry.data.expr.addr);
  824. X            free(field_entry.data.token);
  825. X        }
  826. X    }
  827. X}
  828. X
  829. X/************************************************************************/
  830. X
  831. X/* SEMANTIC ROUTINE
  832. X      EXPECTS - StackExpr_1, StackToken, StackExpr_2
  833. X      LEAVES  - StackExpr
  834. X      ACTION  - Code for the indicated operation and operands is
  835. X        produced and replaces the 3 items on top of the
  836. X        stack.
  837. X*/
  838. void binary_op() {
  839. X    if (stack_error(3)) {
  840. X        if (stack[top].kind != StackError)
  841. X            free(stack[top].data.expr.addr);
  842. X        top -= 2;
  843. X        stack[top].kind = StackError;
  844. X        return;
  845. X    }
  846. X    else {
  847. X        stack_entry entry_1, entry_2, entry_3;
  848. X        entry_3 = stack[top--];
  849. X        entry_2 = stack[top--];
  850. X        entry_1 = stack[top];
  851. X
  852. X        /* Only fields can use (non)equality tests. */
  853. X        if (!entry_1.data.expr.unstructured && 
  854. X            !entry_3.data.expr.unstructured && 
  855. X            !strcmp(entry_2.data.token, "=") && 
  856. X            !strcmp(entry_2.data.token, "!="))
  857. X            error("Comparisons of structured cells are limited to '=' and '!='",
  858. X                (char*) NULL);
  859. X        else if (entry_1.data.expr.unstructured != 
  860. X                        entry_3.data.expr.unstructured)
  861. X            error("Value types of operation, '%s', are incompatable",
  862. X                entry_2.data.token);
  863. X
  864. X        stack[top].kind = StackExpr;
  865. X        stack[top].data.expr.assignable = false;
  866. X        stack[top].data.expr.unstructured = 
  867. X                        entry_1.data.expr.unstructured;
  868. X
  869. X        if (entry_1.data.expr.unstructured || field_count == 1) {
  870. X            stack[top].data.expr.addr = 
  871. X                mymalloc((unsigned int)
  872. X                    (strlen(entry_1.data.expr.addr) +
  873. X                         strlen(entry_2.data.token) +
  874. X                         strlen(entry_3.data.expr.addr) +
  875. X                         strlen("(  )") + 1));
  876. X            sprintf(stack[top].data.expr.addr, "(%s %s %s)",
  877. X                entry_1.data.expr.addr,
  878. X                entry_2.data.token,
  879. X                entry_3.data.expr.addr);
  880. X        }
  881. X        else {
  882. X            unsigned int size =
  883. X                    strlen(entry_1.data.expr.addr) +
  884. X                         strlen(entry_2.data.token) +
  885. X                         strlen(entry_3.data.expr.addr) +
  886. X                         strlen("neq(&(),&())") + 1;
  887. X
  888. X            if (strcmp(entry_2.data.token, "!=")) size++;
  889. X
  890. X            stack[top].data.expr.addr = mymalloc(size);
  891. X
  892. X            if (strcmp(entry_2.data.token, "!="))
  893. X                sprintf(stack[top].data.expr.addr, "neq(&(%s),&(%s))",
  894. X                    entry_1.data.expr.addr,
  895. X                    entry_2.data.token,
  896. X                    entry_3.data.expr.addr);
  897. X            else
  898. X                sprintf(stack[top].data.expr.addr, "!neq(&(%s),&(%s))",
  899. X                    entry_1.data.expr.addr,
  900. X                    entry_2.data.token,
  901. X                    entry_3.data.expr.addr);
  902. X        }
  903. X
  904. X        free(entry_1.data.expr.addr);
  905. X        free(entry_2.data.token);
  906. X        free(entry_3.data.expr.addr);
  907. X    }
  908. X}
  909. X
  910. X/* SEMANTIC ROUTINE
  911. X      EXPECTS - StackExpr, StackToken
  912. X      LEAVES  - StackExpr
  913. X      ACTION  - The stack is rearranged to look like:
  914. X           StackExpr_1, StackMark, StackToken
  915. X        and a call made to endfuncall.
  916. X*/
  917. void unary_op() {
  918. X    if (stack_error(2)) {
  919. X        if (stack[top].kind != StackError)
  920. X            free(stack[top].data.expr.addr);
  921. X        top--;
  922. X        stack[top].kind = StackError;
  923. X        return;
  924. X    }
  925. X    else {
  926. X        stack_entry entry_1, entry_2;
  927. X        entry_2 = stack[top--];
  928. X        entry_1 = stack[top];
  929. X
  930. X        /* Only fields can use unary operations. */
  931. X        if (!entry_2.data.expr.unstructured)
  932. X            error("Unary operations must operate on integer values",
  933. X                (char*) NULL);
  934. X            
  935. X        stack[top].kind = StackExpr;
  936. X        stack[top].data.expr.assignable = false;
  937. X        stack[top].data.expr.unstructured = 
  938. X                        entry_2.data.expr.unstructured;
  939. X        stack[top].data.expr.addr = 
  940. X            mymalloc((unsigned int)
  941. X                    (strlen(entry_1.data.token) +
  942. X                         strlen(entry_2.data.expr.addr) +
  943. X                         strlen("( )") + 1));
  944. X        sprintf(stack[top].data.expr.addr, "(%s %s)",
  945. X            entry_1.data.token,
  946. X            entry_2.data.expr.addr);
  947. X        free(entry_1.data.token);
  948. X        free(entry_2.data.expr.addr);
  949. X    }
  950. X}
  951. X
  952. X/************************************************************************/
  953. X
  954. X/* SUPPORT ROUTINE
  955. X      ACTION - Generates code to check that the read times are legal,
  956. X           (i.e. greater than the current time).
  957. X*/
  958. void gen_check_time() {
  959. X    print_indent();
  960. X    fprintf(file_c, "if (next_time < _time) {\n");
  961. X    indent;
  962. X    print_indent();
  963. X    fprintf(file_c, 
  964. X        "fprintf(stderr, \"%%s; time %%lu, entry %%lu: Must go forwards in time.\\n\", command, _time, entry);\n");
  965. X    print_indent();
  966. X    fprintf(file_c, "exit(1);\n");
  967. X    undent;
  968. X    print_indent();
  969. X    fprintf(file_c, "}\n");
  970. X}
  971. X
  972. X/* SUPPORT ROUTINE
  973. X      ACTION - Generates code to give a read error message and quit, when
  974. X           a index/value should have been read but wasn't.
  975. X*/
  976. void gen_read_error() {
  977. X    indent;
  978. X    print_indent();
  979. X    fprintf(file_c, "fprintf(stderr, \"%%s; time %%lu, entry %%lu: read error\\n\", command, _time, entry);\n");
  980. X    print_indent();
  981. X    fprintf(file_c, "exit(1);\n");
  982. X    undent;
  983. X}
  984. X
  985. X/* SUPPORT ROUTINE
  986. X      ACTION - Generates code to give a read error message and quit, when
  987. X           the value read in was incorrect.
  988. X*/
  989. void gen_read_value_error(position) int position; {
  990. X    indent;
  991. X    print_indent();
  992. X    if (position <= dimension_count)
  993. X        fprintf(file_c, "fprintf(stderr, \"%%s; time %%lu, entry %%lu: value of index %d is out of range\\n\", command, _time, entry);\n",
  994. X            position);
  995. X    else
  996. X        fprintf(file_c, "fprintf(stderr, \"%%s; time %%lu, entry %%lu: cell value is out of range\\n\", command, _time, entry);\n");
  997. X    print_indent();
  998. X    fprintf(file_c, "exit(1);\n");
  999. X    undent;
  1000. X}
  1001. X
  1002. X/* SUPPORT ROUTINE
  1003. X      ACTION - Generates code to read the data from stdandard input
  1004. X           when the time has reached the time associated with
  1005. X           the next set of cell-value combinations to read.
  1006. X*/
  1007. void gen_read_loop() {
  1008. X    int i;
  1009. X
  1010. X    /* As long as the time of the automata is the time of the
  1011. X       data entries, keep looping to read all of the cell-value
  1012. X       data.
  1013. X    */
  1014. X    print_indent();
  1015. X    fprintf(file_c, "entry = 0;\n");
  1016. X    print_indent();
  1017. X    fprintf(file_c, "while (_time == next_time) {\n");
  1018. X    indent;
  1019. X
  1020. X    /* Generate code to read in the dimension values.  Because the
  1021. X       dimension variables are held in registers, the actually values
  1022. X       are read into temporary locations and the values then assigned
  1023. X       to the dimension variables.
  1024. X    */
  1025. X
  1026. X    /* Declare temporaries. */
  1027. X    for (i = 1; i <= dimension_count; i++) {
  1028. X        print_indent();
  1029. X        fprintf(file_c, "int temp_dim_%d;\n", i);
  1030. X    }
  1031. X
  1032. X    /* Read dimension values into temporaries. */
  1033. X    print_indent();
  1034. X    fprintf(file_c, "int scan_count;\n");
  1035. X    print_indent();
  1036. X    fprintf(file_c, "int count = scanf(\" [ %%d");
  1037. X    for (i = 1; i < dimension_count; i++)
  1038. X        fprintf(file_c, " , %%d");
  1039. X    fprintf(file_c, " \"");
  1040. X    for (i = 1; i <= dimension_count; i++)
  1041. X        fprintf(file_c, ", &temp_dim_%d", i);
  1042. X    fprintf(file_c, ");\n");
  1043. X
  1044. X    /* Assign temporaries to the dimension variables. */
  1045. X    for (i = 1; i <= dimension_count; i++) {
  1046. X        print_indent();
  1047. X        fprintf(file_c, "dim_%d = temp_dim_%d;\n", i, i);
  1048. X    }
  1049. X
  1050. X
  1051. X    /* Update the input entry count, for the printing of error messgaes. */
  1052. X    print_indent();
  1053. X    fprintf(file_c, "entry++;\n");
  1054. X
  1055. X    /* If no dimensions values read, then maybe this is a time. */
  1056. X    print_indent();
  1057. X    fprintf(file_c, "if (0 == count || EOF == count) {\n");
  1058. X    indent;
  1059. X    print_indent();
  1060. X    fprintf(file_c, "count = scanf(\" %%ld \", &next_time);\n");
  1061. X
  1062. X    /* If a time was read, make sure it was a legal time. */
  1063. X    print_indent();
  1064. X    fprintf(file_c, "if (1 == count) {\n");
  1065. X    indent;
  1066. X    gen_check_time();
  1067. X    undent;
  1068. X    print_indent();
  1069. X    fprintf(file_c, "}\n");
  1070. X
  1071. X    /* If this is the end of the input, then set next_time so that
  1072. X       no attempt is made to read from the input again. 
  1073. X    */
  1074. X    print_indent();
  1075. X    fprintf(file_c, "else if (0 == count || EOF == count) {\n");
  1076. X    indent;
  1077. X    /* Make sure that only spaces, tabs and newlines are left; otherwise
  1078. X       indicate an error.
  1079. X    */
  1080. X    print_indent();
  1081. X    fprintf(file_c, "int c = getchar();\n");
  1082. X    print_indent();
  1083. X    fprintf(file_c, "while (c == '\\n' || c == '\\t' || c == ' ') c = getchar();\n");
  1084. X    print_indent();
  1085. X    fprintf(file_c, "if (c != EOF) {\n");
  1086. X    gen_read_error();
  1087. X    print_indent();
  1088. X    fprintf(file_c, "}\n");
  1089. X
  1090. X    print_indent();
  1091. X    fprintf(file_c, "next_time = -1;\n");
  1092. X
  1093. X    undent;
  1094. X    print_indent();
  1095. X    fprintf(file_c, "}\n");
  1096. X    print_indent();
  1097. X    fprintf(file_c, "break;\n");
  1098. X
  1099. X    undent;
  1100. X    print_indent();
  1101. X    fprintf(file_c, "}\n");
  1102. X
  1103. X    /* Generate code to check and see if only some of the cell
  1104. X       indices were read in.
  1105. X    */
  1106. X    print_indent();
  1107. X    fprintf(file_c, "else if (count != %d) {\n", dimension_count);
  1108. X    indent;
  1109. X    print_indent();
  1110. X    fprintf(file_c, "fprintf(stderr, \"%%s; time %%lu, entry %%lu: Incorrect number of dimensions referenced\\n\", command, _time, entry);\n");
  1111. X    print_indent();
  1112. X    fprintf(file_c, "exit(1);\n");
  1113. X    undent;
  1114. X    print_indent();
  1115. X    fprintf(file_c, "}\n");
  1116. X
  1117. X    /* Generate code to check the legality of the cell indices. */
  1118. X    for (i = 1; i <= dimension_count; i++) {
  1119. X        print_indent();
  1120. X        fprintf(file_c, "if (DIM_%d_SIZE-1 < dim_%d || dim_%d < 0) {\n",
  1121. X            i, i, i, i);
  1122. X        gen_read_value_error(i);
  1123. X        print_indent();
  1124. X        fprintf(file_c, "}\n");
  1125. X    }
  1126. X
  1127. X    print_indent();
  1128. X    fprintf(file_c, "scanf(\" ] = \");\n");
  1129. X
  1130. X    /* Find the location of the described cell. */
  1131. X    print_indent();
  1132. X    fprintf(file_c, "_cell = &cells[now]");
  1133. X    for (i = 1; i <= dimension_count; i++)
  1134. X        fprintf(file_c, "[dim_%d]", i, i);
  1135. X    fprintf(file_c, ";\n");
  1136. X
  1137. X    /* Write code to print the cell location just read in. */
  1138. X    print_indent();
  1139. X    fprintf(file_c, 
  1140. X        "if (_time == next_report_time || _time == next_read_time)\n");
  1141. X    indent;
  1142. X    print_indent();
  1143. X#if COMBINED
  1144. X    fprintf(file_c, "if (output) ");
  1145. X#endif
  1146. X    fprintf(file_c, "printf(\"[%%d");
  1147. X    for (i = 2; i <= dimension_count; i++)
  1148. X        fprintf(file_c, ", %%d");
  1149. X    fprintf(file_c, "] = \"");
  1150. X    for (i = 1; i <= dimension_count; i++)
  1151. X        fprintf(file_c, ", dim_%d", i);
  1152. X    fprintf(file_c, ");\n", i);
  1153. X    undent;
  1154. X
  1155. X    /* Read, check and write out all of the fields. */
  1156. X    print_indent();
  1157. X    fprintf(file_c, "count = 0;\n");
  1158. X    for (i = 0; i < field_count; i++) {
  1159. X
  1160. X        /* Read and count the values. */
  1161. X        if (i > 0) {
  1162. X            print_indent();
  1163. X            fprintf(file_c, "scan_count = scanf(\" , %%d\", &read_value);\n");
  1164. X        }
  1165. X        else {
  1166. X            print_indent();
  1167. X            fprintf(file_c, "scan_count = scanf(\" %%d\", &read_value);\n");
  1168. X        }
  1169. X
  1170. X        /* Only do stuff with this value, if a value was read in. */
  1171. X        print_indent();
  1172. X        fprintf(file_c, "if (scan_count > 0) {\n");
  1173. X        indent;
  1174. X        print_indent();
  1175. X        fprintf(file_c, "count += scan_count;\n");
  1176. X
  1177. X        /* Make sure read values fall within the supported range. */
  1178. X        print_indent();
  1179. X        fprintf(file_c, "if (%d < read_value || read_value < %d) {\n",
  1180. X            MAX_RANGE_UB, MAX_RANGE_LB);
  1181. X        gen_read_value_error(dimension_count + 1);
  1182. X        print_indent();
  1183. X        fprintf(file_c, "}\n");
  1184. X
  1185. X        /* Assign read cell value to the cell.  Values are assumed
  1186. X           to be represented by char.
  1187. X        */
  1188. X        print_indent();
  1189. X        if (field_count > 1)
  1190. X            fprintf(file_c, "_cell->%s = read_value;\n", 
  1191. X                field_list[i].name);
  1192. X        else
  1193. X            fprintf(file_c, "*_cell = read_value;\n");
  1194. X
  1195. X        /* Write out the value just read in. */
  1196. X        print_indent();
  1197. X        fprintf(file_c, 
  1198. X            "if (_time == next_report_time || _time == next_read_time)\n");
  1199. X        indent;
  1200. X        print_indent();
  1201. X#if COMBINED
  1202. X        fprintf(file_c, "if (output) ");
  1203. X#endif
  1204. X        if (i > 0)
  1205. X            fprintf(file_c, "printf(\", %%d\", read_value);\n");
  1206. X        else
  1207. X            fprintf(file_c, "printf(\"%%d\", read_value);\n");
  1208. X        undent;
  1209. X
  1210. X        undent;
  1211. X        print_indent();
  1212. X        fprintf(file_c, "}\n");
  1213. X
  1214. X        /* If no value was read, then default value is zero. */
  1215. X        print_indent();
  1216. X        fprintf(file_c, 
  1217. X            "else if (_time == next_report_time || _time == next_read_time) {\n");
  1218. X        indent;
  1219. X#if COMBINED
  1220. X        print_indent();
  1221. X        fprintf(file_c, "if (output) {\n");
  1222. X        indent;
  1223. X#endif
  1224. X        if (i > 0) {
  1225. X            print_indent();
  1226. X            fprintf(file_c, "printf(\", \");\n");
  1227. X        }
  1228. X        print_indent();
  1229. X        if (field_count > 1)
  1230. X            fprintf(file_c, "printf(\"%%d\", _cell->%s);\n", 
  1231. X                field_list[i].name);
  1232. X        else
  1233. X            fprintf(file_c, "printf(\"%%d\", *_cell);\n");
  1234. X#if COMBINED
  1235. X        undent;
  1236. X        print_indent();
  1237. X        fprintf(file_c, "}\n");
  1238. X#endif
  1239. X        undent;
  1240. X        print_indent();
  1241. X        fprintf(file_c, "}\n");
  1242. X    }
  1243. X    print_indent();
  1244. X#if COMBINED
  1245. X    fprintf(file_c, "if (output) ");
  1246. X#endif
  1247. X    fprintf(file_c, "printf(\"\\n\");\n");
  1248. X
  1249. X    /* Check for too few cell values given. */
  1250. X    print_indent();
  1251. X    fprintf(file_c, "if (count < 1) {\n"); 
  1252. X    indent;
  1253. X    print_indent();
  1254. X    fprintf(file_c, "fprintf(stderr, \"%%s; time %%lu, entry %%lu: Too few cell value(s)\\n\", command, _time, entry);\n");
  1255. X    print_indent();
  1256. X    fprintf(file_c, "exit(1);\n");
  1257. X    undent;
  1258. X    print_indent();
  1259. X    fprintf(file_c, "}\n");
  1260. X
  1261. X    /* Check for too many cell values given. */
  1262. X    print_indent();
  1263. X    fprintf(file_c, "if (count > %d) {\n", field_count); 
  1264. X    indent;
  1265. X    print_indent();
  1266. X    fprintf(file_c, "fprintf(stderr, \"%%s; time %%lu, entry %%lu: Too many cell value(s)\\n\", command, _time, entry);\n");
  1267. X    print_indent();
  1268. X    fprintf(file_c, "exit(1);\n");
  1269. X    undent;
  1270. X    print_indent();
  1271. X    fprintf(file_c, "}\n");
  1272. X
  1273. X#if COMBINED
  1274. X    print_indent();
  1275. X    fprintf(file_c, "if (!output) {\n");
  1276. X    indent;
  1277. X
  1278. X    if (field_count > 1) {
  1279. X        print_indent();
  1280. X        fprintf(file_c, "%s field_value;\n", FIELD_TYPE);
  1281. X        print_indent();
  1282. X        fprintf(file_c, "switch (field) {\n");
  1283. X        indent;
  1284. X        for (i = 0; i < field_count; i++) {
  1285. X            print_indent();
  1286. X            fprintf(file_c, "case %d: field_value = _cell->%s;\n", 
  1287. X                i, field_list[i].name);
  1288. X        }
  1289. X        undent;
  1290. X        print_indent();
  1291. X        fprintf(file_c, "}\n");
  1292. X    }
  1293. X
  1294. X    print_indent();
  1295. X    fprintf(file_c, "set_cell_entry(dim_1, ");
  1296. X    if (dimension_count > 1)
  1297. X        fprintf(file_c, " dim_2, ");
  1298. X    else
  1299. X        fprintf(file_c, " 0, ");    /* Could be one dimensional. */
  1300. X    if (field_count > 1)
  1301. X        fprintf(file_c, "field_value);\n");
  1302. X    else
  1303. X        fprintf(file_c, "*_cell);\n");
  1304. X
  1305. X    undent;
  1306. X    print_indent();
  1307. X    fprintf(file_c, "}\n");
  1308. X#endif
  1309. X    
  1310. X    /* Close of the loop for reading data. */
  1311. X    undent;
  1312. X    print_indent();
  1313. X    fprintf(file_c, "}\n");
  1314. X}
  1315. X
  1316. X/* SUPPORT ROUTINE
  1317. X      ACTION - Generates code to perform the looping over the cellular
  1318. X           universe for each time step, starting at 0.
  1319. X*/
  1320. void gen_begin_time_loop() {
  1321. X    print_indent();
  1322. X#if COMBINED
  1323. X    /* Begin a possibly infinite "time" loop. */
  1324. X    fprintf(file_c, "do {\n");
  1325. X#else
  1326. X    /* Begin an infinite "time" loop. */
  1327. X    fprintf(file_c, "while (1) {\n");
  1328. X#endif
  1329. X    indent;
  1330. X
  1331. X    /* Generate code to write out the time. */
  1332. X    print_indent();
  1333. X    fprintf(file_c, "if (_time == next_report_time || _time == next_read_time)\n");
  1334. X    indent;
  1335. X    print_indent();
  1336. X#if COMBINED
  1337. X    fprintf(file_c, "if (output) ");
  1338. X#endif
  1339. X    fprintf(file_c, "printf(\"%%lu\\n\", _time);\n");
  1340. X    undent;
  1341. X
  1342. X    gen_read_loop();
  1343. X}
  1344. X
  1345. X/* SUPPORT ROUTINE
  1346. X      ACTION - Generates code to perform the looping over the cellular
  1347. X           universe for each time step, starting at 0.
  1348. X*/
  1349. void gen_end_time_loop() {
  1350. X    /* Go to the next time step. */
  1351. X    print_indent();
  1352. X    fprintf(file_c, "_time++;\n");
  1353. X
  1354. X    /* Generate code to exchange the values for "next" and "now". */
  1355. X    print_indent();
  1356. X    fprintf(file_c, "next = !next;\n");
  1357. X    print_indent();
  1358. X    fprintf(file_c, "now = !now;\n");
  1359. X
  1360. X    /* Close off the infinite "time" loop. */
  1361. X    undent;
  1362. X    print_indent();
  1363. X#if COMBINED
  1364. X    fprintf(file_c, "} while (output);\n");
  1365. X#else
  1366. X    fprintf(file_c, "}\n");
  1367. X#endif
  1368. X}
  1369. X
  1370. X/* SUPPORT ROUTINE
  1371. X      ACTION - Generates code to initialize the cells of the cellular
  1372. X           universe to 0.
  1373. X*/
  1374. void gen_cell_init() {
  1375. X    int i, f;
  1376. X
  1377. X    /* Write code to initialize the cellular universe to contain 0's. */
  1378. X    for (i = 1; i <= dimension_count; i++) {
  1379. X        print_indent();
  1380. X        fprintf(file_c, "for(dim_%d=0;dim_%d<DIM_%d_SIZE;dim_%d++)\n",
  1381. X            i, i, i, i, i);
  1382. X    }
  1383. X    print_indent();
  1384. X    fprintf(file_c, "{\n");
  1385. X    indent;
  1386. X    
  1387. X    /* The following code assumes that fields are stored as
  1388. X       unsigned char.
  1389. X    */
  1390. X    for (f = 0; f < field_count; f++) {
  1391. X        print_indent();
  1392. X        fprintf(file_c, "*(char*)((unsigned int)&cells[0]");
  1393. X        for (i = 1; i <= dimension_count; i++)
  1394. X            fprintf(file_c, "[dim_%d]", i, i);
  1395. X        fprintf(file_c, "+%d) = 0;\n", f);
  1396. X        print_indent();
  1397. X        fprintf(file_c, "*(char*)((unsigned int)&cells[1]");
  1398. X        for (i = 1; i <= dimension_count; i++)
  1399. X            fprintf(file_c, "[dim_%d]", i, i);
  1400. X        fprintf(file_c, "+%d) = 0;\n", f);
  1401. X    }
  1402. X
  1403. X    undent;
  1404. X    print_indent();
  1405. X    fprintf(file_c, "}\n");
  1406. X}
  1407. X
  1408. X/* SUPPORT ROUTINE
  1409. X      ACTION - Generates code for the variable declarations in the main 
  1410. X           body of the program.
  1411. X*/
  1412. void gen_declarations() {
  1413. X    int i;
  1414. X
  1415. X    /* Declare (locally) the dimension variables. */
  1416. X    for (i = 1; i <= dimension_count; i++) {
  1417. X        print_indent();
  1418. X        fprintf(file_c, "register int dim_%d;\n", i);
  1419. X    }
  1420. X
  1421. X    /* The location of the current cell within the universe is
  1422. X       always contained in the variable "cell".
  1423. X    */
  1424. X    print_indent();
  1425. X    fprintf(file_c, "register cell_type *_cell = NULL;\n");
  1426. X
  1427. X    /* For counting lines of the input data to the cellular atuomata. */
  1428. X    print_indent();
  1429. X    fprintf(file_c, "unsigned long int entry = 1;\n");
  1430. X
  1431. X    /* Temporary variable used for reading in cell field values. */
  1432. X    print_indent();
  1433. X    fprintf(file_c, "int read_value;\n");
  1434. X}
  1435. X
  1436. X/* SUPPORT ROUTINE
  1437. X      ACTION - Generates code for the initialization in the main 
  1438. X           body of the program.
  1439. X*/
  1440. void gen_initialize() {
  1441. X    int i;
  1442. X
  1443. X    /* Declare (locally) the dimension variables. */
  1444. X    for (i = 1; i <= dimension_count; i++) {
  1445. X        print_indent();
  1446. X        fprintf(file_c, "register int dim_%d;\n", i);
  1447. X    }
  1448. X
  1449. X    /* If no data is given, don't try to read from it ever again. */
  1450. X    print_indent();
  1451. X    fprintf(file_c, "int count = scanf(\" %%ld \", &next_time);\n");
  1452. X    print_indent();
  1453. X    fprintf(file_c, "if (0 == count || EOF == count) {\n");
  1454. X    indent;
  1455. X    /* Make sure that only spaces, tabs and newlines are left; otherwise
  1456. X       indicate an error.
  1457. X    */
  1458. X    print_indent();
  1459. X    fprintf(file_c, "int c = getchar();\n");
  1460. X    print_indent();
  1461. X    fprintf(file_c, "while (c == '\\n' || c == '\\t' || c == ' ') c = getchar();\n");
  1462. X
  1463. X    print_indent();
  1464. X    fprintf(file_c, "if (c != EOF) {\n");
  1465. X    indent;
  1466. X    print_indent();
  1467. X    fprintf(file_c, "fprintf(stderr, \"%%s: read error at beginning of input file\\n\", command);\n");
  1468. X    print_indent();
  1469. X    fprintf(file_c, "exit(1);\n");
  1470. X    undent;
  1471. X    print_indent();
  1472. X    fprintf(file_c, "}\n");
  1473. X
  1474. X    print_indent();
  1475. X    fprintf(file_c, "next_time = -1;\n");
  1476. X    undent;
  1477. X    print_indent();
  1478. X    fprintf(file_c, "} else\n");
  1479. X
  1480. X    /* Make sure that the time read in is okay. */
  1481. X    print_indent();
  1482. X    fprintf(file_c, "if (next_time < _time) {\n");
  1483. X    indent;
  1484. X    print_indent();
  1485. X    fprintf(file_c, 
  1486. X        "fprintf(stderr, \"%%s: First time in input file must be >= 0\\n\", command);\n");
  1487. X    print_indent();
  1488. X    fprintf(file_c, "exit(1);\n");
  1489. X    undent;
  1490. X    print_indent();
  1491. X    fprintf(file_c, "}\n");
  1492. X
  1493. X    gen_cell_init();
  1494. X}
  1495. X
  1496. X/* SUPPORT ROUTINE
  1497. X      ACTION - Generates code to read the command line arguments.  These
  1498. X           consist of a time file and a set of upper bounds on each of
  1499. X           the dimensions (appearing in order).  The time file, if 
  1500. X           given, is opened otherwise the time reporting step is set
  1501. X           to 1.  The upper bounds on the dimensions are set.
  1502. X*/
  1503. void gen_get_command_line() {
  1504. X
  1505. X    /* Get and set the upper bounds on the dimensions. */
  1506. X    print_indent();
  1507. X    fprintf(file_c, "if (argc != %d) {\n", 2);
  1508. X    indent;
  1509. X    print_indent();
  1510. X    fprintf(file_c, "fprintf(stderr, \"%%s: Incorrect number of command line arguments\\n\", argv[0]);\n");
  1511. X    print_indent();
  1512. X    fprintf(file_c, "exit(1);\n");
  1513. X    undent;
  1514. X    print_indent();
  1515. X    fprintf(file_c, "}\n");
  1516. X
  1517. X    /* Open the time file which specifies report times, if given. */
  1518. X    print_indent();
  1519. X    fprintf(file_c, "if (strcmp(argv[1], \"-\") != 0) {\n");
  1520. X    indent;
  1521. X    print_indent();
  1522. X    fprintf(file_c, "time_file = fopen(argv[1], \"r\");\n");
  1523. X    print_indent();
  1524. X    fprintf(file_c, "next_read_time = 0;\n");
  1525. X    print_indent();
  1526. X    fprintf(file_c, "get_report_time(time_file, &report_time_step, &next_read_time);\n");
  1527. X    undent;
  1528. X    print_indent();
  1529. X    fprintf(file_c, "}\n");
  1530. X}
  1531. X
  1532. X/* SUPPORT ROUTINE
  1533. X      ACTION - Generates code to read the report time file entries.
  1534. X*/
  1535. void gen_get_report_time() {
  1536. X    print_indent();
  1537. X    fprintf(file_c, "void get_report_time(file, time_step, read_time)\n");
  1538. X    print_indent();
  1539. X    fprintf(file_c, "FILE *file; unsigned long int *time_step; long int *read_time; {\n");
  1540. X    indent;
  1541. X
  1542. X    /* Get the next entry from the file. */
  1543. X    print_indent();
  1544. X    fprintf(file_c, "int c;\n");
  1545. X    print_indent();
  1546. X    fprintf(file_c, "*time_step = 0;\n");
  1547. X    print_indent();
  1548. X    fprintf(file_c, "while (*read_time >= 0)\n");
  1549. X    indent;
  1550. X    print_indent();
  1551. X    fprintf(file_c, "if (1 == fscanf(file, \" +%%u\", time_step));\n");
  1552. X    print_indent();
  1553. X    fprintf(file_c, "else if (1 == fscanf(file, \" %%ld\", read_time)) break;\n");
  1554. X    print_indent();
  1555. X    fprintf(file_c, "else if ((c = getc(file)) == '!') exit(0);\n");
  1556. X    print_indent();
  1557. X    fprintf(file_c, "else if (c == ' ' || c == '\\n');\n");
  1558. X    print_indent();
  1559. X    fprintf(file_c, "else *read_time = -1;\n");
  1560. X    undent;
  1561. X
  1562. X    undent;
  1563. X    print_indent();
  1564. X    fprintf(file_c, "}\n\n");
  1565. X}
  1566. X
  1567. X/* SUPPORT ROUTINE
  1568. X      ACTION - Generates code to read the report time file entries.
  1569. X*/
  1570. void gen_init_cells() {
  1571. X    print_indent();
  1572. X    fprintf(file_c, "void init_cells() {\n");
  1573. X    indent;
  1574. X
  1575. X    gen_initialize();
  1576. X
  1577. X    undent;
  1578. X    print_indent();
  1579. X    fprintf(file_c, "}\n\n");
  1580. X}
  1581. X
  1582. X/************************************************************************/
  1583. X
  1584. X/* SEMANTIC ROUTINE
  1585. X      EXPECTS - n/a
  1586. X      LEAVES  - n/a
  1587. X      ACTION  - Writes code to perform all the actions on the cellular 
  1588. X        automata and its rules.  Including, but not limited to,
  1589. X        variable declarations, I/O, cell initialization.
  1590. X*/
  1591. void begin_rules() {
  1592. X    int i;
  1593. X
  1594. X    decl_time_and_cell();
  1595. X
  1596. X    /* Define the function for reading the report time file entries. */
  1597. X    gen_get_report_time();
  1598. X
  1599. X    /* Declare the cell universe. */
  1600. X    print_indent();
  1601. X    fprintf(file_c, "static cell_type cells[2]");
  1602. X    for (i = 0; i < dimension_count; i++)
  1603. X        fprintf(file_c, "[%d]", MAX_DIM_SIZE);
  1604. X    fprintf(file_c, ";\n\n");
  1605. X
  1606. X    /* Define the function for initializing the cell universe. */
  1607. X    gen_init_cells();
  1608. X
  1609. X    /* Start the "main" body of the program. */
  1610. X#if COMBINED
  1611. X    fprintf(file_c, "int cellang_main (output, field) int output, field; {\n");
  1612. X#else
  1613. X    fprintf(file_c, "int main (argc, argv) int argc; char *argv[]; {\n");
  1614. X#endif
  1615. X    indent;
  1616. X
  1617. X    gen_declarations();
  1618. X
  1619. X#if !COMBINED
  1620. X    gen_get_command_line();
  1621. X
  1622. X    print_indent();
  1623. X    fprintf(file_c, "command = argv[0];\n");
  1624. X
  1625. X    print_indent();
  1626. X    fprintf(file_c, "init_cells();\n");
  1627. X#endif
  1628. X
  1629. X    gen_begin_time_loop();
  1630. X
  1631. X    /* Generate code to step through the ranges of all indices. */
  1632. X    for (i = 1; i <= dimension_count; i++) {
  1633. X        print_indent();
  1634. X        fprintf(file_c, "for(dim_%d=0;dim_%d<DIM_%d_SIZE;dim_%d++)\n",
  1635. X            i, i, i, i, i);
  1636. X    }
  1637. X
  1638. X    /* Begin statements of for loop that range over dimensional ranges. */
  1639. X    print_indent();
  1640. X    fprintf(file_c, "{\n");
  1641. X    indent;
  1642. X
  1643. X    /* Generate code to read in the variables include file. */
  1644. X    fprintf(file_c, "#include \".cellang.h\"\n");
  1645. X
  1646. X    /* Declare temporary used for computing indices. */
  1647. X    print_indent();
  1648. X    fprintf(file_c, "register int x;\n");
  1649. X
  1650. X    /* Declare the variable that is the current "now" cell. */
  1651. X    print_indent();
  1652. X    fprintf(file_c, "cell_type now_cell;\n");
  1653. X
  1654. X    /* Generate code to set the location of the current "next" cell. */
  1655. X    print_indent();
  1656. X    fprintf(file_c, "_cell = &cells[next]");
  1657. X    for (i = 1; i <= dimension_count; i++)
  1658. X        fprintf(file_c, "[dim_%d]", i);
  1659. X    fprintf(file_c, ";\n");
  1660. X
  1661. X    /* Generate code to set the current values of "_cell" and "now_cell". */
  1662. X    print_indent();
  1663. X    fprintf(file_c, "assign_cell(&now_cell, &(cells[now]");
  1664. X    for (i = 1; i <= dimension_count; i++)
  1665. X        fprintf(file_c, "[dim_%d]", i);
  1666. X    fprintf(file_c, "));\n");
  1667. X    
  1668. X    print_indent();
  1669. X    fprintf(file_c, "assign_cell(_cell, &now_cell);\n");
  1670. X}
  1671. X
  1672. X/* SEMANTIC ROUTINE
  1673. X      EXPECTS - n/a
  1674. X      LEAVES  - n/a
  1675. X      ACTION  - Writes code to end the grouping of cellular automata rules.
  1676. X*/
  1677. void end_rules() {
  1678. X    int i;
  1679. X
  1680. X    /* Generate code to "write out" the location and value of the "next"
  1681. X       cell value if it is different from the "now" value.
  1682. X    */
  1683. X    print_indent();
  1684. X    fprintf(file_c, "if ((neq(_cell, &now_cell) && 1 == report_time_step) || (report_time_step > 1 && (_time == next_report_time || _time == next_read_time))) {\n");
  1685. X    indent;
  1686. X#if COMBINED
  1687. X    print_indent();
  1688. X    fprintf(file_c, "if (!output) {\n");
  1689. X    indent;
  1690. X
  1691. X    if (field_count > 1) {
  1692. X        print_indent();
  1693. X        fprintf(file_c, "%s field_value;\n", FIELD_TYPE);
  1694. X        print_indent();
  1695. X        fprintf(file_c, "switch (field) {\n");
  1696. X        indent;
  1697. X        for (i = 0; i < field_count; i++) {
  1698. X            print_indent();
  1699. X            fprintf(file_c, "case %d: field_value = _cell->%s;\n", 
  1700. X                i, field_list[i].name);
  1701. X        }
  1702. X        undent;
  1703. X        print_indent();
  1704. X        fprintf(file_c, "}\n");
  1705. X    }
  1706. X
  1707. X    print_indent();
  1708. X    fprintf(file_c, "set_cell_entry(dim_1, ");
  1709. X    if (dimension_count > 1)
  1710. X        fprintf(file_c, " dim_2, ");
  1711. X    else
  1712. X        fprintf(file_c, " 0, ");    /* Could be one dimensional. */
  1713. X    if (field_count > 1)
  1714. X        fprintf(file_c, "field_value);\n");
  1715. X    else
  1716. X        fprintf(file_c, "*_cell);\n");
  1717. X
  1718. X    undent;
  1719. X    print_indent();
  1720. X    fprintf(file_c, "} else {\n");
  1721. X    indent;
  1722. X#endif
  1723. X    print_indent();
  1724. X    fprintf(file_c, "printf(\"[%%d");
  1725. X    for (i = 2; i <= dimension_count; i++)
  1726. X        fprintf(file_c, ", %%d");
  1727. X    fprintf(file_c, "] = %%d");
  1728. X
  1729. X    for (i = 2; i <= field_count; i++)
  1730. X        fprintf(file_c, ", %%d");
  1731. X    fprintf(file_c, "\\n\"");
  1732. X
  1733. X    for (i = 1; i <= dimension_count; i++)
  1734. X        fprintf(file_c, ", dim_%d", i, i);
  1735. X
  1736. X    if (field_count > 1)
  1737. X        for (i = 0; i < field_count; i++)
  1738. X            fprintf(file_c, ", _cell->%s", field_list[i].name);
  1739. X    else
  1740. X        fprintf(file_c, ", *_cell");
  1741. X    fprintf(file_c, ");\n");
  1742. X
  1743. X    undent;
  1744. X    print_indent();
  1745. X    fprintf(file_c, "}\n");
  1746. X
  1747. X#if COMBINED
  1748. X    undent;
  1749. X    print_indent();
  1750. X    fprintf(file_c, "}\n");
  1751. X#endif
  1752. X
  1753. X    /* Close off for loops that range over dimensional ranges. */
  1754. X    undent;
  1755. X    print_indent();
  1756. X    fprintf(file_c, "}\n");
  1757. X
  1758. X    /* Update the time variables which determine when cell values
  1759. X       should be reported.
  1760. X    */
  1761. X    print_indent();
  1762. X    fprintf(file_c, "if (_time == next_read_time)\n");
  1763. X    indent;
  1764. X    print_indent();
  1765. X    fprintf(file_c, "get_report_time(time_file, &report_time_step, &next_read_time);\n");
  1766. X    undent;
  1767. X    print_indent();
  1768. X    fprintf(file_c, "if (report_time_step > 0 && _time >= next_report_time)\n");
  1769. X    indent;
  1770. X    print_indent();
  1771. X    fprintf(file_c, "next_report_time = _time + report_time_step;\n");
  1772. X    undent;
  1773. X
  1774. X    gen_end_time_loop();
  1775. X
  1776. X    /* Close off the "main" body. */
  1777. X    undent;
  1778. X    fprintf(file_c, "}\n");
  1779. X}
  1780. X
  1781. X/************************************************************************/
  1782. X
  1783. X/* SEMANTIC ROUTINE
  1784. X      EXPECTS - n/a
  1785. X      LEAVES  - n/a
  1786. X      ACTION  - Places the forward declarations for predefined symbols 
  1787. X                into the symbol table.  This semantic routine is called 
  1788. X        from main as opposed to being called from the grammar.
  1789. X*/
  1790. void start_up() {
  1791. X    int i;
  1792. X
  1793. X    /* Open the C files. */
  1794. X    file_h = fopen(".cellang.h", "w");
  1795. X    file_c = fopen(".cellang.c", "w");
  1796. X
  1797. X    /* Initialize the symbol table. */
  1798. X    initsymboltable();
  1799. X
  1800. X    /* Generate code to read in the standard include file(s). */
  1801. X    fprintf(file_c, "#include<stdio.h>\n");
  1802. X    fprintf(file_c, "#include<stdlib.h>\n");
  1803. X    fprintf(file_c, "#include<string.h>\n\n");
  1804. X
  1805. X#if COMBINED
  1806. X    /* Generate the external reference to use to cellviewer. */
  1807. X    fprintf(file_c, "extern set_cell_entry();\n\n");
  1808. X#endif
  1809. X
  1810. X    /* The declarations for now, next and time_file are given outside
  1811. X       the body of functions so that when the software is made such
  1812. X       the the viewer is COMBINED with the executable of a Cellang
  1813. X       program, these variables are visible and/or get initialized
  1814. X       only once.
  1815. X    */
  1816. X
  1817. X    /* command should be extern if COMBINED since it will be set
  1818. X       by the viewer software, otherwise it should be static.
  1819. X    */
  1820. X    print_indent();
  1821. X#if COMBINED
  1822. X    fprintf(file_c, "extern char *command;\n");
  1823. X#else
  1824. X    fprintf(file_c, "static char *command = NULL;\n");
  1825. X#endif
  1826. X
  1827. X    /* Write code to initialize the variable used for reading
  1828. X       the input to the cellular program.
  1829. X    */
  1830. X    print_indent();
  1831. X    fprintf(file_c, "static long int next_time;\n");
  1832. X
  1833. X    /* _time should NOT be static, since if COMBINED it will be used
  1834. X       by the viewer software.
  1835. X    */
  1836. X    print_indent();
  1837. X    fprintf(file_c, "unsigned long int _time = 0;\n");
  1838. X
  1839. X    /* Declare the time variables that determine when reports of 
  1840. X       cell values should be made. 
  1841. X    */
  1842. X    print_indent();
  1843. X    fprintf(file_c, "static unsigned long int report_time_step = 1;\n");
  1844. X    print_indent();
  1845. X    fprintf(file_c, "static unsigned long int next_report_time = 0;\n");
  1846. X    print_indent();
  1847. X    fprintf(file_c, "static long int next_read_time = -1;\n");
  1848. X
  1849. X    /* The first dimension of the cellular universe is used to
  1850. X       distinguish between current (now) cell values and those
  1851. X       values being computer for the next generation (next).
  1852. X       The two variables are also declared here.
  1853. X    */
  1854. X    print_indent();
  1855. X    fprintf(file_c, "static int now = 0;\n");
  1856. X    print_indent();
  1857. X    fprintf(file_c, "static int next = 1;\n\n");
  1858. X
  1859. X    /* time_file should NOT be static, since if COMBINED it will be used
  1860. X       by the viewer software.
  1861. X    */
  1862. X    print_indent();
  1863. X    fprintf(file_c, "FILE *time_file = NULL;\n\n");
  1864. X
  1865. X    for (i = 1; i <= MAX_SUPPORTED_DIMENSIONS; i++)
  1866. X        fprintf(file_c, "#define DIM_%d_SIZE  %d\n", i, MAX_DIM_SIZE);
  1867. X}
  1868. X
  1869. X
  1870. X/* SEMANTIC ROUTINE
  1871. X      EXPECTS - n/a
  1872. X      LEAVES  - n/a
  1873. X      ACTION  - Do some clean up actions.
  1874. X*/
  1875. void finish_up() {
  1876. X    /* Check to make sure that the semantic stack is empty. */
  1877. X    if (top != -1)
  1878. X        error("COMPILER ERROR -- %d entry(ies) left on the semantic stack",
  1879. X              (char*) top+1);
  1880. X
  1881. X    /* Flush and close the output files. */
  1882. X    fflush(file_h);
  1883. X    fclose(file_h);
  1884. X    fflush(file_c);
  1885. X    fclose(file_c);
  1886. X}
  1887. END_OF_FILE
  1888. if test 50650 -ne `wc -c <'compiler/semantic.c'`; then
  1889.     echo shar: \"'compiler/semantic.c'\" unpacked with wrong size!
  1890. fi
  1891. # end of 'compiler/semantic.c'
  1892. fi
  1893. if test -f 'tutorial.tex' -a "${1}" != "-c" ; then 
  1894.   echo shar: Will not clobber existing file \"'tutorial.tex'\"
  1895. else
  1896. echo shar: Extracting \"'tutorial.tex'\" \(28266 characters\)
  1897. sed "s/^X//" >'tutorial.tex' <<'END_OF_FILE'
  1898. X%  tutorial.tex
  1899. X%  Copyright (C) 1992  J Dana Eckart
  1900. X%
  1901. X%  This program is free software; you can redistribute it and/or modify
  1902. X%  it under the terms of the GNU General Public License as published by
  1903. X%  the Free Software Foundation; either version 1, or (at your option)
  1904. X%  any later version.
  1905. X%
  1906. X%  This program is distributed in the hope that it will be useful,
  1907. X%  but WITHOUT ANY WARRANTY; without even the implied warranty of
  1908. X%  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  1909. X%  GNU General Public License for more details.
  1910. X%
  1911. X%  You should have received a copy of the GNU General Public License
  1912. X%  along with CELLULAR-2.0; see the file COPYING.  If not, write to the 
  1913. X%  Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  1914. X
  1915. X\documentstyle[12pt]{article}
  1916. X
  1917. X% Setup the desired page style.
  1918. X\pagestyle{plain}
  1919. X\setlength{\textwidth}{6.5in}
  1920. X\setlength{\textheight}{9.15in}
  1921. X\setlength{\oddsidemargin}{0mm}
  1922. X\setlength{\evensidemargin}{0mm}
  1923. X\setlength{\topmargin}{-0.3in}
  1924. X\setlength{\headheight}{0mm}
  1925. X\setlength{\headsep}{0mm}
  1926. X
  1927. X\setlength{\columnsep}{5mm}
  1928. X
  1929. X% Setup the desired paragraph style.
  1930. X\setlength{\parindent}{0mm}
  1931. X\setlength{\parskip}{3mm}
  1932. X\begin{document}
  1933. X
  1934. X% A new command to define a constant tabbing distance for code examples.
  1935. X\newcommand{\tab}{\hspace{5mm}}
  1936. X
  1937. X\title{A {\em Cellular} Automata Simulation System:\\Version 2.0}
  1938. X\author{J Dana Eckart\\
  1939. X        Radford University}
  1940. X\date{}
  1941. X\maketitle
  1942. X
  1943. X\section{Introduction}
  1944. With the growing popularity of cellular automata in both recreation
  1945. X\cite{life}\cite{wireworld}\cite{fluids}\cite{crystals} 
  1946. and the modeling of physical 
  1947. systems\cite{toffoli}\cite{Wolf-Gladrow}\cite{Chen}\cite{Lavallee}\cite{Lim},
  1948. the need for an easy--to--use system for cellular automata programming
  1949. is greater than ever.  {\em Cellular} is a system designed and implemented
  1950. by the author to meet these needs.  The system consists of: a programming
  1951. language, {\em Cellang 2.0}\footnote{
  1952. X            Pronounced cell ' ang.
  1953. X        },
  1954. and associated compiler, {\tt cellc};
  1955. an ``abstract'' virtual machine\footnote{
  1956. X        The construction of an actual machine embodying the
  1957. X        pe--scam architecture is under development.\cite{pe-scam}
  1958. X    }
  1959. for execution, {\tt pe-scam}; and a viewer, {\tt cellview}.
  1960. Compiled {\em Cellang 2.0} programs can be run
  1961. with input provided at any specified time during the execution.  The
  1962. results of an execution can either be viewed directly or output as
  1963. a stream of cell locations and values.  This stream of output
  1964. data can then be fed into {\tt cellview} for viewing, or it may
  1965. be passed through a filter that compiles statistics, massages the
  1966. data, or merely acts as a valve to control the flow of data from the
  1967. cellular automaton program to the viewer.  This simple UNIX\footnote{
  1968. X                UNIX is a registered trademark of AT\&T.
  1969. X        }
  1970. toolkit view of the simulation process provides greater control
  1971. than systems which combine the language and viewer (i.e.
  1972. cellsim\cite{cellsim} and CAM--6\cite{toffoli}).  {\em Cellang 2.0}
  1973. provides greater flexibility, particularly in the formation of
  1974. neighborhoods, than does {\em Cal} (part of the {\em Scamper} 
  1975. system)\cite{Scamper}.  And although the {\em SLANG}\cite{SLANG} system
  1976. supports probablistic possibilities, {\em Cellang 2.0} is a far
  1977. simpler language for constructing deterministic cellular automata.
  1978. X
  1979. X\section{The Language}
  1980. X
  1981. Programs written in {\em Cellang 2.0} have two main components, a cell
  1982. description and a set of statements.  The cell description determines
  1983. how many dimensions there are, what field(s) each cell
  1984. contains, and the range of assignable values associated with each field.  
  1985. Statements occur in only two varieties:
  1986. assignment and if.  The assignment
  1987. statement is unusual in that it provides conditional assignment;
  1988. the if statement is of a conventional nature.
  1989. X
  1990. There is only one primitive data type in {\em Cellang 2.0}, integer. 
  1991. Variables are
  1992. declared by their first usage which is usually as the left hand side of an
  1993. assignment statement.  Conditional expressions follow the
  1994. rules of {\em C}\cite{harbison},
  1995. thus 0 values correspond to false and non--0 values indicate
  1996. true.  The arithmetic and logical operators available are: --, +, *, /,
  1997. X\% (remainder), ! (logical not), \& (logical and), $|$ (logical or), 
  1998. X=, !=, $<=$ and $>=$.  The field values of cells 
  1999. neighboring the 
  2000. current cell may be accessed by placing their relative position within square
  2001. brackets ([ ]), followed by an optional dot (.) and field name.
  2002. X
  2003. This version (2.0) is an incompatible upgrade to the previous 
  2004. version (1.0).\cite{cellang 1.0}
  2005. The differences are primarily:
  2006. X\begin{itemize}
  2007. X
  2008. X\item
  2009. X{\em Cellang 2.0} does NOT permit the specification of dimension index ranges
  2010. X(whereas {\em Cellang 1.0} did);
  2011. X
  2012. X\item
  2013. X{\em Cellang 2.0} does NOT permit the use of dimension names to determine a
  2014. cell's exact location within the universe (as did {\em Cellang 1.0});
  2015. X
  2016. X\item
  2017. X{\em Cellang 2.0} DOES allow multiple fields to be associated with each cell
  2018. of the universe (unlike {\em Cellang 1.0} which had only one field per cell);
  2019. X
  2020. X\item
  2021. X{\em Cellang 2.0} REQUIRES a range of legal values be given for all cell fields 
  2022. X(whereas this was optional in {\em Cellang 1.0}).
  2023. X
  2024. X\end{itemize}
  2025. X
  2026. X\begin{figure}[t]
  2027. X\begin{center}
  2028. X\begin{verbatim}
  2029. X2 dimensions of 0..1
  2030. X
  2031. sum := [0, 1] + [1, 1] + [1, 0] + [-1, 1] + [-1, 0] + 
  2032. X       [-1, -1] + [0, -1] + [1, -1]
  2033. X
  2034. cell := 1 when (sum = 2 & cell = 1) | sum = 3
  2035. X     := 0 otherwise
  2036. X\end{verbatim}
  2037. X\end{center}
  2038. X\caption{The game of Life}
  2039. X\label{simple life}
  2040. X\end{figure}
  2041. X
  2042. The game of Life, popularized by Gardener\cite{life},
  2043. demonstrates many of the features of {\em Cellang 2.0}.  
  2044. XFigure~\ref{simple life}
  2045. shows the this problem.  Note
  2046. that the universe of cells is 2--dimensional each having either a 0 or
  2047. X1 value.  Comments begin
  2048. with a sharp (\#) and continue to the end of that line.  The predefined variable
  2049. X{\tt cell} is special as it refers to the current cell of the universe under 
  2050. consideration.
  2051. Assignment to the variable {\tt cell} is the only way in which the value 
  2052. of the current cell (or one of its fields)
  2053. can be altered.  Furthermore, the new value of {\tt cell} doesn't take effect
  2054. until the beginning of the next cycle.  Notice that the standard Moore 
  2055. neighborhood used by the
  2056. game of Life must be given by relative indexing.\footnote{
  2057. X                Relative indexing specifies a cell relative to the
  2058. X                current cell.  Thus the relative index ``[-1, 1]''
  2059. X                refers to the bordering northwest cell.
  2060. X        }
  2061. While relative indexing may seem cumbersome,
  2062. it provides great flexibility.  The only practical restriction on relative 
  2063. indices is that they be integer constants.
  2064. X
  2065. Because there are no language specific limits on the size of relative indices,
  2066. it is possible to explore a wide range of neighborhoods.
  2067. Neighborhoods which use field values {\em n} cells away are possible 
  2068. for any value of integer value {\em n}.
  2069. In addition, there is no restriction that neighborhoods
  2070. be symmetrical or have any other special topographical properties.
  2071. X
  2072. An additional predefined variable,
  2073. X{\tt time}, can only appear within expressions.
  2074. Thus a program can not change {\tt time}, but {\tt time} can be used to 
  2075. influence
  2076. computation.  The initial value of {\tt time} is 0 and it is incremented by 1 
  2077. each time all the cells of the universe have been updated.
  2078. This feature allows neighborhoods which
  2079. are time dependent.  Figure~\ref{time dependent life} demonstrates this
  2080. possibility.  Similarly it is also possible to have cell field values change
  2081. with dependence upon time.
  2082. The time dependent neighborhoods can be used to represent both
  2083. hybrid neighborhoods
  2084. or in situations where the physical system behaves
  2085. according to different rules/neighborhoods as it ages.
  2086. X
  2087. X\begin{figure}[t]
  2088. X\begin{center}
  2089. X\begin{verbatim}
  2090. X2 dimensions of 0..1
  2091. X
  2092. if time % 2 = 0 then
  2093. X   sum := [0, 1] + [1, 0] + [-1, 0] + [0, -1]
  2094. else
  2095. X   sum := [1, 1] + [-1, 1] + [-1, -1] + [1, -1]
  2096. end
  2097. X
  2098. cell := 1 when (sum = 2 | sum = 3) & cell = 1
  2099. X     := 1 when sum = 3 & cell = 0
  2100. X     := 0 otherwise
  2101. X\end{verbatim}
  2102. X\end{center}
  2103. X\caption{An alternate game of life with a time dependent (hybrid) neighborhood}
  2104. X\label{time dependent life}
  2105. X\end{figure}
  2106. X
  2107. X\begin{figure}[t]
  2108. X\begin{center}
  2109. X\begin{verbatim}
  2110. X2 dimensions of
  2111. X        x, y of 0..255
  2112. end
  2113. X
  2114. cell.x := ([1, 0].y + [0, 1].y + [-1, 0].y + [0, -1].y) % 256 
  2115. X                when time % 2
  2116. X
  2117. cell.y := ([-1, 1].x + [1, 1].x + [-1, -1].x + [1, -1].x) % 256 
  2118. X                when (time + 1) % 2
  2119. X\end{verbatim}
  2120. X\end{center}
  2121. X\caption{An example program with multi--field cells.}
  2122. X\label{multiple cell fields}
  2123. X\end{figure}
  2124. X
  2125. X{\em Cellang 2.0} programs may also contain more than a single field
  2126. per cell.  The program given in Figure~\ref{multiple cell fields} shows 
  2127. a program with 3 fields per cell.
  2128. Note that the dot notation familiar from many other languages for use
  2129. with records/structures, is used here to determine which of several
  2130. cell fields is being denoted.  If, on the other hand, the field name is 
  2131. not present, then all fields of the cell are used in
  2132. assignment and for tests of equality and inequality.
  2133. X
  2134. XFinally, both the input and output of {\em Cellang 2.0} programs
  2135. allow the user to manipulate cellular automata data in ways that many
  2136. systems do not permit.  Both input and output are of identical form,
  2137. thus allowing automata to be chained together.  Both
  2138. input and output are given as a sequence of time blocks.  A time block
  2139. begins with a time (a non--negative integer value) followed by zero or more
  2140. cell location and value pairs.  When multiple time blocks are given,
  2141. successive times must be strictly greater than all previous times.
  2142. An example set of time blocks for a 2--dimensional automata is given in
  2143. XFigure~\ref{time blocks}.  It specifies that although
  2144. all the cells of the universe have a default value of 0 at time
  2145. X0, the cell at absolute location 3, 3 will have a value of 1.  Furthermore,
  2146. it specifies that at the beginning of time 100 (before any cells have been
  2147. updated), the cell at absolute location 24, 56 has its first field set to 0,
  2148. the cell at absolute location 50, 50 has its first field set to 5 and it second
  2149. field set to 6, and the cell at location 2, 32 has its third field set to 3.
  2150. This cell value input process continues for
  2151. as many time blocks as are in the input.  The output of a {\em Cellang 2.0}
  2152. program has the same form and can thus appear as input to another
  2153. automata.  If each cell has several values which must be set, then the
  2154. multiple values are separated by commas and are assigned in the order in
  2155. which they were declared in the associated {\em Cellang 2.0} program.  When
  2156. only some of the possible field values are given, then the values
  2157. are assigned in order until no more are available, the unspecified cell fields 
  2158. thus retain their previous values.
  2159. X\begin{figure}[t]
  2160. X\begin{center}
  2161. X\begin{verbatim}
  2162. X                             0
  2163. X                             [3, 3] = 1
  2164. X                             100
  2165. X                             [24, 56] = 0
  2166. X                             [50, 50] = 5, 6
  2167. X                             [2, 32] = , , 3
  2168. X\end{verbatim}
  2169. X\end{center}
  2170. X\caption{An example input/output for a {\em Cellang 2.0} program}
  2171. X\label{time blocks}
  2172. X\end{figure}
  2173. X
  2174. X\section{The Viewer}
  2175. X
  2176. The viewer, which is used to examine the cell values in a graphic manner, is
  2177. independent of the {\em Cellang 2.0} language and compiler.  The input
  2178. to the viewer is identical in form to the output (and thus the input)
  2179. of {\em Cellang 2.0} programs.  The current viewer allows the viewing of
  2180. a single field along contiguous portions of any two dimensions.
  2181. The values can be displayed as either characters
  2182. X(via curses) or colored squares (via X--Windows).  A limited debugging
  2183. aid (available only with the X--Windows viewing option) also allows the numeric 
  2184. values of a neighborhood of cells (as opposed
  2185. to the color associated with this value) to be viewed.
  2186. X
  2187. The idea of separating the language (and thus the cellular automata
  2188. simulator) and the viewer allows
  2189. greater flexibility both in the viewing of data and in the creation of
  2190. cellular automata.  There is no restriction that
  2191. the input to the viewer be generated by a {\em Cellang 2.0} program, and it
  2192. is possible that programs of other sorts will be developed
  2193. to examine, gather and report statistics concerning the results of
  2194. X{\em Cellang 2.0} programs.  ``Valve'' filters
  2195. could be inserted between the output generated by a {\em Cellang 2.0}
  2196. program and the input to the viewer.  Such a valve program could allow
  2197. the presentation speed to be tailored to the researcher's needs.
  2198. Since the output of {\em Cellang 2.0} programs are written
  2199. to the standard output, it can be piped directly
  2200. into the viewer with no need for intermediate storage files.  The
  2201. use of a tpipe filter would enable storage of all or part of the
  2202. produced cell values into a file.
  2203. X
  2204. X\begin{figure}[t]
  2205. X\begin{center}
  2206. X\begin{verbatim}
  2207. X                                     50
  2208. X                                     +1
  2209. X                                     100
  2210. X                                     500!
  2211. X\end{verbatim}
  2212. X\end{center}
  2213. X\caption{An example time file for reporting cell values}
  2214. X\label{report times}
  2215. X\end{figure}
  2216. X
  2217. X\section{Compiling \& Viewing}
  2218. X
  2219. Suppose the {\em Cellang 2.0} program for the game of Life that appears in 
  2220. XFigure~\ref{simple life} is in the file {\tt life}.
  2221. A compiled version of the code is obtained by doing {\tt cellc life}
  2222. which places the object code into a file called {\tt a.pe-scam}.
  2223. The object code is executed and displayed by the {\tt pe-scam} 
  2224. abstract machine via:
  2225. X\begin{verbatim}
  2226. pe-scam -c a.pe-scam -r times -x11 -map life.colors < life.data
  2227. X\end{verbatim}
  2228. where {\tt life.data} is a data file containing the 
  2229. initial configuration of live cells and
  2230. X{\tt life.colors}
  2231. contains a suitable color map.
  2232. An optional parameter, {\tt -f},
  2233. is used to indicate which field (starting from 1 for the first field) to 
  2234. use as the value to display for the cells.
  2235. The {\tt -r} option indicates a file which contains information about
  2236. which generations to report cell values for.  
  2237. X
  2238. If the {\tt -r} option is not given
  2239. then the cell values which have changed will be reported for each generation.
  2240. A sample time file appears in Figure~\ref{report times}.  A time file is a list
  2241. of time indications given one per line.  A number indicates a 
  2242. time when the values should be
  2243. reported, while a ``+'' entry causes these values to be produced at the 
  2244. indicated time intervals.  Finally a ``!'' entry determines the time at
  2245. which the last set of values should be produced and the simulation stops.
  2246. Note that a time file need not contain a ``!'' entry.  In the example,
  2247. The first set of values (after time 0) is produced at time 50, then at each 
  2248. time thereafter until time 100 at which point no values are reported 
  2249. until time 500 and the simulation stops.
  2250. X
  2251. Alternatively, {\tt pe-scam} can just output the cell values which can be
  2252. filtered and/or viewed with {\tt cellview}.  An example of this style of
  2253. use is:
  2254. X\begin{verbatim}
  2255. cat  life.data | pe-scam -r times -o |
  2256. X                         cellview -x11 -map life.colors -dim 0..63,0..63
  2257. X\end{verbatim}
  2258. Where the {\tt -o} option indicates that cell values be written to the
  2259. standard output.  The ``-c a.pe--scam'' has been left out, since the
  2260. the codefile is assumed to be ``a.pe-scam'' by default.
  2261. Note that now, however, the dimensions of the cell universe must be known.
  2262. By convention, {\tt pe-scam}'s cell universe begins numbering at 0 for
  2263. each dimension.  The size and number of dimensions is implementation
  2264. dependent (and can be configured at installation time in the current release
  2265. of the software).
  2266. X
  2267. X\begin{figure}[t]
  2268. X\begin{center}
  2269. X\setlength{\unitlength}{3pt}
  2270. X\begin{picture}(31, 31)(0, 0)
  2271. X\normalsize
  2272. X
  2273. X\put(0, 20){\framebox(10, 10){0}}
  2274. X\put(10, 20){\framebox(10, 10){1}}
  2275. X\put(10, 10){\framebox(10, 10){3}}
  2276. X\put(0, 10){\framebox(10, 10){2}}
  2277. X
  2278. X\put(11, 9){\dashbox(10, 10){}}
  2279. X\put(21, 9){\dashbox(10, 10){2}}
  2280. X\put(21, -1){\dashbox(10, 10){0}}
  2281. X\put(11, -1){\dashbox(10, 10){1}}
  2282. X
  2283. X\end{picture}
  2284. X\end{center}
  2285. X\caption{Margolus neighborhood}
  2286. X\label{Margolus neighborhood}
  2287. X\end{figure}
  2288. X
  2289. X\begin{figure}[t]
  2290. X\begin{center}
  2291. X\begin{verbatim}
  2292. X                             0 1 0 1 0 1 0 1 0 1
  2293. X                             2 3 2 3 2 3 2 3 2 3
  2294. X                             0 1 0 1 0 1 0 1 0 1
  2295. X                             2 3 2 3 2 3 2 3 2 3
  2296. X\end{verbatim}
  2297. X\end{center}
  2298. X\caption{The pattern of {\tt which} field values for the Margolus neighborhood}
  2299. X\label{which Margolus}
  2300. X\end{figure}
  2301. X
  2302. X\section{Advanced Examples}
  2303. This section examines two example programs that demonstrate techniques for
  2304. generating the Margolus and hexagonal neighborhoods.  The Margolus
  2305. neighborhood will be used in the simulation of the diffusion of a 
  2306. gas,\footnote{
  2307. X        The program is modeled closely on the version
  2308. X        described by \cite{toffoli} on page 156.
  2309. X    }
  2310. while the hexagonal neighborhood is used to calculate distance.
  2311. X
  2312. X\begin{figure}[tbp]
  2313. X\begin{center}
  2314. X\footnotesize
  2315. X\begin{verbatim}
  2316. X2 dimensions of 
  2317. X        which of 0..3
  2318. X        rand  of 0..1
  2319. X        gas   of 0..1
  2320. end
  2321. X
  2322. X# Calculate the shared random value in the block of 4 cells.
  2323. random := cell.rand + [1, 0].rand + [1, -1].rand + [0, -1].rand
  2324. X                when (cell.which = 0 & time%2 = 1) | (cell.which = 3 & time%2 = 0)
  2325. X
  2326. X       := [-1, 0].rand + cell.rand + [0, -1].rand + [-1, -1].rand
  2327. X                when (cell.which = 1 & time%2 = 1) | (cell.which = 2 & time%2 = 0)
  2328. X
  2329. X       := [-1, 1].rand + [0, 1].rand + cell.rand + [-1, 0].rand
  2330. X                when (cell.which = 3 & time%2 = 1) | (cell.which = 0 & time%2 = 0)
  2331. X
  2332. X       := [0, 1].rand + [1, 1].rand + [1, 0].rand + cell.rand
  2333. X                otherwise
  2334. X
  2335. X# Alternate between the overlapping 4 cell blocks
  2336. if time%2 = 1 then
  2337. X        if random%2 = 1 then
  2338. X                # Clockwise rotation
  2339. X                cell.gas := [0, -1].gas when cell.which = 0
  2340. X                         := [-1, 0].gas when cell.which = 1
  2341. X                         := [0, 1].gas when cell.which = 3
  2342. X                         := [1, 0].gas when cell.which = 2
  2343. X        else
  2344. X                # Counter-clockwise rotation
  2345. X                cell.gas := [1, 0].gas when cell.which = 0
  2346. X                         := [0, -1].gas when cell.which = 1
  2347. X                         := [-1, 0].gas when cell.which = 3
  2348. X                         := [0, 1].gas when cell.which = 2
  2349. X        end
  2350. else
  2351. X        if random%2 = 1 then
  2352. X                # Clockwise rotation
  2353. X                cell.gas := [0, -1].gas when cell.which = 3
  2354. X                         := [-1, 0].gas when cell.which = 2
  2355. X                         := [0, 1].gas when cell.which = 0
  2356. X                         := [1, 0].gas when cell.which = 1
  2357. X        else
  2358. X                # Counter-clockwise rotation
  2359. X                cell.gas := [1, 0].gas when cell.which = 3
  2360. X                         := [0, -1].gas when cell.which = 2
  2361. X                         := [-1, 0].gas when cell.which = 0
  2362. X                         := [0, 1].gas when cell.which = 1
  2363. X        end
  2364. end
  2365. X
  2366. X# Stir the random values, so that they keep changing.
  2367. cell.rand := ([1, 0].rand + [0, 1].rand + [-1, 0].rand + [0, -1].rand + cell.rand)%2
  2368. X\end{verbatim}
  2369. X\end{center}
  2370. X\caption{Gas diffusion using a Margolus neighborhood}
  2371. X\label{gas diffusion}
  2372. X\end{figure}
  2373. X
  2374. X\subsection{Margolus Neighborhood}
  2375. Gas diffusion can be simulated by implementing a random walk for each
  2376. particle/molecule of gas.
  2377. The random walk can be implemented by using non--overlapping
  2378. blocks of four cells (two on a side) which are offset at alternate times
  2379. X(Margolus neighborhood) and having each block of cells randomly rotate their 
  2380. gas particles either clockwise or 
  2381. counter--clockwise.
  2382. X
  2383. To better understand the Margolus neighborhood, consider 
  2384. XFigure~\ref{Margolus neighborhood}.  The four cell block with a solid
  2385. outline, and the other with the dashed outline, would be used at
  2386. alternate times.  At any particular time, however, the universe of cells 
  2387. is completely covered by a non--overlapping set of blocks.  To implement
  2388. a Margolus neighborhood in {\em Cellang 2.0} requires use of the {\tt
  2389. time} variable and some way of distinguishing between different blocks
  2390. of 4 cells.  The latter is accomplished by introducing a field, {\tt which},
  2391. that contains a value, 0 to 3, indicating the cells relative position in
  2392. the block.  A portion of the cell universe {\tt which} values
  2393. are shown in Figure~\ref{which Margolus}.
  2394. X
  2395. Now that the four cell block can be identified, a random number, common
  2396. to each cell in the block, must be generated.  This is done by having
  2397. each cell maintain a two value (0 or 1) {\tt rand} field.  By using {\tt time}
  2398. and the value of {\tt which} a random number, ``shared'' by each cell of the
  2399. block, can be calculated.  This random number is used to determine whether
  2400. the particles of gas, denoted by the value of the {\tt gas} fields,
  2401. are rotated clockwise or counter--clockwise.
  2402. To maintain an ever changing {\tt rand} field
  2403. for each cell, a new value is calculated using the Von Neumann neighborhood.
  2404. The {\em Cellang 2.0} program that implements gas diffusion is shown in 
  2405. XFigure~\ref{gas diffusion}.  
  2406. X
  2407. X\begin{figure}[tbp]
  2408. X\begin{center}
  2409. X\setlength{\unitlength}{4pt}
  2410. X\begin{picture}(80, 60)(0, 0)
  2411. X
  2412. X\multiput(10, 40)(20, 0){3}{\framebox(10, 20)
  2413. X    {\shortstack{\,n\vspace{1ex}\\
  2414. X            \, nw \  ne \vspace{6.2ex}\\
  2415. X            \, sw \ \, se \vspace{1ex}\\
  2416. X            s}}}
  2417. X\multiput(10, 20)(20, 0){3}{\framebox(10, 20)
  2418. X    {\shortstack{\,n\vspace{1ex}\\
  2419. X            \, nw \  ne \vspace{6.2ex}\\
  2420. X            \, sw \ \, se \vspace{1ex}\\
  2421. X            s}}}
  2422. X\multiput(10, 0)(20, 0){3}{\framebox(10, 20)
  2423. X    {\shortstack{\,n\vspace{1ex}\\
  2424. X            \, nw \  ne \vspace{6.2ex}\\
  2425. X            \, sw \ \, se \vspace{1ex}\\
  2426. X            s}}}
  2427. X
  2428. X\multiput(0, 30)(20, 0){4}{\framebox(10, 20)
  2429. X    {\shortstack{\,n\vspace{1ex}\\
  2430. X            \, nw \  ne \vspace{6.2ex}\\
  2431. X            \, sw \ \, se \vspace{1ex}\\
  2432. X            s}}}
  2433. X\multiput(0, 10)(20, 0){4}{\framebox(10, 20)
  2434. X    {\shortstack{\,n\vspace{1ex}\\
  2435. X            \, nw \  ne \vspace{6.2ex}\\
  2436. X            \, sw \ \, se \vspace{1ex}\\
  2437. X            s}}}
  2438. X
  2439. X\end{picture}
  2440. X\end{center}
  2441. X\caption{A portion of a ``squeezed'' hexagonal universe}
  2442. X\label{hexagons}
  2443. X\end{figure}
  2444. X
  2445. X\begin{figure}[tbp]
  2446. X\begin{center}
  2447. X\begin{verbatim}
  2448. X                             0 1 0 1 0 1 0 1 0 1
  2449. X                             1 0 1 0 1 0 1 0 1 0
  2450. X                             0 1 0 1 0 1 0 1 0 1
  2451. X                             1 0 1 0 1 0 1 0 1 0
  2452. X\end{verbatim}
  2453. X\end{center}
  2454. X\caption{The pattern of {\tt which} field values for the hexagonal neighborhood}
  2455. X\label{which hexagon}
  2456. X\end{figure}
  2457. X
  2458. X\subsection{Hexagonal Neighborhood}
  2459. Hexagonal neighborhoods exhibit properties desirable in the simulation
  2460. of many physical systems.  Fortunately, they are quite easy to build
  2461. in {\em Cellang 2.0}.  Simply imagine taking a hexagon and squeezing in
  2462. at the sides, yielding a two cell stack.  Doing this for the
  2463. entire cell universe is depicted in Figure~\ref{hexagons}.  The solid
  2464. lines show the boundary of the original hexagon.  The sides of the
  2465. hexagons have been labeled, clockwise from the top, n (north), ne (north
  2466. east), se (south east), s (south), sw (south west) and nw (north west).
  2467. X
  2468. In order to have the cells act as sets of 2 block stacks, a {\tt which}
  2469. field with the value pattern depicted in Figure~\ref{which hexagon} is
  2470. used.  The value 1 represents the top cell in a pair, while 0 denotes
  2471. the bottom cell.  Note that the top cell of a pair gets its s (south)
  2472. value by skipping over the bottom cell of the pair, likewise the bottom
  2473. cell skips over the top one for its n (north) value.  Thus each cell
  2474. pair agrees on the relative location of neighboring values.  Note that
  2475. this requires that initial (and subsequent) values for fields of cells
  2476. given as input must be coordinated with the assignment to the {\tt which}
  2477. fields, otherwise one or more cell pairs will have only one of the pair
  2478. getting the desired value.\footnote{
  2479. X    In order to more accurately display (in X--Windows) the height--
  2480. X    width ratio of the ``hexagons'', the option ``--s 5,3'' to
  2481. X    {\tt pe-scam}/{\tt cellview} makes the displayed cells 5 pixels
  2482. X    wide and 3 pixels high.
  2483. X}
  2484. X
  2485. X\begin{figure}[p]
  2486. X\begin{center}
  2487. X\begin{verbatim}
  2488. X#                          north
  2489. X#                          -----
  2490. X#                    nw  /       \  ne
  2491. X#                       /         \
  2492. X#                       \         /
  2493. X#                    sw  \       /  se
  2494. X#                          -----
  2495. X#                          south
  2496. X#
  2497. X2 dimensions of 
  2498. X        which of 0..1
  2499. X        dist  of 0..255
  2500. end
  2501. X
  2502. X# Identification of the neighboring cells.
  2503. X#
  2504. if cell.which = 0 then
  2505. X        north := [0, 1]
  2506. X        ne    := [1, 0]
  2507. X        se    := [1, -1]
  2508. X        south := [0, -2]
  2509. X        sw    := [-1, -1]
  2510. X        nw    := [-1, 0]
  2511. else
  2512. X        north := [0, 2]
  2513. X        ne    := [1, 1]
  2514. X        se    := [1, 0]
  2515. X        south := [0, -1]
  2516. X        sw    := [-1, 0]
  2517. X        nw    := [-1, 1]
  2518. end
  2519. X
  2520. min_dist := 255
  2521. min_dist := north.dist when north.dist < min_dist & north.dist > 0
  2522. min_dist := ne.dist    when ne.dist    < min_dist & ne.dist    > 0
  2523. min_dist := se.dist    when se.dist    < min_dist & se.dist    > 0
  2524. min_dist := south.dist when south.dist < min_dist & south.dist > 0
  2525. min_dist := sw.dist    when sw.dist    < min_dist & sw.dist    > 0
  2526. min_dist := nw.dist    when nw.dist    < min_dist & nw.dist    > 0
  2527. X
  2528. cell.dist := min_dist + 4 when cell.dist = 0 & min_dist < 255
  2529. X\end{verbatim}
  2530. X\end{center}
  2531. X\caption{Calculating distance with hexagonal neighborhood}
  2532. X\label{dist}
  2533. X\end{figure}
  2534. X
  2535. X\section{How To Find Out More}
  2536. X
  2537. The entire {\em Cellular} system is available from the author.  Please
  2538. send requests to either:
  2539. X\begin{center}
  2540. J Dana Eckart\\
  2541. Box 6933\\
  2542. Computer Science Department\\
  2543. Radford University\\
  2544. Radford, VA \ 24142\\
  2545. X\ \\
  2546. or\\
  2547. X\ \\
  2548. dana@rucs.faculty.cs.runet.edu\\
  2549. X\end{center}
  2550. X
  2551. X\begin{thebibliography}{99}
  2552. X
  2553. X\bibitem{Chen}
  2554. Chen, Shiyi, Hudong Chen and Gary D. Doolen,
  2555. X``How the Lattice Gas Model for the Navier--Stokes Equation Improves When
  2556. a New Speed is Added'', {\em Complex Systems}, {\bf 3} (1989), 243--251.
  2557. X
  2558. X\bibitem{wireworld}
  2559. Dewdney, A. K., ``The Cellular Automata Programs That Create Wireworld,
  2560. Rugworld and Other Diversions'',
  2561. X{\em Scientific American}, {\bf 262}:1 (January 1990), 146--149.
  2562. X
  2563. X\bibitem{crystals}
  2564. Dewdney, A. K., ``A Cellular Universe of Debris, Droplets, Defects and Demons'',
  2565. X{\em Scientific American}, {\bf 261}:2 (August 1989), 102--105.
  2566. X
  2567. X\bibitem{fluids}
  2568. Dewdney, A. K., ``The Hodgepodge Machine Makes Waves'',
  2569. X{\em Scientific American}, {\bf 259}:2 (August 1988), 104--107.
  2570. X
  2571. X\bibitem{pe-scam}
  2572. XEckart, J. Dana, ``A Parallel Extendible Scalable Cellular Automata Machine:
  2573. PE--SCAM'',
  2574. X{\em Proceedings of the ACM $20^{th}$ Annual Computer Science Conference}, 
  2575. March 3--5, 1992, 467--472.
  2576. X
  2577. X\bibitem{cellang 1.0}
  2578. XEckart, J. Dana, ``A {\em Cellular} Automata Simulation System'',
  2579. X{\em SIGPLAN Notices}, {\bf 26}:8 (August 1991), 80--85.
  2580. X
  2581. X\bibitem{life}
  2582. Gardner, Martin,
  2583. X``The Fantastic Combinations of John Conway's New Solitaire Game of `Life','',
  2584. X{\em Scientific American}, {\bf 223}:4 (April 1970), 120--123.
  2585. X
  2586. X\bibitem{harbison}
  2587. Harbison, Samuel P. and Guy L. Steele Jr., {\em C: A Reference Manual},
  2588. Prentice Hall, Englewood Cliffs, New Jersey, 1991.
  2589. X
  2590. X\bibitem{cellsim}
  2591. Langton, Chris and Dave Hiebeler, {\em Cellsim}, available by anonymous
  2592. ftp from isy.liu.se, Version 2.5.
  2593. X
  2594. X\bibitem{Lavallee}
  2595. Lavalle\`e, Paul, Jean Pierre Boon and Alain Noullez,
  2596. X``Lattice Boltzmann Equation for Laminar Boundary Flow'',
  2597. X{\em Complex Systems}, {\bf 3} (1989), 317--330.
  2598. X
  2599. X\bibitem{Lim}
  2600. Lim, Hwa A., ``Lattice Gas Automata of Fluid Dynamics for Unsteady Flow'',
  2601. X{\em Complex Systems}, {\bf 2} (1988), 45--58.
  2602. X
  2603. X\bibitem{Scamper}
  2604. Palmer, Ian J., {\em Scamper}, available by anonymous ftp from ftp.uu.net.
  2605. X
  2606. X\bibitem{SLANG}
  2607. Sieburg, Hans B. and Oliver K. Clay, ``The Cellular Device Machine Development
  2608. System for Modeling Biology on the Computer'', {\em Complex Systems},
  2609. X{\bf 5} (1991), 575--601.
  2610. X
  2611. X\bibitem{toffoli}
  2612. Toffoli, Tommaso and Norman Margolus,
  2613. X{\em Cellular Automata Machines: A New Environment for Modeling},
  2614. The MIT Press, Cambridge, Massachusetts, 1987.
  2615. X
  2616. X\bibitem{Wolf-Gladrow}
  2617. Wolf--Gladrow, D. A., R. Nasilowski and A. Vogeler,
  2618. X``Numerical Simulations of Fluid Dynamics with a Pair Interaction
  2619. Automaton in Two Dimensions'',
  2620. X{\em Complex Systems}, {\bf 5} (1991), 89--100.
  2621. X
  2622. X\end{thebibliography}
  2623. X
  2624. X\end{document}
  2625. END_OF_FILE
  2626. if test 28266 -ne `wc -c <'tutorial.tex'`; then
  2627.     echo shar: \"'tutorial.tex'\" unpacked with wrong size!
  2628. fi
  2629. # end of 'tutorial.tex'
  2630. fi
  2631. echo shar: End of archive 3 \(of 3\).
  2632. cp /dev/null ark3isdone
  2633. MISSING=""
  2634. for I in 1 2 3 ; do
  2635.     if test ! -f ark${I}isdone ; then
  2636.     MISSING="${MISSING} ${I}"
  2637.     fi
  2638. done
  2639. if test "${MISSING}" = "" ; then
  2640.     echo You have unpacked all 3 archives.
  2641.     rm -f ark[1-9]isdone
  2642. else
  2643.     echo You still need to unpack the following archives:
  2644.     echo "        " ${MISSING}
  2645. fi
  2646. ##  End of shell archive.
  2647. exit 0
  2648.