home *** CD-ROM | disk | FTP | other *** search
/ HAM Radio 1 / HamRadio.cdr / tech / pcbsrcs2 / io3.c < prev    next >
C/C++ Source or Header  |  1991-02-07  |  41KB  |  1,248 lines

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <malloc.h>
  5. #include <ctype.h>
  6. #include "cell.h"
  7.  
  8. extern int Nrows, Ncols; /* board dimensions */
  9.  
  10. extern int InitBoardDone; /* sanity check */
  11. extern int SortConnects; /* 0 = don't sort, 1 = sort */
  12.  
  13. /* memory usage */
  14. extern unsigned long Ltotal; /* for board */
  15. extern unsigned long Itotal; /* for dist */
  16. extern unsigned long Ctotal; /* for dir */
  17.  
  18. /*
  19. ** the following types of input lines are legal (spaces and tabs can separate
  20. ** tokens, and case is not significant):
  21. **
  22. **  1) a blank line (ignored)
  23. **  2) ';' followed by anything (ignored)
  24. **     use semicolon to insert comments.
  25. **  3) DIMENSION (row,column)
  26. **     this defines the number of rows and columns on the board, and must be
  27. **     given before any of the lines below. note that the user sees the board
  28. **     coordinate space as being 1-based, but internally it is 0-based.
  29. **  4) HOLE (row,column)
  30. **     this defines a hole location.
  31. **  5) CONNECT thing AND thing
  32. **     this declares that two holes are to be electrically connected. a thing
  33. **     can be (row,column), or name1.name2, where name1 is the name of a
  34. **     CHIPAT-defined chip, and name2 is the name of one of its pins, or a
  35. **     number, giving the pin number of the named chip. you can use "TO" or
  36. **     "=" instead of "AND" if you want.
  37. **  6) PRIORITY CONNECT thing AND thing
  38. **     same as above, except the order of connections will be preserved. the
  39. **     autorouter is free to reorder the non-PRIORITY CONNECTs, and in fact
  40. **     reorders them shortest first. if there are PRIORITY CONNECTs, they will
  41. **     all be routed before non-PRIORITY CONNECTs.
  42. **  7) INCLUDE filename
  43. **     this causes the input to be temporarily taken from the given filename.
  44. **     when the given filename is completely processed (EOF encountered),
  45. **     control returns to the current file. INCLUDE statements may be nested
  46. **     (they may occur inside the given filename). complete and partial
  47. **     pathnames can be used (C:\TTL.INC, ..\TTL.INC, \TTL.INC, FOO\TTL.INC).
  48. **  8) CHIP TYPE=type PINS=number HORIZONTAL=number VERTICAL=number
  49. **     this declares a chip type, which can be used to place chips on the
  50. **     board (see CHIPAT, below), but does not itself place anything on the
  51. **     board. TYPE gives the name that will be used in later CHIPAT
  52. **     statements. PINS declares the number of pins. HORIZONTAL gives the
  53. **     number of 50-mil units separating adjacent pins (along the long side of
  54. **     the chip). and VERTICAL gives the number of 50-mil units separating
  55. **     pins across from each other (across the skinny width of the chip).
  56. **     standard values for HORIZONTAL and VERTICAL are 2 and 6, respectively.
  57. **     all CHIP type names must be unique.
  58. **  9) number=name
  59. **     this declares a pin name for the chip that is currently being defined.
  60. **     this statement must follow a CHIP statement. pins not defined will have
  61. **     no name, but you can still refer to them by number. each pin on a chip
  62. **     can be named at most once.
  63. ** 10) name=number
  64. **     same as above.
  65. ** 11) CHIPAT (row,column) NAME=name TYPE=type ORIENTATION=orientation
  66. **     this defines an instance of a chip, and places the appropriate holes on
  67. **     the board. (row,column) is the location of pin 1. NAME defines the name
  68. **     to be used in following CONNECT statements. TYPE declares the
  69. **     CHIPAT-defined type of the chip. ORIENTATION can have the values
  70. **     NORMAL, UP, DOWN, and UPSIDEDOWN. all CHIPAT names must be unique.
  71. ** 12) INLINE TYPE=type PINS=number HORIZONTAL=number
  72. **     this declares an inline type, which can be used to place chips on the
  73. **     board (see CHIPAT, below), but does not itself place anything on the
  74. **     board. TYPE gives the name that will be used in later INLINAT
  75. **     statements. PINS declares the number of pins. HORIZONTAL gives the
  76. **     number of 50-mil units separating adjacent pins.  Standard value
  77. **     for HORIZONTAL is 2.  All INLINE type names must be unique.
  78. ** 13) INLINEAT (row,column) NAME=name TYPE=type ORIENTATION=orientation
  79. **     this defines an instance of an inline, and places the appropriate
  80. **     holes on the board. (row,column) is the location of pin 1. NAME defines
  81. **     the name to be used in following CONNECT statements. TYPE declares the
  82. **     INLINEAT-defined type of the chip. ORIENTATION can have the values
  83. **     NORMAL, UP, DOWN, and UPSIDEDOWN. all CHIPAT names must be unique.
  84. **
  85. **      NORMAL           UP           DOWN        UPSIDEDOWN
  86. **
  87. **       6 5 4          +---+         +---+          3 2 1
  88. **     +-*-*-*-+      4 *   * 3     1 * | * 6      +-*-*-*-+
  89. **     |  ->   |      5 * ^ * 2     2 * v * 5      |   <-  |
  90. **     +-*-*-*-+      6 * | * 1     3 *   * 4      +-*-*-*-+
  91. **       1 2 3          +---+         +---+          4 5 6
  92. **
  93. **     usually the highest-numbered pin (pin N) is Vcc (power) and the pin
  94. **     farthest from it (pin N/2) is GND (ground).
  95. */
  96.  
  97. /* chip orientations (rotations) */
  98. #define ORIENT_NORMAL        1
  99. #define ORIENT_UP           2
  100. #define ORIENT_DOWN         3
  101. #define ORIENT_UPSIDEDOWN    4
  102.  
  103. /* input token types */
  104. #define TOK_EOF             1   /* end of file, no more tokens          */
  105. #define TOK_NEWLINE         2   /* end of line                          */
  106. #define TOK_NUMBER          3   /* number (digits)                      */
  107. #define TOK_HOLE            4   /* "HOLE"                               */
  108. #define TOK_ROWCOLUMN       5   /* "(row,column)"                       */
  109. #define TOK_CONNECT         6   /* "CONNECT"                            */
  110. #define TOK_EQUAL           7   /* "="                                  */
  111. #define TOK_AND             8   /* "AND"                                */
  112. #define TOK_ALPHANUM        9   /* name (letters, digits, ':','.','\')  */
  113. #define TOK_CHIP           10  /* "CHIP"                                */
  114. #define TOK_NAME           11  /* "NAME"                                */
  115. #define TOK_PINS           12  /* "PINS"                                */
  116. #define TOK_HORIZONTAL     13  /* "HORIZONTAL"                          */
  117. #define TOK_VERTICAL       14  /* "VERTICAL"                            */
  118. #define TOK_INCLUDE        15  /* "INCLUDE"                             */
  119. #define TOK_CHIPAT         16  /* "CHIPAT"                              */
  120. #define TOK_TYPE           17  /* "TYPE"                                */
  121. #define TOK_ORIENTATION    18  /* "ORIENTATION"                         */
  122. #define TOK_NORMAL         19  /* "NORMAL"                              */
  123. #define TOK_UP             20  /* "UP"                                  */
  124. #define TOK_DOWN           21  /* "DOWN"                                */
  125. #define TOK_UPSIDEDOWN     22  /* "UPSIDEDOWN"                          */
  126. #define TOK_DIMENSION      23  /* "DIMENSION"                           */
  127. #define TOK_PRIORITY       24  /* "PRIORITY"                            */
  128. #define TOK_TO             25  /* "TO"                                  */
  129. #define TOK_INLINE         26  /* "INLINE"                              */
  130. #define TOK_INLINEAT       27  /* "INLINEAT"                            */
  131.  
  132. struct reserved { /* reserved word input tokens */
  133.     char *tokenname;
  134.     int tokenvalue;
  135.     };
  136.  
  137. static struct reserved tokenmatch[] = { /* reserved word table */
  138.   { "HOLE",       TOK_HOLE       },  { "CONNECT",     TOK_CONNECT     },
  139.   { "AND",        TOK_AND        },  { "CHIP",        TOK_CHIP        },
  140.   { "NAME",       TOK_NAME       },  { "PINS",        TOK_PINS        },
  141.   { "HORIZONTAL", TOK_HORIZONTAL },  { "VERTICAL",    TOK_VERTICAL    },
  142.   { "INCLUDE",    TOK_INCLUDE    },  { "CHIPAT",      TOK_CHIPAT      },
  143.   { "TYPE",       TOK_TYPE       },  { "ORIENTATION", TOK_ORIENTATION },
  144.   { "NORMAL",     TOK_NORMAL     },  { "UP",          TOK_UP          },
  145.   { "DOWN",       TOK_DOWN       },  { "UPSIDEDOWN",  TOK_UPSIDEDOWN  },
  146.   { "DIMENSION",  TOK_DIMENSION  },  { "PRIORITY",    TOK_PRIORITY    },
  147.   { "TO",         TOK_TO         },  { "INLINE",      TOK_INLINE      },
  148.   { "INLINEAT",   TOK_INLINEAT   },
  149.  };
  150.  
  151. #define MAXTOK    80    /* maximum token length (including null) */
  152.  
  153. static int numres = sizeof(tokenmatch) / sizeof(tokenmatch[0]);
  154. static char token[MAXTOK]; /* the current token is formed here */
  155.  
  156. struct pinassign { /* for assigning names to pins */
  157.     int            index;
  158.     char far        *name;
  159.     struct pinassign far    *next;
  160.     };
  161.  
  162. struct template { /* for "CHIP" declarations */
  163.     char far        *type;
  164.     int            pins;
  165.     int            horizontal;
  166.     int            vertical;
  167.     struct pinassign far    *pinlist;
  168.     struct template far    *next;
  169.     };
  170.  
  171. struct instance { /* for "CHIPAT" definitions */
  172.     int            row;
  173.     int            column;
  174.     char far        *name;
  175.     struct template far    *type;
  176.     int            orientation;
  177.     struct instance far    *next;
  178.     };
  179.  
  180. static struct template far *chip = NULL; /* list of CHIPs */
  181. static struct instance far *chipat = NULL; /* list of CHIPATs */
  182.  
  183. extern void InitBoard( void );
  184. extern long GetCell( int, int, int );
  185. extern void SetCell( int, int, int, long );
  186. extern void InitWork( void );
  187. extern void SetWork( int, int, char far *, int, int, char far *, int );
  188. extern void SortWork( void );
  189. extern void Nomem( void );
  190.  
  191. int Initialize( char *, int );
  192. static int initfile( FILE *, char * );
  193. static void initchip( struct instance far *, char *, int );
  194. static void initinline( struct instance far *, char *, int );
  195. static void locate( char *, int *, int *, char *, int );
  196. static int gettoken( FILE *, char *, int );
  197. static char far *fcopy( char * );
  198. static int same( char far *, char far * );
  199. void Report( FILE * );
  200.  
  201. int Initialize ( file, echo ) /* get hole coordinates and connections */
  202.     char *file;
  203.     int echo;
  204.     {
  205.     FILE *fp;
  206.     int tot;
  207.  
  208.     if (echo)
  209.         printf( "Enter Initialize()\n" );
  210.     if (!(fp = fopen( file, "r" ))) {
  211.         fprintf( stderr, "can't open %s\n", file );
  212.         exit( -1 );
  213.         }
  214.     InitWork(); /* clear work list */
  215.     tot = initfile( fp, file ); /* read input file(s) */
  216.     if (SortConnects)
  217.         SortWork(); /* arrange to do shortest ones first */
  218.     if (echo) {
  219.         printf( "  %lu bytes used for Board\n", Ltotal );
  220.         printf( "  %lu bytes used for Dist\n", Itotal );
  221.         printf( "  %lu bytes used for Dir\n", Ctotal );
  222.         printf( "Exit Initialize()\n" );
  223.         }
  224.     if (fclose( fp ))
  225.         fprintf( stderr, "error closing %s\n", file );
  226.     return( tot );
  227.     }
  228.  
  229. /* some useful macros (common code sequences) */
  230.  
  231. #define FileLine    { fprintf( stderr, "%s(%d): ", file, line ); }
  232.  
  233. #define GetTok(tok)    ((tok) = gettoken( fp, file, line ))
  234.  
  235. #define SkipRest    { while (GetTok(tok) != TOK_EOF \
  236.                 && tok != TOK_NEWLINE) ; \
  237.             if (tok == TOK_NEWLINE) line++; }
  238.  
  239. #define SkipTokRest    { while (tok != TOK_EOF && tok != TOK_NEWLINE) \
  240.                 GetTok(tok); } \
  241.             if (tok == TOK_NEWLINE) line++; \
  242.             continue;
  243.  
  244. #define CheckInit    { if (!InitBoardDone) { \
  245.                 FileLine; \
  246.                 fprintf( stderr, "need dimensions first\n" ); \
  247.                 SkipRest; \
  248.                 continue; } }
  249.  
  250. static int initfile ( fp, file ) /* read and process input file(s) */
  251.     FILE *fp;
  252.     char *file;
  253.     {
  254.     int tok, r1, c1, r2, c2, i, line;
  255.     char far *p;
  256.     char far *n1;
  257.     char far *n2;
  258.     long cell;
  259.     struct template far *p1;
  260.     struct pinassign far *p2;
  261.     struct pinassign far *p22;
  262.     struct instance far *p3;
  263.     FILE *fnew;
  264.     char *fname;
  265.     int tot = 0;
  266.  
  267.     line = 1;
  268.     while (GetTok(tok) != TOK_EOF) {
  269.         if (tok == TOK_DIMENSION) {
  270.             if (InitBoardDone) { /* can only do it once */
  271.                 FileLine;
  272.                 fprintf( stderr,
  273.                     "redundant dimensions\n" );
  274.                 SkipRest;
  275.                 continue;
  276.                 }
  277.             if (GetTok(tok) != TOK_ROWCOLUMN) {
  278.                 FileLine;
  279.                 fprintf( stderr, "expect (row,column)\n" );
  280.                 SkipTokRest;
  281.                 }
  282.             sscanf( token, "(%d,%d)", &Nrows, &Ncols );
  283.             if (Nrows <= 0 || Ncols <= 0) {
  284.                 FileLine;
  285.                 fprintf( stderr, "dimension error\n" );
  286.                 }
  287.             else /* allocate memory for data structures */
  288.                 InitBoard();
  289.             }
  290.         else if (tok == TOK_HOLE) {
  291.             CheckInit; /* must get dimensions first */
  292.             if (GetTok(tok) != TOK_ROWCOLUMN) {
  293.                 FileLine;
  294.                 fprintf( stderr, "expect (row,column)\n" );
  295.                 SkipTokRest;
  296.                 }
  297.             sscanf( token, "(%d,%d)", &r1, &c1 );
  298.             if (r1 <= 0 || r1 > Nrows || c1 <= 0 || c1 > Ncols) {
  299.                 FileLine;
  300.                 fprintf( stderr, "out of range\n" );
  301.                 }
  302.             else { /* position the hole on the board */
  303.                 /* should check for neighbor holes (error) */
  304.                 SetCell( r1-1, c1-1, TOP, HOLE );
  305.                 SetCell( r1-1, c1-1, BOTTOM, HOLE );
  306.                 }
  307.             }
  308.         else if (tok == TOK_CONNECT) {
  309.             CheckInit; /* must get dimensions first */
  310.             if (GetTok(tok) == TOK_ROWCOLUMN)
  311.                 sscanf( token, "(%d,%d)", &r1, &c1 );
  312.             else if (tok == TOK_ALPHANUM)
  313.                 locate( token, &r1, &c1, file, line );
  314.             else {
  315.                 FileLine;
  316.                 fprintf( stderr,
  317.                     "expect (row,column) or name\n" );
  318.                 SkipTokRest;
  319.                 }
  320.             n1 = fcopy( token );
  321.             if (GetTok(tok) != TOK_EQUAL
  322.                 && tok != TOK_AND && tok != TOK_TO) {
  323.                 FileLine;
  324.                 fprintf( stderr, "expect = or AND or TO\n" );
  325.                 SkipTokRest;
  326.                 }
  327.             if (GetTok(tok) == TOK_ROWCOLUMN)
  328.                 sscanf( token, "(%d,%d)", &r2, &c2 );
  329.             else if (tok == TOK_ALPHANUM)
  330.                 locate( token, &r2, &c2, file, line );
  331.             else {
  332.                 FileLine;
  333.                 fprintf( stderr,
  334.                     "expect (row,column) or name\n" );
  335.                 SkipTokRest;
  336.                 }
  337.             n2 = fcopy( token );
  338.             if (r1 <= 0 || r1 > Nrows || r2 <= 0 || r2 > Nrows
  339.                 || c1 <= 0 || c1 > Ncols
  340.                 || c2 <= 0 || c2 > Ncols) {
  341.                 FileLine;
  342.                 fprintf( stderr, "out of range\n" );
  343.                 farfree( n1 );
  344.                 farfree( n2 );
  345.                 }
  346.             else {
  347.                 cell = GetCell( r1-1, c1-1, TOP );
  348.                 if (!(cell & HOLE)) {
  349.                     FileLine;
  350.                     fprintf( stderr, "no source hole\n" );
  351.                     farfree( n1 );
  352.                     farfree( n2 );
  353.                     SkipRest;
  354.                     continue;
  355.                     }
  356.                 cell = GetCell( r2-1, c2-1, TOP );
  357.                 if (!(cell & HOLE)) {
  358.                     FileLine;
  359.                     fprintf( stderr, "no target hole\n" );
  360.                     farfree( n1 );
  361.                     farfree( n2 );
  362.                     SkipRest;
  363.                     continue;
  364.                     }
  365.                 SetWork( r1-1, c1-1, n1, r2-1, c2-1, n2, 0 );
  366.                 tot++;
  367.                 }
  368.             }
  369.         else if (tok == TOK_PRIORITY) {
  370.             CheckInit; /* must get dimensions first */
  371.             if (GetTok(tok) != TOK_CONNECT) {
  372.                 FileLine;
  373.                 fprintf( stderr, "expect CONNECT\n" );
  374.                 SkipTokRest;
  375.                 }
  376.             if (GetTok(tok) == TOK_ROWCOLUMN)
  377.                 sscanf( token, "(%d,%d)", &r1, &c1 );
  378.             else if (tok == TOK_ALPHANUM)
  379.                 locate( token, &r1, &c1, file, line );
  380.             else {
  381.                 FileLine;
  382.                 fprintf( stderr,
  383.                     "expect (row,column) or name\n" );
  384.                 SkipTokRest;
  385.                 }
  386.             n1 = fcopy( token );
  387.             if (GetTok(tok) != TOK_EQUAL
  388.                 && tok != TOK_AND && tok != TOK_TO) {
  389.                 FileLine;
  390.                 fprintf( stderr, "expect = or AND or TO\n" );
  391.                 SkipTokRest;
  392.                 }
  393.             if (GetTok(tok) == TOK_ROWCOLUMN)
  394.                 sscanf( token, "(%d,%d)", &r2, &c2 );
  395.             else if (tok == TOK_ALPHANUM)
  396.                 locate( token, &r2, &c2, file, line );
  397.             else {
  398.                 FileLine;
  399.                 fprintf( stderr,
  400.                     "expect (row,column) or name\n" );
  401.                 SkipTokRest;
  402.                 }
  403.             n2 = fcopy( token );
  404.             if (r1 <= 0 || r1 > Nrows || r2 <= 0 || r2 > Nrows
  405.                 || c1 <= 0 || c1 > Ncols
  406.                 || c2 <= 0 || c2 > Ncols) {
  407.                 FileLine;
  408.                 fprintf( stderr, "out of range\n" );
  409.                 farfree( n1 );
  410.                 farfree( n2 );
  411.                 }
  412.             else {
  413.                 cell = GetCell( r1-1, c1-1, TOP );
  414.                 if (!(cell & HOLE)) {
  415.                     FileLine;
  416.                     fprintf( stderr, "no source hole\n" );
  417.                     farfree( n1 );
  418.                     farfree( n2 );
  419.                     SkipRest;
  420.                     continue;
  421.                     }
  422.                 cell = GetCell( r2-1, c2-1, TOP );
  423.                 if (!(cell & HOLE)) {
  424.                     FileLine;
  425.                     fprintf( stderr, "no target hole\n" );
  426.                     farfree( n1 );
  427.                     farfree( n2 );
  428.                     SkipRest;
  429.                     continue;
  430.                     }
  431.                 SetWork( r1-1, c1-1, n1, r2-1, c2-1, n2, 1 );
  432.                 tot++;
  433.                 }
  434.             }
  435.         else if (tok == TOK_INCLUDE) {
  436.             CheckInit; /* must get dimensions first */
  437.             if (GetTok(tok) != TOK_ALPHANUM) {
  438.                 FileLine;
  439.                 fprintf( stderr,
  440.                     "expect file name for INCLUDE\n" );
  441.                 SkipTokRest;
  442.                 }
  443.             if (!(fnew = fopen( token, "r" ))) {
  444.                 FileLine;
  445.                 fprintf( stderr,
  446.                     "can't open INCLUDE file %s\n",
  447.                     token );
  448.                 SkipRest;
  449.                 continue;
  450.                 }
  451.             if (!(fname = strdup( token )))
  452.                 Nomem();
  453.             if (GetTok(tok) != TOK_EOF
  454.                 && tok != TOK_NEWLINE) {
  455.                 FileLine;
  456.                 fprintf( stderr,
  457.                     "extra chars on INCLUDE line\n" );
  458.                 SkipRest;
  459.                 }
  460.             if (tok == TOK_NEWLINE)
  461.                 line++;
  462.             tot += initfile( fnew, fname ); /* recurse */
  463.             if (fclose( fnew )) {
  464.                 FileLine;
  465.                 fprintf( stderr,
  466.                     "error closing INCLUDE file\n" );
  467.                 }
  468.             free( fname );
  469.             continue; /* already ate the NEWLINE, if any */
  470.             }
  471.         else if (tok == TOK_CHIP) {
  472.             CheckInit; /* must get dimensions first */
  473.             if (GetTok(tok) != TOK_TYPE
  474.                 || GetTok(tok) != TOK_EQUAL
  475.                 || GetTok(tok) != TOK_ALPHANUM) {
  476.                 FileLine;
  477.                 fprintf( stderr, "expect TYPE=type\n" );
  478.                 SkipTokRest;
  479.                 }
  480.             if (!(p1 = (struct template far *)
  481.                 farmalloc( sizeof(struct template) )))
  482.                 Nomem();
  483.             p1->type = fcopy( token );
  484.             if (GetTok(tok) != TOK_PINS
  485.                 || GetTok(tok) != TOK_EQUAL
  486.                 || GetTok(tok) != TOK_NUMBER) {
  487.                 FileLine;
  488.                 fprintf( stderr, "expect PINS=number\n" );
  489.                 farfree( p1->type );
  490.                 farfree( p1 );
  491.                 SkipTokRest;
  492.                 }
  493.             sscanf( token, "%d", &i );
  494.             p1->pins = i;
  495.             if ((p1->pins = i) < 0 || (i & 1)) {
  496.                 FileLine;
  497.                 fprintf( stderr, "PINS negative or odd\n" );
  498.                 }
  499.             if (GetTok(tok) != TOK_HORIZONTAL
  500.                 || GetTok(tok) != TOK_EQUAL
  501.                 || GetTok(tok) != TOK_NUMBER) {
  502.                 FileLine;
  503.                 fprintf( stderr,
  504.                     "expect HORIZONTAL=number\n" );
  505.                 farfree( p1->type );
  506.                 farfree( p1 );
  507.                 SkipTokRest;
  508.                 }
  509.             sscanf( token, "%d", &i );
  510.             if ((p1->horizontal = i) <= 0) {
  511.                 FileLine;
  512.                 fprintf( stderr, "HORIZONTAL nonpositive\n" );
  513.                 }
  514.             if (GetTok(tok) != TOK_VERTICAL
  515.                 || GetTok(tok) != TOK_EQUAL
  516.                 || GetTok(tok) != TOK_NUMBER) {
  517.                 FileLine;
  518.                 fprintf( stderr, "expect VERTICAL=number\n" );
  519.                 farfree( p1->type );
  520.                 farfree( p1 );
  521.                 SkipTokRest;
  522.                 }
  523.             sscanf( token, "%d", &i );
  524.             if ((p1->vertical = i) < 0) {
  525.                 FileLine;
  526.                 fprintf( stderr, "VERTICAL nonpositive\n" );
  527.                 }
  528.             p1->pinlist = NULL;
  529.             p1->next = chip;
  530.             chip = p1;
  531.             }
  532.         else if (tok == TOK_INLINE) {
  533.             CheckInit; /* must get dimensions first */
  534.             if (GetTok(tok) != TOK_TYPE
  535.                 || GetTok(tok) != TOK_EQUAL
  536.                 || GetTok(tok) != TOK_ALPHANUM) {
  537.                 FileLine;
  538.                 fprintf( stderr, "expect TYPE=type\n" );
  539.                 SkipTokRest;
  540.                 }
  541.             if (!(p1 = (struct template far *)
  542.                 farmalloc( sizeof(struct template) )))
  543.                 Nomem();
  544.             p1->type = fcopy( token );
  545.             if (GetTok(tok) != TOK_PINS
  546.                 || GetTok(tok) != TOK_EQUAL
  547.                 || GetTok(tok) != TOK_NUMBER) {
  548.                 FileLine;
  549.                 fprintf( stderr, "expect PINS=number\n" );
  550.                 farfree( p1->type );
  551.                 farfree( p1 );
  552.                 SkipTokRest;
  553.                 }
  554.             sscanf( token, "%d", &i );
  555.             p1->pins = i;
  556.             if (GetTok(tok) != TOK_HORIZONTAL
  557.                 || GetTok(tok) != TOK_EQUAL
  558.                 || GetTok(tok) != TOK_NUMBER) {
  559.                 FileLine;
  560.                 fprintf( stderr,
  561.                     "expect HORIZONTAL=number\n" );
  562.                 farfree( p1->type );
  563.                 farfree( p1 );
  564.                 SkipTokRest;
  565.                 }
  566.             sscanf( token, "%d", &i );
  567.             if ((p1->horizontal = i) <= 0) {
  568.                 FileLine;
  569.                 fprintf( stderr, "HORIZONTAL nonpositive\n" );
  570.                 }
  571.             p1->vertical = 0;
  572.             p1->pinlist = NULL;
  573.             p1->next = chip;
  574.             chip = p1;
  575.             }
  576.         else if (tok == TOK_NUMBER) {
  577.             CheckInit; /* must get dimensions first */
  578.             if (!chip) {
  579.                 FileLine;
  580.                 fprintf( stderr, "no template\n" );
  581.                 SkipRest;
  582.                 continue;
  583.                 }
  584.             sscanf( token, "%d", &i );
  585.             if (GetTok(tok) != TOK_EQUAL
  586.                 || GetTok(tok) != TOK_ALPHANUM) {
  587.                 FileLine;
  588.                 fprintf( stderr, "expect number=name\n" );
  589.                 SkipTokRest;
  590.                 }
  591.             if (!(p2 = (struct pinassign far *)
  592.                 farmalloc( sizeof(struct pinassign) )))
  593.                 Nomem();
  594.             p2->name = fcopy( token );
  595.             p2->index = i;
  596.             /* check uniqueness of name and index */
  597.             for (p22 = chip->pinlist; p22; p22 = p22->next)
  598.                 if (p22->index == i
  599.                     || same( p22->name, p )) {
  600.                     FileLine;
  601.                     fprintf( stderr,
  602.                         "warning: repeated pin\n" );
  603.                     break;
  604.                     }
  605.             p2->next = chip->pinlist;
  606.             chip->pinlist = p2;
  607.             }
  608.         else if (tok == TOK_ALPHANUM) {
  609.             CheckInit; /* must get dimensions first */
  610.             if (!chip) {
  611.                 FileLine;
  612.                 fprintf( stderr, "no template\n" );
  613.                 SkipRest;
  614.                 continue;
  615.                 }
  616.             p = fcopy( token );
  617.             if (GetTok(tok) != TOK_EQUAL
  618.                 || GetTok(tok) != TOK_NUMBER) {
  619.                 FileLine;
  620.                 fprintf( stderr, "expect name=number\n" );
  621.                 farfree( p );
  622.                 SkipTokRest;
  623.                 }
  624.             sscanf( token, "%d", &i );
  625.             if (!(p2 = (struct pinassign far *)
  626.                 farmalloc( sizeof(struct pinassign) )))
  627.                 Nomem();
  628.             p2->name = p;
  629.             p2->index = i;
  630.             /* check uniqueness of name and index */
  631.             for (p22 = chip->pinlist; p22; p22 = p22->next)
  632.                 if (p22->index == i
  633.                     || same( p22->name, p )) {
  634.                     FileLine;
  635.                     fprintf( stderr,
  636.                         "warning: repeated pin\n" );
  637.                     break;
  638.                     }
  639.             p2->next = chip->pinlist;
  640.             chip->pinlist = p2;
  641.             }
  642.         else if (tok == TOK_CHIPAT) {
  643.             CheckInit; /* must get dimensions first */
  644.             if (GetTok(tok) != TOK_ROWCOLUMN) {
  645.                 FileLine;
  646.                 fprintf( stderr, "expect (row,column)\n" );
  647.                 SkipTokRest;
  648.                 }
  649.             sscanf( token, "(%d,%d)", &r1, &c1 );
  650.             if (GetTok(tok) != TOK_NAME
  651.                 || GetTok(tok) != TOK_EQUAL
  652.                 || GetTok(tok) != TOK_ALPHANUM) {
  653.                 FileLine;
  654.                 fprintf( stderr, "expect NAME=name\n" );
  655.                 SkipTokRest;
  656.                 }
  657.             if (!(p3 = (struct instance far *)
  658.                 farmalloc( sizeof(struct instance) )))
  659.                 Nomem();
  660.             p3->name = fcopy( token );
  661.             p3->row = r1;
  662.             p3->column = c1;
  663.             if (GetTok(tok) != TOK_TYPE
  664.                 || GetTok(tok) != TOK_EQUAL
  665.                 || GetTok(tok) != TOK_ALPHANUM) {
  666.                 FileLine;
  667.                 fprintf( stderr, "expect TYPE=type\n" );
  668.                 farfree( p3->name );
  669.                 farfree( p3 );
  670.                 SkipTokRest;
  671.                 }
  672.             for (p3->type = chip; p3->type;
  673.                 p3->type = p3->type->next)
  674.                 if (same( token, p3->type->type ))
  675.                     break;
  676.             if (!(p3->type)) {
  677.                 FileLine;
  678.                 fprintf( stderr,
  679.                     "couldn't find chip type\n" );
  680.                 farfree( p3->name );
  681.                 farfree( p3 );
  682.                 SkipTokRest;
  683.                 }
  684.             if (GetTok(tok) != TOK_ORIENTATION
  685.                 || GetTok(tok) != TOK_EQUAL
  686.                 || (GetTok(tok) != TOK_NORMAL
  687.                 && tok != TOK_UP && tok != TOK_DOWN
  688.                 && tok != TOK_UPSIDEDOWN)) {
  689.                 FileLine;
  690.                 fprintf( stderr,
  691.                     "expect ORIENTATION=orientation\n" );
  692.                 farfree( p3->name );
  693.                 farfree( p3 );
  694.                 SkipTokRest;
  695.                 }
  696.             switch (tok) {
  697.             case TOK_NORMAL:
  698.                 p3->orientation = ORIENT_NORMAL;    break;
  699.             case TOK_UP:
  700.                 p3->orientation = ORIENT_UP;        break;
  701.             case TOK_DOWN:
  702.                 p3->orientation = ORIENT_DOWN;      break;
  703.             case TOK_UPSIDEDOWN:
  704.                 p3->orientation = ORIENT_UPSIDEDOWN;    break;
  705.             default:
  706.                 FileLine;
  707.                 fprintf( stderr, "internal error\n" );
  708.                 exit( -1 );
  709.                 break;
  710.                 }
  711.             p3->next = chipat;
  712.             chipat = p3;
  713.             initchip( p3, file, line );
  714.             }
  715.         else if (tok == TOK_INLINEAT) {
  716.             CheckInit; /* must get dimensions first */
  717.             if (GetTok(tok) != TOK_ROWCOLUMN) {
  718.                 FileLine;
  719.                 fprintf( stderr, "expect (row,column)\n" );
  720.                 SkipTokRest;
  721.                 }
  722.             sscanf( token, "(%d,%d)", &r1, &c1 );
  723.             if (GetTok(tok) != TOK_NAME
  724.                 || GetTok(tok) != TOK_EQUAL
  725.                 || GetTok(tok) != TOK_ALPHANUM) {
  726.                 FileLine;
  727.                 fprintf( stderr, "expect NAME=name\n" );
  728.                 SkipTokRest;
  729.                 }
  730.             if (!(p3 = (struct instance far *)
  731.                 farmalloc( sizeof(struct instance) )))
  732.                 Nomem();
  733.             p3->name = fcopy( token );
  734.             p3->row = r1;
  735.             p3->column = c1;
  736.             if (GetTok(tok) != TOK_TYPE
  737.                 || GetTok(tok) != TOK_EQUAL
  738.                 || GetTok(tok) != TOK_ALPHANUM) {
  739.                 FileLine;
  740.                 fprintf( stderr, "expect TYPE=type\n" );
  741.                 farfree( p3->name );
  742.                 farfree( p3 );
  743.                 SkipTokRest;
  744.                 }
  745.             for (p3->type = chip; p3->type;
  746.                 p3->type = p3->type->next)
  747.                 if (same( token, p3->type->type ))
  748.                     break;
  749.             if (!(p3->type)) {
  750.                 FileLine;
  751.                 fprintf( stderr,
  752.                     "couldn't find chip type\n" );
  753.                 farfree( p3->name );
  754.                 farfree( p3 );
  755.                 SkipTokRest;
  756.                 }
  757.             if (GetTok(tok) != TOK_ORIENTATION
  758.                 || GetTok(tok) != TOK_EQUAL
  759.                 || (GetTok(tok) != TOK_NORMAL
  760.                 && tok != TOK_UP && tok != TOK_DOWN
  761.                 && tok != TOK_UPSIDEDOWN)) {
  762.                 FileLine;
  763.                 fprintf( stderr,
  764.                     "expect ORIENTATION=orientation\n" );
  765.                 farfree( p3->name );
  766.                 farfree( p3 );
  767.                 SkipTokRest;
  768.                 }
  769.             switch (tok) {
  770.             case TOK_NORMAL:
  771.                 p3->orientation = ORIENT_NORMAL;    break;
  772.             case TOK_UP:
  773.                 p3->orientation = ORIENT_UP;        break;
  774.             case TOK_DOWN:
  775.                 p3->orientation = ORIENT_DOWN;      break;
  776.             case TOK_UPSIDEDOWN:
  777.                 p3->orientation = ORIENT_UPSIDEDOWN;    break;
  778.             default:
  779.                 FileLine;
  780.                 fprintf( stderr, "internal error\n" );
  781.                 exit( -1 );
  782.                 break;
  783.                 }
  784.             p3->next = chipat;
  785.             chipat = p3;
  786.             initinline( p3, file, line );
  787.             }        else if (tok == TOK_NEWLINE) {
  788.             line++;
  789.             continue;
  790.             }
  791.         else { /* something unexpected */
  792.             FileLine;
  793.             fprintf( stderr, "syntax error: unexpected input\n" );
  794.             }
  795.         if (GetTok(tok) != TOK_EOF
  796.             && tok != TOK_NEWLINE) {
  797.             FileLine;
  798.             fprintf( stderr,
  799.                 "syntax error: expected end of line\n" );
  800.             SkipRest;
  801.             }
  802.         else if (tok == TOK_NEWLINE)
  803.             line++;
  804.         }
  805.     return( tot );
  806.     }
  807.  
  808. static void initchip ( p, file, line ) /* init chip definition (make holes) */
  809.     struct instance far *p;
  810.     char *file;
  811.     int line;
  812.     {
  813.     int r, c, pin;
  814.     struct template far *t;
  815.  
  816.     pin = 1;
  817.     r = p->row;
  818.     c = p->column;
  819.     t = p->type;
  820.     /* should check for neighboring holes (warning if so) */
  821.     switch (p->orientation) {
  822.     case ORIENT_NORMAL:
  823.         while (pin <= t->pins / 2) {
  824.             SetCell( r-1, c-1, TOP, HOLE );
  825.             SetCell( r-1, c-1, BOTTOM, HOLE );
  826.             pin++;
  827.             c += t->horizontal;
  828.             }
  829.         c -= t->horizontal;
  830.         r += t->vertical;
  831.         while (pin <= t->pins) {
  832.             SetCell( r-1, c-1, TOP, HOLE );
  833.             SetCell( r-1, c-1, BOTTOM, HOLE );
  834.             pin++;
  835.             c -= t->horizontal;
  836.             }
  837.         break;
  838.     case ORIENT_UP:
  839.         while (pin <= t->pins / 2) {
  840.             SetCell( r-1, c-1, TOP, HOLE );
  841.             SetCell( r-1, c-1, BOTTOM, HOLE );
  842.             pin++;
  843.             r += t->horizontal;
  844.             }
  845.         r -= t->horizontal;
  846.         c -= t->vertical;
  847.         while (pin <= t->pins) {
  848.             SetCell( r-1, c-1, TOP, HOLE );
  849.             SetCell( r-1, c-1, BOTTOM, HOLE );
  850.             pin++;
  851.             r -= t->horizontal;
  852.             }
  853.         break;
  854.     case ORIENT_DOWN:
  855.         while (pin <= t->pins / 2) {
  856.             SetCell( r-1, c-1, TOP, HOLE );
  857.             SetCell( r-1, c-1, BOTTOM, HOLE );
  858.             pin++;
  859.             r -= t->horizontal;
  860.             }
  861.         r += t->horizontal;
  862.         c += t->vertical;
  863.         while (pin <= t->pins) {
  864.             SetCell( r-1, c-1, TOP, HOLE );
  865.             SetCell( r-1, c-1, BOTTOM, HOLE );
  866.             pin++;
  867.             r += t->horizontal;
  868.             }
  869.         break;
  870.     case ORIENT_UPSIDEDOWN:
  871.         while (pin <= t->pins / 2) {
  872.             SetCell( r-1, c-1, TOP, HOLE );
  873.             SetCell( r-1, c-1, BOTTOM, HOLE );
  874.             pin++;
  875.             c -= t->horizontal;
  876.             }
  877.         c += t->horizontal;
  878.         r -= t->vertical;
  879.         while (pin <= t->pins) {
  880.             SetCell( r-1, c-1, TOP, HOLE );
  881.             SetCell( r-1, c-1, BOTTOM, HOLE );
  882.             pin++;
  883.             c += t->horizontal;
  884.             }
  885.         break;
  886.     default:
  887.         FileLine;
  888.         fprintf( stderr, "internal error: unexpected orientation\n" );
  889.         exit( -1 );
  890.         break;
  891.         }
  892.     }
  893.  
  894. static void initinline( p, file, line ) /* init inline definition (make holes) */
  895.     struct instance far *p;
  896.     char *file;
  897.     int line;
  898.     {
  899.     int r, c, pin;
  900.     struct template far *t;
  901.  
  902.     pin = 1;
  903.     r = p->row;
  904.     c = p->column;
  905.     t = p->type;
  906.     /* should check for neighboring holes (warning if so) */
  907.     switch (p->orientation) {
  908.     case ORIENT_NORMAL:
  909.         while (pin <= t->pins) {
  910.             SetCell( r-1, c-1, TOP, HOLE );
  911.             SetCell( r-1, c-1, BOTTOM, HOLE );
  912.             pin++;
  913.             c += t->horizontal;
  914.             }
  915.         break;
  916.     case ORIENT_UP:
  917.         while (pin <= t->pins) {
  918.             SetCell( r-1, c-1, TOP, HOLE );
  919.             SetCell( r-1, c-1, BOTTOM, HOLE );
  920.             pin++;
  921.             r += t->horizontal;
  922.             }
  923.         break;
  924.     case ORIENT_DOWN:
  925.         while (pin <= t->pins) {
  926.             SetCell( r-1, c-1, TOP, HOLE );
  927.             SetCell( r-1, c-1, BOTTOM, HOLE );
  928.             pin++;
  929.             r -= t->horizontal;
  930.             }
  931.         break;
  932.     case ORIENT_UPSIDEDOWN:
  933.         while (pin <= t->pins) {
  934.             SetCell( r-1, c-1, TOP, HOLE );
  935.             SetCell( r-1, c-1, BOTTOM, HOLE );
  936.             pin++;
  937.             c -= t->horizontal;
  938.             }
  939.         break;
  940.     default:
  941.         FileLine;
  942.         fprintf( stderr, "internal error: unexpected orientation\n" );
  943.         exit( -1 );
  944.         break;
  945.         }
  946.     }
  947.  
  948. static void locate ( p, r, c, file, line )
  949.     /* find location of name1.{name2,number} */
  950.     char *p;
  951.     int *r, *c;
  952.     char *file;
  953.     int line;
  954.     {
  955.     char *q;
  956.     int i;
  957.     struct instance far *s;
  958.     struct pinassign far *t;
  959.  
  960.     if (!(q = strchr( p, '.' ))) {
  961.         FileLine;
  962.         fprintf( stderr, "expect name1.{name2,number}\n" );
  963.         return;
  964.         }
  965.     *q++ = 0; /* separate into two parts & point at second part */
  966.     for (s = chipat; s; s = s->next) /* find proper chip */
  967.         if (same( p, s->name ))
  968.             break;
  969.     if (!s || !(s->type)) {
  970.         FileLine;
  971.         fprintf( stderr, "can't find chip or chip type\n" );
  972.         return;
  973.         }
  974.     if (isdigit( *q )) { /* get pin number */
  975.         i = atoi( q );
  976.         if (i <= 0 || i > s->type->pins) {
  977.             FileLine;
  978.             fprintf( stderr, "pin out of range\n" );
  979.             return;
  980.             }
  981.         }
  982.     else { /* get index of named pin via the template */
  983.         for (t = s->type->pinlist; t; t = t->next)
  984.             if (same( q, t->name ))
  985.                 break;
  986.         if (!t) {
  987.             FileLine;
  988.             fprintf( stderr, "can't find pin\n" );
  989.             return;
  990.             }
  991.         i = t->index;
  992.         }
  993.     *r = s->row;
  994.     *c = s->column;
  995.     if( ( s->type->vertical != 0 ) && ( s->type->horizontal != 0 ) )
  996.         {
  997.         switch (s->orientation) {
  998.         case ORIENT_NORMAL:
  999.             if ((i <= s->type->pins / 2) || (s->type->vertical == 0))
  1000.                 *c += (i-1) * s->type->horizontal;
  1001.             else {
  1002.                 *r += s->type->vertical;
  1003.                 *c += (s->type->pins - i) * s->type->horizontal;
  1004.                 }
  1005.             break;
  1006.         case ORIENT_UP:
  1007.             if ((i <= s->type->pins / 2) || (s->type->vertical == 0))
  1008.                 *r += (i-1) * s->type->horizontal;
  1009.             else {
  1010.                 *c -= s->type->vertical;
  1011.                 *r += (s->type->pins - i) * s->type->horizontal;
  1012.                 }
  1013.             break;
  1014.         case ORIENT_DOWN:
  1015.             if ((i <= s->type->pins / 2) || (s->type->vertical == 0))
  1016.                 *r -= (i-1) * s->type->horizontal;
  1017.             else {
  1018.                 *c += s->type->vertical;
  1019.                 *r -= (s->type->pins - i) * s->type->horizontal;
  1020.                 }
  1021.             break;
  1022.         case ORIENT_UPSIDEDOWN:
  1023.             if ((i <= s->type->pins / 2) || (s->type->vertical == 0))
  1024.                 *c -= (i-1) * s->type->horizontal;
  1025.             else {
  1026.                 *r -= s->type->vertical;
  1027.                 *c -= (s->type->pins - i) * s->type->horizontal;
  1028.                 }
  1029.             break;
  1030.         default:
  1031.             FileLine;
  1032.             fprintf( stderr, "internal error: unexpected orientation\n" );
  1033.             exit( -1 );
  1034.             break;
  1035.             }
  1036.         }
  1037.     else
  1038.         {
  1039.         switch (s->orientation) {
  1040.         case ORIENT_NORMAL:
  1041.             if ((i <= s->type->pins / 2) || (s->type->vertical == 0))
  1042.                 *c += (i-1) * s->type->horizontal;
  1043.             else {
  1044.                 *r += s->type->vertical;
  1045.                 *c += (s->type->pins - i) * s->type->horizontal;
  1046.                 }
  1047.             break;
  1048.         case ORIENT_UP:
  1049.             if ((i <= s->type->pins / 2) || (s->type->vertical == 0))
  1050.                 *r += (i-1) * s->type->horizontal;
  1051.             else {
  1052.                 *c -= s->type->vertical;
  1053.                 *r += (s->type->pins - i) * s->type->horizontal;
  1054.                 }
  1055.             break;
  1056.         case ORIENT_DOWN:
  1057.             if ((i <= s->type->pins / 2) || (s->type->vertical == 0))
  1058.                 *r -= (i-1) * s->type->horizontal;
  1059.             else {
  1060.                 *c += s->type->vertical;
  1061.                 *r -= (s->type->pins - i) * s->type->horizontal;
  1062.                 }
  1063.             break;
  1064.         case ORIENT_UPSIDEDOWN:
  1065.             if ((i <= s->type->pins / 2) || (s->type->vertical == 0))
  1066.                 *c -= (i-1) * s->type->horizontal;
  1067.             else {
  1068.                 *r -= s->type->vertical;
  1069.                 *c -= (s->type->pins - i) * s->type->horizontal;
  1070.                 }
  1071.             break;
  1072.         default:
  1073.             FileLine;
  1074.             fprintf( stderr, "internal error: unexpected orientation\n" );
  1075.             exit( -1 );
  1076.             break;
  1077.             }
  1078.  
  1079.         }
  1080.     *--q = '.'; /* put back the separator */
  1081.     }
  1082.  
  1083. static int gettoken ( fp, file, line )
  1084.     /* get next token into token[], return value */
  1085.     FILE *fp;
  1086.     char *file;
  1087.     int line;
  1088.     {
  1089.     int ch, i;
  1090.  
  1091.     /* burn whitespace */
  1092.     while ((ch = getc( fp )) == ' ' || ch == '\t')
  1093.         ;
  1094.     if (ch == EOF)
  1095.         return( TOK_EOF );
  1096.     else if (ch == '\n')
  1097.         return( TOK_NEWLINE );
  1098.     else if (ch == ';') { /* comment; burn to end of line */
  1099.         while ((ch = getc( fp )) != EOF && ch != '\n')
  1100.             ;
  1101.         return( (ch == '\n') ? TOK_NEWLINE : TOK_EOF );
  1102.         }
  1103.     else if (ch == '=')
  1104.         return( TOK_EQUAL );
  1105.     else if (isdigit( ch )) { /* a number; move it to the buffer */
  1106.         i = 0;
  1107.         do {
  1108.             if (i < MAXTOK-1)
  1109.                 token[i++] = (char)ch;
  1110.             ch = getc( fp );
  1111.             } while (isdigit( ch ));
  1112.         token[i] = 0;
  1113.         if (ch != EOF)
  1114.             ungetc( ch, fp );
  1115.         return( TOK_NUMBER );
  1116.         }
  1117.     else if (isalpha( ch ) || ch == '.' || ch == '\\') {
  1118.         /* a name; move it to the buffer */
  1119.         i = 0;
  1120.         do {
  1121.             if (i < MAXTOK-1)
  1122.                 token[i++] = (char)ch;
  1123.             ch = getc( fp );
  1124.             } while (isalnum( ch ) || ch == ':' || ch == '.'
  1125.                 || ch == '\\');
  1126.         token[i] = 0;
  1127.         if (ch != EOF)
  1128.             ungetc( ch, fp );
  1129.         /* try to identify it as a reserved word */
  1130.         for (i = 0; i < numres; i++) /* search table */
  1131.             if (!stricmp( tokenmatch[i].tokenname, token ))
  1132.                 return( tokenmatch[i].tokenvalue );
  1133.         /* it's not a reserved word; just return it */
  1134.         strupr( token );
  1135.         return( TOK_ALPHANUM );
  1136.         }
  1137.     else if (ch == '(') { /* "(row,column)", move it to the buffer */
  1138.         token[0] = (char)ch;
  1139.         i = 1;
  1140.         while ((ch = getc( fp )) == ' ' || ch == '\t')
  1141.             ;
  1142.         if (!isdigit( ch )) {
  1143.             FileLine;
  1144.             fprintf( stderr, "syntax error: expected digit\n" );
  1145.             exit( -1 );
  1146.             }
  1147.         do {
  1148.             if (i < MAXTOK-1)
  1149.                 token[i++] = (char)ch;
  1150.             ch = getc( fp );
  1151.             } while (isdigit( ch ));
  1152.         while (ch == ' ' || ch == '\t')
  1153.             ch = getc( fp );
  1154.         if (ch != ',') {
  1155.             FileLine;
  1156.             fprintf( stderr, "syntax error: expected comma\n" );
  1157.             exit( -1 );
  1158.             }
  1159.         if (i < MAXTOK-1)
  1160.             token[i++] = (char)ch;
  1161.         while ((ch = getc( fp )) == ' ' || ch == '\t')
  1162.             ;
  1163.         if (!isdigit( ch )) {
  1164.             FileLine;
  1165.             fprintf( stderr, "syntax error: expected digit\n" );
  1166.             exit( -1 );
  1167.             }
  1168.         do {
  1169.             if (i < MAXTOK-1)
  1170.                 token[i++] = (char)ch;
  1171.             ch = getc( fp );
  1172.             } while (isdigit( ch ));
  1173.         while (ch == ' ' || ch == '\t')
  1174.             ch = getc( fp );
  1175.         if (ch != ')') {
  1176.             FileLine;
  1177.             fprintf( stderr,
  1178.                 "syntax error: expected right paren\n" );
  1179.             exit( -1 );
  1180.             }
  1181.         if (i < MAXTOK-1)
  1182.             token[i++] = (char)ch;
  1183.         token[i] = 0;
  1184.         return( TOK_ROWCOLUMN );
  1185.         }
  1186.     else {
  1187.         FileLine;
  1188.         fprintf( stderr, "syntax error: unrecognized token\n" );
  1189.         exit( -1 );
  1190.         }
  1191.     }
  1192.  
  1193. static char far *fcopy ( p ) /* return ptr to far string copy */
  1194.     char *p;
  1195.     {
  1196.     char far *q;
  1197.     char far *r;
  1198.  
  1199.     if (!(q = r = farmalloc( strlen( p ) + 1 )))
  1200.         Nomem();
  1201.     while (*r++ = *p++) /* copy string */
  1202.         ;
  1203.     return( q );
  1204.     }
  1205.  
  1206. static int same ( p, q ) /* return 1 if far strings are identical, else 0 */
  1207.     char far *p;
  1208.     char far *q;
  1209.     {
  1210.     while (*p && *p == *q) { /* compare bytes until mismatch or end */
  1211.         p++;
  1212.         q++;
  1213.         }
  1214.     return( (*p || *q) ? 0 : 1 );
  1215.     }
  1216.  
  1217. void Report ( fp ) /* output routed board */
  1218.     FILE *fp;
  1219.     {
  1220.     int r, c;
  1221.     char b;
  1222.     long x;
  1223.  
  1224.     printf( "Enter Report()\n" );
  1225.     /* output dimensions first */
  1226.     b = (char)Nrows;    putc( b, fp );
  1227.     b = (char)(Nrows>>8);    putc( b, fp );
  1228.     b = (char)Ncols;    putc( b, fp );
  1229.     b = (char)(Ncols>>8);    putc( b, fp );
  1230.     /* now do rows and columns */
  1231.     for (r = 0; r < Nrows; r++)
  1232.         for (c = 0; c < Ncols; c++) {
  1233.             x = GetCell( r, c, TOP ); /* first do frontside */
  1234.             b = (char)x;        putc( b, fp );
  1235.             b = (char)(x>>8);    putc( b, fp );
  1236.             b = (char)(x>>16);    putc( b, fp );
  1237.             b = (char)(x>>24);    putc( b, fp );
  1238.             x = GetCell( r, c, BOTTOM ); /* then do backside */
  1239.             b = (char)x;        putc( b, fp );
  1240.             b = (char)(x>>8);    putc( b, fp );
  1241.             b = (char)(x>>16);    putc( b, fp );
  1242.             b = (char)(x>>24);    putc( b, fp );
  1243.             }
  1244.     if (ferror( fp ))
  1245.         fprintf( stderr, "output error; disk might be full\n" );
  1246.     printf( "Exit Report()\n" );
  1247.     }
  1248.