home *** CD-ROM | disk | FTP | other *** search
/ HAM Radio 1 / HamRadio.cdr / tech / pcbsrcs2 / io.c < prev    next >
C/C++ Source or Header  |  1991-02-07  |  28KB  |  1,015 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. **
  72. **      NORMAL           UP           DOWN        UPSIDEDOWN
  73. **
  74. **       6 5 4          +---+         +---+          3 2 1
  75. **     +-*-*-*-+      4 *   * 3     1 * | * 6      +-*-*-*-+
  76. **     |  ->   |      5 * ^ * 2     2 * v * 5      |   <-  |
  77. **     +-*-*-*-+      6 * | * 1     3 *   * 4      +-*-*-*-+
  78. **       1 2 3          +---+         +---+          4 5 6
  79. **
  80. **     usually the highest-numbered pin (pin N) is Vcc (power) and the pin
  81. **     farthest from it (pin N/2) is GND (ground).
  82. */
  83.  
  84. /* chip orientations (rotations) */
  85. #define ORIENT_NORMAL        1
  86. #define ORIENT_UP        2
  87. #define ORIENT_DOWN        3
  88. #define ORIENT_UPSIDEDOWN    4
  89.  
  90. /* input token types */
  91. #define TOK_EOF        1    /* end of file, no more tokens        */
  92. #define TOK_NEWLINE    2    /* end of line                */
  93. #define TOK_NUMBER    3    /* number (digits)            */
  94. #define TOK_HOLE    4    /* "HOLE"                */
  95. #define TOK_ROWCOLUMN    5    /* "(row,column)"            */
  96. #define TOK_CONNECT    6    /* "CONNECT"                */
  97. #define TOK_EQUAL    7    /* "="                    */
  98. #define TOK_AND        8    /* "AND"                */
  99. #define TOK_ALPHANUM    9    /* name (letters, digits, ':','.','\')    */
  100. #define TOK_CHIP    10    /* "CHIP"                */
  101. #define TOK_NAME    11    /* "NAME"                */
  102. #define TOK_PINS    12    /* "PINS"                */
  103. #define TOK_HORIZONTAL    13    /* "HORIZONTAL"                */
  104. #define TOK_VERTICAL    14    /* "VERTICAL"                */
  105. #define TOK_INCLUDE    15    /* "INCLUDE"                */
  106. #define TOK_CHIPAT    16    /* "CHIPAT"                */
  107. #define TOK_TYPE    17    /* "TYPE"                */
  108. #define TOK_ORIENTATION    18    /* "ORIENTATION"            */
  109. #define TOK_NORMAL    19    /* "NORMAL"                */
  110. #define TOK_UP        20    /* "UP"                    */
  111. #define TOK_DOWN    21    /* "DOWN"                */
  112. #define TOK_UPSIDEDOWN    22    /* "UPSIDEDOWN"                */
  113. #define TOK_DIMENSION    23    /* "DIMENSION"                */
  114. #define TOK_PRIORITY    24    /* "PRIORITY"                */
  115. #define TOK_TO        25    /* "TO"                    */
  116.  
  117. struct reserved { /* reserved word input tokens */
  118.     char *tokenname;
  119.     int tokenvalue;
  120.     };
  121.  
  122. static struct reserved tokenmatch[] = { /* reserved word table */
  123.   { "HOLE",       TOK_HOLE       },  { "CONNECT",     TOK_CONNECT     },
  124.   { "AND",        TOK_AND        },  { "CHIP",        TOK_CHIP        },
  125.   { "NAME",       TOK_NAME       },  { "PINS",        TOK_PINS        },
  126.   { "HORIZONTAL", TOK_HORIZONTAL },  { "VERTICAL",    TOK_VERTICAL    },
  127.   { "INCLUDE",    TOK_INCLUDE    },  { "CHIPAT",      TOK_CHIPAT      },
  128.   { "TYPE",       TOK_TYPE       },  { "ORIENTATION", TOK_ORIENTATION },
  129.   { "NORMAL",     TOK_NORMAL     },  { "UP",          TOK_UP          },
  130.   { "DOWN",       TOK_DOWN       },  { "UPSIDEDOWN",  TOK_UPSIDEDOWN  },
  131.   { "DIMENSION",  TOK_DIMENSION  },  { "PRIORITY",    TOK_PRIORITY    },
  132.   { "TO",         TOK_TO         }
  133.  };
  134.  
  135. #define MAXTOK    80    /* maximum token length (including null) */
  136.  
  137. static int numres = sizeof(tokenmatch) / sizeof(tokenmatch[0]);
  138. static char token[MAXTOK]; /* the current token is formed here */
  139.  
  140. struct pinassign { /* for assigning names to pins */
  141.     int            index;
  142.     char far        *name;
  143.     struct pinassign far    *next;
  144.     };
  145.  
  146. struct template { /* for "CHIP" declarations */
  147.     char far        *type;
  148.     int            pins;
  149.     int            horizontal;
  150.     int            vertical;
  151.     struct pinassign far    *pinlist;
  152.     struct template far    *next;
  153.     };
  154.  
  155. struct instance { /* for "CHIPAT" definitions */
  156.     int            row;
  157.     int            column;
  158.     char far        *name;
  159.     struct template far    *type;
  160.     int            orientation;
  161.     struct instance far    *next;
  162.     };
  163.  
  164. static struct template far *chip = NULL; /* list of CHIPs */
  165. static struct instance far *chipat = NULL; /* list of CHIPATs */
  166.  
  167. extern void InitBoard( void );
  168. extern long GetCell( int, int, int );
  169. extern void SetCell( int, int, int, long );
  170. extern void InitWork( void );
  171. extern void SetWork( int, int, char far *, int, int, char far *, int );
  172. extern void SortWork( void );
  173. extern void Nomem( void );
  174.  
  175. int Initialize( char *, int );
  176. static int initfile( FILE *, char * );
  177. static void initchip( struct instance far *, char *, int );
  178. static void locate( char *, int *, int *, char *, int );
  179. static int gettoken( FILE *, char *, int );
  180. static char far *fcopy( char * );
  181. static int same( char far *, char far * );
  182. void Report( FILE * );
  183.  
  184. int Initialize ( file, echo ) /* get hole coordinates and connections */
  185.     char *file;
  186.     int echo;
  187.     {
  188.     FILE *fp;
  189.     int tot;
  190.  
  191.     if (echo)
  192.         printf( "Enter Initialize()\n" );
  193.     if (!(fp = fopen( file, "r" ))) {
  194.         fprintf( stderr, "can't open %s\n", file );
  195.         exit( -1 );
  196.         }
  197.     InitWork(); /* clear work list */
  198.     tot = initfile( fp, file ); /* read input file(s) */
  199.     if (SortConnects)
  200.         SortWork(); /* arrange to do shortest ones first */
  201.     if (echo) {
  202.         printf( "  %lu bytes used for Board\n", Ltotal );
  203.         printf( "  %lu bytes used for Dist\n", Itotal );
  204.         printf( "  %lu bytes used for Dir\n", Ctotal );
  205.         printf( "Exit Initialize()\n" );
  206.         }
  207.     if (fclose( fp ))
  208.         fprintf( stderr, "error closing %s\n", file );
  209.     return( tot );
  210.     }
  211.  
  212. /* some useful macros (common code sequences) */
  213.  
  214. #define FileLine    { fprintf( stderr, "%s(%d): ", file, line ); }
  215.  
  216. #define GetTok(tok)    ((tok) = gettoken( fp, file, line ))
  217.  
  218. #define SkipRest    { while (GetTok(tok) != TOK_EOF \
  219.                 && tok != TOK_NEWLINE) ; \
  220.             if (tok == TOK_NEWLINE) line++; }
  221.  
  222. #define SkipTokRest    { while (tok != TOK_EOF && tok != TOK_NEWLINE) \
  223.                 GetTok(tok); } \
  224.             if (tok == TOK_NEWLINE) line++; \
  225.             continue;
  226.  
  227. #define CheckInit    { if (!InitBoardDone) { \
  228.                 FileLine; \
  229.                 fprintf( stderr, "need dimensions first\n" ); \
  230.                 SkipRest; \
  231.                 continue; } }
  232.  
  233. static int initfile ( fp, file ) /* read and process input file(s) */
  234.     FILE *fp;
  235.     char *file;
  236.     {
  237.     int tok, r1, c1, r2, c2, i, line;
  238.     char far *p;
  239.     char far *n1;
  240.     char far *n2;
  241.     long cell;
  242.     struct template far *p1;
  243.     struct pinassign far *p2;
  244.     struct pinassign far *p22;
  245.     struct instance far *p3;
  246.     FILE *fnew;
  247.     char *fname;
  248.     int tot = 0;
  249.  
  250.     line = 1;
  251.     while (GetTok(tok) != TOK_EOF) {
  252.         if (tok == TOK_DIMENSION) {
  253.             if (InitBoardDone) { /* can only do it once */
  254.                 FileLine;
  255.                 fprintf( stderr,
  256.                     "redundant dimensions\n" );
  257.                 SkipRest;
  258.                 continue;
  259.                 }
  260.             if (GetTok(tok) != TOK_ROWCOLUMN) {
  261.                 FileLine;
  262.                 fprintf( stderr, "expect (row,column)\n" );
  263.                 SkipTokRest;
  264.                 }
  265.             sscanf( token, "(%d,%d)", &Nrows, &Ncols );
  266.             if (Nrows <= 0 || Ncols <= 0) {
  267.                 FileLine;
  268.                 fprintf( stderr, "dimension error\n" );
  269.                 }
  270.             else /* allocate memory for data structures */
  271.                 InitBoard();
  272.             }
  273.         else if (tok == TOK_HOLE) {
  274.             CheckInit; /* must get dimensions first */
  275.             if (GetTok(tok) != TOK_ROWCOLUMN) {
  276.                 FileLine;
  277.                 fprintf( stderr, "expect (row,column)\n" );
  278.                 SkipTokRest;
  279.                 }
  280.             sscanf( token, "(%d,%d)", &r1, &c1 );
  281.             if (r1 <= 0 || r1 > Nrows || c1 <= 0 || c1 > Ncols) {
  282.                 FileLine;
  283.                 fprintf( stderr, "out of range\n" );
  284.                 }
  285.             else { /* position the hole on the board */
  286.                 /* should check for neighbor holes (error) */
  287.                 SetCell( r1-1, c1-1, TOP, HOLE );
  288.                 SetCell( r1-1, c1-1, BOTTOM, HOLE );
  289.                 }
  290.             }
  291.         else if (tok == TOK_CONNECT) {
  292.             CheckInit; /* must get dimensions first */
  293.             if (GetTok(tok) == TOK_ROWCOLUMN)
  294.                 sscanf( token, "(%d,%d)", &r1, &c1 );
  295.             else if (tok == TOK_ALPHANUM)
  296.                 locate( token, &r1, &c1, file, line );
  297.             else {
  298.                 FileLine;
  299.                 fprintf( stderr,
  300.                     "expect (row,column) or name\n" );
  301.                 SkipTokRest;
  302.                 }
  303.             n1 = fcopy( token );
  304.             if (GetTok(tok) != TOK_EQUAL
  305.                 && tok != TOK_AND && tok != TOK_TO) {
  306.                 FileLine;
  307.                 fprintf( stderr, "expect = or AND or TO\n" );
  308.                 SkipTokRest;
  309.                 }
  310.             if (GetTok(tok) == TOK_ROWCOLUMN)
  311.                 sscanf( token, "(%d,%d)", &r2, &c2 );
  312.             else if (tok == TOK_ALPHANUM)
  313.                 locate( token, &r2, &c2, file, line );
  314.             else {
  315.                 FileLine;
  316.                 fprintf( stderr,
  317.                     "expect (row,column) or name\n" );
  318.                 SkipTokRest;
  319.                 }
  320.             n2 = fcopy( token );
  321.             if (r1 <= 0 || r1 > Nrows || r2 <= 0 || r2 > Nrows
  322.                 || c1 <= 0 || c1 > Ncols
  323.                 || c2 <= 0 || c2 > Ncols) {
  324.                 FileLine;
  325.                 fprintf( stderr, "out of range\n" );
  326.                 _ffree( n1 );
  327.                 _ffree( n2 );
  328.                 }
  329.             else {
  330.                 cell = GetCell( r1-1, c1-1, TOP );
  331.                 if (!(cell & HOLE)) {
  332.                     FileLine;
  333.                     fprintf( stderr, "no source hole\n" );
  334.                     _ffree( n1 );
  335.                     _ffree( n2 );
  336.                     SkipRest;
  337.                     continue;
  338.                     }
  339.                 cell = GetCell( r2-1, c2-1, TOP );
  340.                 if (!(cell & HOLE)) {
  341.                     FileLine;
  342.                     fprintf( stderr, "no target hole\n" );
  343.                     _ffree( n1 );
  344.                     _ffree( n2 );
  345.                     SkipRest;
  346.                     continue;
  347.                     }
  348.                 SetWork( r1-1, c1-1, n1, r2-1, c2-1, n2, 0 );
  349.                 tot++;
  350.                 }
  351.             }
  352.         else if (tok == TOK_PRIORITY) {
  353.             CheckInit; /* must get dimensions first */
  354.             if (GetTok(tok) != TOK_CONNECT) {
  355.                 FileLine;
  356.                 fprintf( stderr, "expect CONNECT\n" );
  357.                 SkipTokRest;
  358.                 }
  359.             if (GetTok(tok) == TOK_ROWCOLUMN)
  360.                 sscanf( token, "(%d,%d)", &r1, &c1 );
  361.             else if (tok == TOK_ALPHANUM)
  362.                 locate( token, &r1, &c1, file, line );
  363.             else {
  364.                 FileLine;
  365.                 fprintf( stderr,
  366.                     "expect (row,column) or name\n" );
  367.                 SkipTokRest;
  368.                 }
  369.             n1 = fcopy( token );
  370.             if (GetTok(tok) != TOK_EQUAL
  371.                 && tok != TOK_AND && tok != TOK_TO) {
  372.                 FileLine;
  373.                 fprintf( stderr, "expect = or AND or TO\n" );
  374.                 SkipTokRest;
  375.                 }
  376.             if (GetTok(tok) == TOK_ROWCOLUMN)
  377.                 sscanf( token, "(%d,%d)", &r2, &c2 );
  378.             else if (tok == TOK_ALPHANUM)
  379.                 locate( token, &r2, &c2, file, line );
  380.             else {
  381.                 FileLine;
  382.                 fprintf( stderr,
  383.                     "expect (row,column) or name\n" );
  384.                 SkipTokRest;
  385.                 }
  386.             n2 = fcopy( token );
  387.             if (r1 <= 0 || r1 > Nrows || r2 <= 0 || r2 > Nrows
  388.                 || c1 <= 0 || c1 > Ncols
  389.                 || c2 <= 0 || c2 > Ncols) {
  390.                 FileLine;
  391.                 fprintf( stderr, "out of range\n" );
  392.                 _ffree( n1 );
  393.                 _ffree( n2 );
  394.                 }
  395.             else {
  396.                 cell = GetCell( r1-1, c1-1, TOP );
  397.                 if (!(cell & HOLE)) {
  398.                     FileLine;
  399.                     fprintf( stderr, "no source hole\n" );
  400.                     _ffree( n1 );
  401.                     _ffree( n2 );
  402.                     SkipRest;
  403.                     continue;
  404.                     }
  405.                 cell = GetCell( r2-1, c2-1, TOP );
  406.                 if (!(cell & HOLE)) {
  407.                     FileLine;
  408.                     fprintf( stderr, "no target hole\n" );
  409.                     _ffree( n1 );
  410.                     _ffree( n2 );
  411.                     SkipRest;
  412.                     continue;
  413.                     }
  414.                 SetWork( r1-1, c1-1, n1, r2-1, c2-1, n2, 1 );
  415.                 tot++;
  416.                 }
  417.             }
  418.         else if (tok == TOK_INCLUDE) {
  419.             CheckInit; /* must get dimensions first */
  420.             if (GetTok(tok) != TOK_ALPHANUM) {
  421.                 FileLine;
  422.                 fprintf( stderr,
  423.                     "expect file name for INCLUDE\n" );
  424.                 SkipTokRest;
  425.                 }
  426.             if (!(fnew = fopen( token, "r" ))) {
  427.                 FileLine;
  428.                 fprintf( stderr,
  429.                     "can't open INCLUDE file %s\n",
  430.                     token );
  431.                 SkipRest;
  432.                 continue;
  433.                 }
  434.             if (!(fname = strdup( token )))
  435.                 Nomem();
  436.             if (GetTok(tok) != TOK_EOF
  437.                 && tok != TOK_NEWLINE) {
  438.                 FileLine;
  439.                 fprintf( stderr,
  440.                     "extra chars on INCLUDE line\n" );
  441.                 SkipRest;
  442.                 }
  443.             if (tok == TOK_NEWLINE)
  444.                 line++;
  445.             tot += initfile( fnew, fname ); /* recurse */
  446.             if (fclose( fnew )) {
  447.                 FileLine;
  448.                 fprintf( stderr,
  449.                     "error closing INCLUDE file\n" );
  450.                 }
  451.             free( fname );
  452.             continue; /* already ate the NEWLINE, if any */
  453.             }
  454.         else if (tok == TOK_CHIP) {
  455.             CheckInit; /* must get dimensions first */
  456.             if (GetTok(tok) != TOK_TYPE
  457.                 || GetTok(tok) != TOK_EQUAL
  458.                 || GetTok(tok) != TOK_ALPHANUM) {
  459.                 FileLine;
  460.                 fprintf( stderr, "expect TYPE=type\n" );
  461.                 SkipTokRest;
  462.                 }
  463.             if (!(p1 = (struct template far *)
  464.                 _fmalloc( sizeof(struct template) )))
  465.                 Nomem();
  466.             p1->type = fcopy( token );
  467.             if (GetTok(tok) != TOK_PINS
  468.                 || GetTok(tok) != TOK_EQUAL
  469.                 || GetTok(tok) != TOK_NUMBER) {
  470.                 FileLine;
  471.                 fprintf( stderr, "expect PINS=number\n" );
  472.                 _ffree( p1->type );
  473.                 _ffree( p1 );
  474.                 SkipTokRest;
  475.                 }
  476.             sscanf( token, "%d", &i );
  477.             p1->pins = i;
  478.             if ((p1->pins = i) < 0 || (i & 1)) {
  479.                 FileLine;
  480.                 fprintf( stderr, "PINS negative or odd\n" );
  481.                 }
  482.             if (GetTok(tok) != TOK_HORIZONTAL
  483.                 || GetTok(tok) != TOK_EQUAL
  484.                 || GetTok(tok) != TOK_NUMBER) {
  485.                 FileLine;
  486.                 fprintf( stderr,
  487.                     "expect HORIZONTAL=number\n" );
  488.                 _ffree( p1->type );
  489.                 _ffree( p1 );
  490.                 SkipTokRest;
  491.                 }
  492.             sscanf( token, "%d", &i );
  493.             if ((p1->horizontal = i) <= 0) {
  494.                 FileLine;
  495.                 fprintf( stderr, "HORIZONTAL nonpositive\n" );
  496.                 }
  497.             if (GetTok(tok) != TOK_VERTICAL
  498.                 || GetTok(tok) != TOK_EQUAL
  499.                 || GetTok(tok) != TOK_NUMBER) {
  500.                 FileLine;
  501.                 fprintf( stderr, "expect VERTICAL=number\n" );
  502.                 _ffree( p1->type );
  503.                 _ffree( p1 );
  504.                 SkipTokRest;
  505.                 }
  506.             sscanf( token, "%d", &i );
  507.             if ((p1->vertical = i) < 0) {
  508.                 FileLine;
  509.                 fprintf( stderr, "VERTICAL nonpositive\n" );
  510.                 }
  511.             p1->pinlist = NULL;
  512.             p1->next = chip;
  513.             chip = p1;
  514.             }
  515.         else if (tok == TOK_NUMBER) {
  516.             CheckInit; /* must get dimensions first */
  517.             if (!chip) {
  518.                 FileLine;
  519.                 fprintf( stderr, "no template\n" );
  520.                 SkipRest;
  521.                 continue;
  522.                 }
  523.             sscanf( token, "%d", &i );
  524.             if (GetTok(tok) != TOK_EQUAL
  525.                 || GetTok(tok) != TOK_ALPHANUM) {
  526.                 FileLine;
  527.                 fprintf( stderr, "expect number=name\n" );
  528.                 SkipTokRest;
  529.                 }
  530.             if (!(p2 = (struct pinassign far *)
  531.                 _fmalloc( sizeof(struct pinassign) )))
  532.                 Nomem();
  533.             p2->name = fcopy( token );
  534.             p2->index = i;
  535.             /* check uniqueness of name and index */
  536.             for (p22 = chip->pinlist; p22; p22 = p22->next)
  537.                 if (p22->index == i
  538.                     || same( p22->name, p )) {
  539.                     FileLine;
  540.                     fprintf( stderr,
  541.                         "warning: repeated pin\n" );
  542.                     break;
  543.                     }
  544.             p2->next = chip->pinlist;
  545.             chip->pinlist = p2;
  546.             }
  547.         else if (tok == TOK_ALPHANUM) {
  548.             CheckInit; /* must get dimensions first */
  549.             if (!chip) {
  550.                 FileLine;
  551.                 fprintf( stderr, "no template\n" );
  552.                 SkipRest;
  553.                 continue;
  554.                 }
  555.             p = fcopy( token );
  556.             if (GetTok(tok) != TOK_EQUAL
  557.                 || GetTok(tok) != TOK_NUMBER) {
  558.                 FileLine;
  559.                 fprintf( stderr, "expect name=number\n" );
  560.                 _ffree( p );
  561.                 SkipTokRest;
  562.                 }
  563.             sscanf( token, "%d", &i );
  564.             if (!(p2 = (struct pinassign far *)
  565.                 _fmalloc( sizeof(struct pinassign) )))
  566.                 Nomem();
  567.             p2->name = p;
  568.             p2->index = i;
  569.             /* check uniqueness of name and index */
  570.             for (p22 = chip->pinlist; p22; p22 = p22->next)
  571.                 if (p22->index == i
  572.                     || same( p22->name, p )) {
  573.                     FileLine;
  574.                     fprintf( stderr,
  575.                         "warning: repeated pin\n" );
  576.                     break;
  577.                     }
  578.             p2->next = chip->pinlist;
  579.             chip->pinlist = p2;
  580.             }
  581.         else if (tok == TOK_CHIPAT) {
  582.             CheckInit; /* must get dimensions first */
  583.             if (GetTok(tok) != TOK_ROWCOLUMN) {
  584.                 FileLine;
  585.                 fprintf( stderr, "expect (row,column)\n" );
  586.                 SkipTokRest;
  587.                 }
  588.             sscanf( token, "(%d,%d)", &r1, &c1 );
  589.             if (GetTok(tok) != TOK_NAME
  590.                 || GetTok(tok) != TOK_EQUAL
  591.                 || GetTok(tok) != TOK_ALPHANUM) {
  592.                 FileLine;
  593.                 fprintf( stderr, "expect NAME=name\n" );
  594.                 SkipTokRest;
  595.                 }
  596.             if (!(p3 = (struct instance far *)
  597.                 _fmalloc( sizeof(struct instance) )))
  598.                 Nomem();
  599.             p3->name = fcopy( token );
  600.             p3->row = r1;
  601.             p3->column = c1;
  602.             if (GetTok(tok) != TOK_TYPE
  603.                 || GetTok(tok) != TOK_EQUAL
  604.                 || GetTok(tok) != TOK_ALPHANUM) {
  605.                 FileLine;
  606.                 fprintf( stderr, "expect TYPE=type\n" );
  607.                 _ffree( p3->name );
  608.                 _ffree( p3 );
  609.                 SkipTokRest;
  610.                 }
  611.             for (p3->type = chip; p3->type;
  612.                 p3->type = p3->type->next)
  613.                 if (same( token, p3->type->type ))
  614.                     break;
  615.             if (!(p3->type)) {
  616.                 FileLine;
  617.                 fprintf( stderr,
  618.                     "couldn't find chip type\n" );
  619.                 _ffree( p3->name );
  620.                 _ffree( p3 );
  621.                 SkipTokRest;
  622.                 }
  623.             if (GetTok(tok) != TOK_ORIENTATION
  624.                 || GetTok(tok) != TOK_EQUAL
  625.                 || (GetTok(tok) != TOK_NORMAL
  626.                 && tok != TOK_UP && tok != TOK_DOWN
  627.                 && tok != TOK_UPSIDEDOWN)) {
  628.                 FileLine;
  629.                 fprintf( stderr,
  630.                     "expect ORIENTATION=orientation\n" );
  631.                 _ffree( p3->name );
  632.                 _ffree( p3 );
  633.                 SkipTokRest;
  634.                 }
  635.             switch (tok) {
  636.             case TOK_NORMAL:
  637.                 p3->orientation = ORIENT_NORMAL;    break;
  638.             case TOK_UP:
  639.                 p3->orientation = ORIENT_UP;        break;
  640.             case TOK_DOWN:
  641.                 p3->orientation = ORIENT_DOWN;        break;
  642.             case TOK_UPSIDEDOWN:
  643.                 p3->orientation = ORIENT_UPSIDEDOWN;    break;
  644.             default:
  645.                 FileLine;
  646.                 fprintf( stderr, "internal error\n" );
  647.                 exit( -1 );
  648.                 break;
  649.                 }
  650.             p3->next = chipat;
  651.             chipat = p3;
  652.             initchip( p3, file, line );
  653.             }
  654.         else if (tok == TOK_NEWLINE) {
  655.             line++;
  656.             continue;
  657.             }
  658.         else { /* something unexpected */
  659.             FileLine;
  660.             fprintf( stderr, "syntax error: unexpected input\n" );
  661.             }
  662.         if (GetTok(tok) != TOK_EOF
  663.             && tok != TOK_NEWLINE) {
  664.             FileLine;
  665.             fprintf( stderr,
  666.                 "syntax error: expected end of line\n" );
  667.             SkipRest;
  668.             }
  669.         else if (tok == TOK_NEWLINE)
  670.             line++;
  671.         }
  672.     return( tot );
  673.     }
  674.  
  675. static void initchip ( p, file, line ) /* init chip definition (make holes) */
  676.     struct instance far *p;
  677.     char *file;
  678.     int line;
  679.     {
  680.     int r, c, pin;
  681.     struct template far *t;
  682.  
  683.     pin = 1;
  684.     r = p->row;
  685.     c = p->column;
  686.     t = p->type;
  687.     /* should check for neighboring holes (warning if so) */
  688.     switch (p->orientation) {
  689.     case ORIENT_NORMAL:
  690.         while (pin <= t->pins / 2) {
  691.             SetCell( r-1, c-1, TOP, HOLE );
  692.             SetCell( r-1, c-1, BOTTOM, HOLE );
  693.             pin++;
  694.             c += t->horizontal;
  695.             }
  696.         c -= t->horizontal;
  697.         r += t->vertical;
  698.         while (pin <= t->pins) {
  699.             SetCell( r-1, c-1, TOP, HOLE );
  700.             SetCell( r-1, c-1, BOTTOM, HOLE );
  701.             pin++;
  702.             c -= t->horizontal;
  703.             }
  704.         break;
  705.     case ORIENT_UP:
  706.         while (pin <= t->pins / 2) {
  707.             SetCell( r-1, c-1, TOP, HOLE );
  708.             SetCell( r-1, c-1, BOTTOM, HOLE );
  709.             pin++;
  710.             r += t->horizontal;
  711.             }
  712.         r -= t->horizontal;
  713.         c -= t->vertical;
  714.         while (pin <= t->pins) {
  715.             SetCell( r-1, c-1, TOP, HOLE );
  716.             SetCell( r-1, c-1, BOTTOM, HOLE );
  717.             pin++;
  718.             r -= t->horizontal;
  719.             }
  720.         break;
  721.     case ORIENT_DOWN:
  722.         while (pin <= t->pins / 2) {
  723.             SetCell( r-1, c-1, TOP, HOLE );
  724.             SetCell( r-1, c-1, BOTTOM, HOLE );
  725.             pin++;
  726.             r -= t->horizontal;
  727.             }
  728.         r += t->horizontal;
  729.         c += t->vertical;
  730.         while (pin <= t->pins) {
  731.             SetCell( r-1, c-1, TOP, HOLE );
  732.             SetCell( r-1, c-1, BOTTOM, HOLE );
  733.             pin++;
  734.             r += t->horizontal;
  735.             }
  736.         break;
  737.     case ORIENT_UPSIDEDOWN:
  738.         while (pin <= t->pins / 2) {
  739.             SetCell( r-1, c-1, TOP, HOLE );
  740.             SetCell( r-1, c-1, BOTTOM, HOLE );
  741.             pin++;
  742.             c -= t->horizontal;
  743.             }
  744.         c += t->horizontal;
  745.         r -= t->vertical;
  746.         while (pin <= t->pins) {
  747.             SetCell( r-1, c-1, TOP, HOLE );
  748.             SetCell( r-1, c-1, BOTTOM, HOLE );
  749.             pin++;
  750.             c += t->horizontal;
  751.             }
  752.         break;
  753.     default:
  754.         FileLine;
  755.         fprintf( stderr, "internal error: unexpected orientation\n" );
  756.         exit( -1 );
  757.         break;
  758.         }
  759.     }
  760.  
  761. static void locate ( p, r, c, file, line )
  762.     /* find location of name1.{name2,number} */
  763.     char *p;
  764.     int *r, *c;
  765.     char *file;
  766.     int line;
  767.     {
  768.     char *q;
  769.     int i;
  770.     struct instance far *s;
  771.     struct pinassign far *t;
  772.  
  773.     if (!(q = strchr( p, '.' ))) {
  774.         FileLine;
  775.         fprintf( stderr, "expect name1.{name2,number}\n" );
  776.         return;
  777.         }
  778.     *q++ = 0; /* separate into two parts & point at second part */
  779.     for (s = chipat; s; s = s->next) /* find proper chip */
  780.         if (same( p, s->name ))
  781.             break;
  782.     if (!s || !(s->type)) {
  783.         FileLine;
  784.         fprintf( stderr, "can't find chip or chip type\n" );
  785.         return;
  786.         }
  787.     if (isdigit( *q )) { /* get pin number */
  788.         i = atoi( q );
  789.         if (i <= 0 || i > s->type->pins) {
  790.             FileLine;
  791.             fprintf( stderr, "pin out of range\n" );
  792.             return;
  793.             }
  794.         }
  795.     else { /* get index of named pin via the template */
  796.         for (t = s->type->pinlist; t; t = t->next)
  797.             if (same( q, t->name ))
  798.                 break;
  799.         if (!t) {
  800.             FileLine;
  801.             fprintf( stderr, "can't find pin\n" );
  802.             return;
  803.             }
  804.         i = t->index;
  805.         }
  806.     *r = s->row;
  807.     *c = s->column;
  808.     switch (s->orientation) {
  809.     case ORIENT_NORMAL:
  810.         if (i <= s->type->pins / 2)
  811.             *c += (i-1) * s->type->horizontal;
  812.         else {
  813.             *r += s->type->vertical;
  814.             *c += (s->type->pins - i) * s->type->horizontal;
  815.             }
  816.         break;
  817.     case ORIENT_UP:
  818.         if (i <= s->type->pins / 2)
  819.             *r += (i-1) * s->type->horizontal;
  820.         else {
  821.             *c -= s->type->vertical;
  822.             *r += (s->type->pins - i) * s->type->horizontal;
  823.             }
  824.         break;
  825.     case ORIENT_DOWN:
  826.         if (i <= s->type->pins / 2)
  827.             *r -= (i-1) * s->type->horizontal;
  828.         else {
  829.             *c += s->type->vertical;
  830.             *r -= (s->type->pins - i) * s->type->horizontal;
  831.             }
  832.         break;
  833.     case ORIENT_UPSIDEDOWN:
  834.         if (i <= s->type->pins / 2)
  835.             *c -= (i-1) * s->type->horizontal;
  836.         else {
  837.             *r -= s->type->vertical;
  838.             *c -= (s->type->pins - i) * s->type->horizontal;
  839.             }
  840.         break;
  841.     default:
  842.         FileLine;
  843.         fprintf( stderr, "internal error: unexpected orientation\n" );
  844.         exit( -1 );
  845.         break;
  846.         }
  847.     *--q = '.'; /* put back the separator */
  848.     }
  849.  
  850. static int gettoken ( fp, file, line )
  851.     /* get next token into token[], return value */
  852.     FILE *fp;
  853.     char *file;
  854.     int line;
  855.     {
  856.     int ch, i;
  857.  
  858.     /* burn whitespace */
  859.     while ((ch = getc( fp )) == ' ' || ch == '\t')
  860.         ;
  861.     if (ch == EOF)
  862.         return( TOK_EOF );
  863.     else if (ch == '\n')
  864.         return( TOK_NEWLINE );
  865.     else if (ch == ';') { /* comment; burn to end of line */
  866.         while ((ch = getc( fp )) != EOF && ch != '\n')
  867.             ;
  868.         return( (ch == '\n') ? TOK_NEWLINE : TOK_EOF );
  869.         }
  870.     else if (ch == '=')
  871.         return( TOK_EQUAL );
  872.     else if (isdigit( ch )) { /* a number; move it to the buffer */
  873.         i = 0;
  874.         do {
  875.             if (i < MAXTOK-1)
  876.                 token[i++] = (char)ch;
  877.             ch = getc( fp );
  878.             } while (isdigit( ch ));
  879.         token[i] = 0;
  880.         if (ch != EOF)
  881.             ungetc( ch, fp );
  882.         return( TOK_NUMBER );
  883.         }
  884.     else if (isalpha( ch ) || ch == '.' || ch == '\\') {
  885.         /* a name; move it to the buffer */
  886.         i = 0;
  887.         do {
  888.             if (i < MAXTOK-1)
  889.                 token[i++] = (char)ch;
  890.             ch = getc( fp );
  891.             } while (isalnum( ch ) || ch == ':' || ch == '.'
  892.                 || ch == '\\');
  893.         token[i] = 0;
  894.         if (ch != EOF)
  895.             ungetc( ch, fp );
  896.         /* try to identify it as a reserved word */
  897.         for (i = 0; i < numres; i++) /* search table */
  898.             if (!stricmp( tokenmatch[i].tokenname, token ))
  899.                 return( tokenmatch[i].tokenvalue );
  900.         /* it's not a reserved word; just return it */
  901.         strupr( token );
  902.         return( TOK_ALPHANUM );
  903.         }
  904.     else if (ch == '(') { /* "(row,column)", move it to the buffer */
  905.         token[0] = (char)ch;
  906.         i = 1;
  907.         while ((ch = getc( fp )) == ' ' || ch == '\t')
  908.             ;
  909.         if (!isdigit( ch )) {
  910.             FileLine;
  911.             fprintf( stderr, "syntax error: expected digit\n" );
  912.             exit( -1 );
  913.             }
  914.         do {
  915.             if (i < MAXTOK-1)
  916.                 token[i++] = (char)ch;
  917.             ch = getc( fp );
  918.             } while (isdigit( ch ));
  919.         while (ch == ' ' || ch == '\t')
  920.             ch = getc( fp );
  921.         if (ch != ',') {
  922.             FileLine;
  923.             fprintf( stderr, "syntax error: expected comma\n" );
  924.             exit( -1 );
  925.             }
  926.         if (i < MAXTOK-1)
  927.             token[i++] = (char)ch;
  928.         while ((ch = getc( fp )) == ' ' || ch == '\t')
  929.             ;
  930.         if (!isdigit( ch )) {
  931.             FileLine;
  932.             fprintf( stderr, "syntax error: expected digit\n" );
  933.             exit( -1 );
  934.             }
  935.         do {
  936.             if (i < MAXTOK-1)
  937.                 token[i++] = (char)ch;
  938.             ch = getc( fp );
  939.             } while (isdigit( ch ));
  940.         while (ch == ' ' || ch == '\t')
  941.             ch = getc( fp );
  942.         if (ch != ')') {
  943.             FileLine;
  944.             fprintf( stderr,
  945.                 "syntax error: expected right paren\n" );
  946.             exit( -1 );
  947.             }
  948.         if (i < MAXTOK-1)
  949.             token[i++] = (char)ch;
  950.         token[i] = 0;
  951.         return( TOK_ROWCOLUMN );
  952.         }
  953.     else {
  954.         FileLine;
  955.         fprintf( stderr, "syntax error: unrecognized token\n" );
  956.         exit( -1 );
  957.         }
  958.     }
  959.  
  960. static char far *fcopy ( p ) /* return ptr to far string copy */
  961.     char *p;
  962.     {
  963.     char far *q;
  964.     char far *r;
  965.  
  966.     if (!(q = r = _fmalloc( strlen( p ) + 1 )))
  967.         Nomem();
  968.     while (*r++ = *p++) /* copy string */
  969.         ;
  970.     return( q );
  971.     }
  972.  
  973. static int same ( p, q ) /* return 1 if far strings are identical, else 0 */
  974.     char far *p;
  975.     char far *q;
  976.     {
  977.     while (*p && *p == *q) { /* compare bytes until mismatch or end */
  978.         p++;
  979.         q++;
  980.         }
  981.     return( (*p || *q) ? 0 : 1 );
  982.     }
  983.  
  984. void Report ( fp ) /* output routed board */
  985.     FILE *fp;
  986.     {
  987.     int r, c;
  988.     char b;
  989.     long x;
  990.  
  991.     printf( "Enter Report()\n" );
  992.     /* output dimensions first */
  993.     b = (char)Nrows;    putc( b, fp );
  994.     b = (char)(Nrows>>8);    putc( b, fp );
  995.     b = (char)Ncols;    putc( b, fp );
  996.     b = (char)(Ncols>>8);    putc( b, fp );
  997.     /* now do rows and columns */
  998.     for (r = 0; r < Nrows; r++)
  999.         for (c = 0; c < Ncols; c++) {
  1000.             x = GetCell( r, c, TOP ); /* first do frontside */
  1001.             b = (char)x;        putc( b, fp );
  1002.             b = (char)(x>>8);    putc( b, fp );
  1003.             b = (char)(x>>16);    putc( b, fp );
  1004.             b = (char)(x>>24);    putc( b, fp );
  1005.             x = GetCell( r, c, BOTTOM ); /* then do backside */
  1006.             b = (char)x;        putc( b, fp );
  1007.             b = (char)(x>>8);    putc( b, fp );
  1008.             b = (char)(x>>16);    putc( b, fp );
  1009.             b = (char)(x>>24);    putc( b, fp );
  1010.             }
  1011.     if (ferror( fp ))
  1012.         fprintf( stderr, "output error; disk might be full\n" );
  1013.     printf( "Exit Report()\n" );
  1014.     }
  1015.