home *** CD-ROM | disk | FTP | other *** search
/ ARM Club 1 / ARM_CLUB_CD.iso / contents / education / a / autopcb / !AutoPCB / c / IO < prev    next >
Text File  |  1991-03-23  |  40KB  |  902 lines

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <ctype.h>
  5.  
  6. #include "heap.h"
  7. #include "dbox.h"
  8. #include "werr.h"
  9.  
  10. #include "cell.h"
  11.  
  12. #define far
  13.  
  14. #define BYTES_BOARD       10
  15. #define BYTES_DIST        11
  16. #define BYTES_DIR         12
  17.  
  18. void strupr(char *);
  19.  
  20. /* board dimensions */
  21. extern int Nrows;
  22. extern int Ncols;
  23.  
  24. extern dbox cmd_dbox;
  25.  
  26. extern int InitBoardDone; /* sanity check */
  27.  
  28. /* memory usage */
  29. extern long Ltotal; /* for board */
  30. extern long Itotal; /* for dist */
  31. extern long Ctotal; /* for dir */
  32.  
  33. /*
  34. ** the following types of input lines are legal (spaces and tabs can separate
  35. ** tokens, and case is not significant):
  36. **
  37. **  1) a blank line (ignored)
  38. **  2) ';' followed by anything (ignored)
  39. **     use semicolon to insert comments.
  40. **  3) DIMENSION (row,column)
  41. **     this defines the number of rows and columns on the board, and must be
  42. **     given before any of the lines below. note that the user sees the board
  43. **     coordinate space as being 1-based, but internally it is 0-based.
  44. **  4) HOLE (row,column)
  45. **     this defines a hole location.
  46. **  5) CONNECT thing AND thing
  47. **     this declares that two holes are to be electrically connected. a thing
  48. **     can be (row,column), or name1.name2, where name1 is the name of a
  49. **     CHIPAT-defined chip, and name2 is the name of one of its pins, or a
  50. **     number, giving the pin number of the named chip. you can use '='
  51. **     instead of 'AND' if you want.
  52. **  6) PRIORITY CONNECT thing AND thing
  53. **     same as above, except the order of connections will be preserved. the
  54. **     autorouter is free to reorder the non-PRIORITY CONNECTs, and in fact
  55. **     reorders them shortest first. if there are PRIORITY CONNECTs, they will
  56. **     all be routed before non-PRIORITY CONNECTs.
  57. **  7) INCLUDE filename
  58. **     this causes the input to be temporarily taken from the given filename.
  59. **     when the given filename is completely processed (EOF encountered),
  60. **     control returns to the current file. INCLUDE statements may be nested
  61. **     (they may occur inside the given filename). complete and partial
  62. **     pathnames can be used (C:\TTL.INC, ..\TTL.INC, \TTL.INC, FOO\TTL.INC).
  63. **  8) CHIP TYPE=type PINS=number HORIZONTAL=number VERTICAL=number
  64. **     this declares a chip type, which can be used to place chips on the
  65. **     board (see CHIPAT, below), but does not itself place anything on the
  66. **     board. TYPE gives the name that will be used in later CHIPAT
  67. **     statements. PINS declares the number of pins. HORIZONTAL gives the
  68. **     number of 50-mil units separating adjacent pins (along the long side of
  69. **     the chip). and VERTICAL gives the number of 50-mil units separating
  70. **     pins across from each other (across the skinny width of the chip).
  71. **     standard values for HORIZONTAL and VERTICAL are 2 and 6, respectively.
  72. **     all CHIP type names must be unique.
  73. **  9) number=name
  74. **     this declares a pin name for the chip that is currently being defined.
  75. **     this statement must follow a CHIP statement. pins not defined will have
  76. **     no name, but you can still refer to them by number. each pin on a chip
  77. **     can be named at most once.
  78. ** 10) name=number
  79. **     same as above.
  80. ** 11) CHIPAT (row,column) NAME=name TYPE=type ORIENTATION=orientation
  81. **     this defines an instance of a chip, and places the appropriate holes on
  82. **     the board. (row,column) is the location of pin 1. NAME defines the name
  83. **     to be used in following CONNECT statements. TYPE declares the
  84. **     CHIPAT-defined type of the chip. ORIENTATION can have the values
  85. **     NORMAL, UP, DOWN, and UPSIDEDOWN. all CHIPAT names must be unique.
  86. **
  87. **      NORMAL           UP           DOWN        UPSIDEDOWN
  88. **
  89. **       6 5 4          +---+         +---+          3 2 1
  90. **     +-*-*-*-+      4 *   * 3     1 * | * 6      +-*-*-*-+
  91. **     |  ->   |      5 * ^ * 2     2 * v * 5      |   <-  |
  92. **     +-*-*-*-+      6 * | * 1     3 *   * 4      +-*-*-*-+
  93. **       1 2 3          +---+         +---+          4 5 6
  94. **
  95. **     usually the highest-numbered pin (pin N) is Vcc (power) and the pin
  96. **     farthest from it (pin N/2) is GND (ground).
  97. */
  98.  
  99. /* chip orientations (rotations) */
  100. #define ORIENT_NORMAL           1
  101. #define ORIENT_UP               2
  102. #define ORIENT_DOWN             3
  103. #define ORIENT_UPSIDEDOWN       4
  104.  
  105. /* input token types */
  106. #define TOK_EOF         1       /* end of file, no more tokens          */
  107. #define TOK_NEWLINE     2       /* end of line                          */
  108. #define TOK_NUMBER      3       /* number (digits)                      */
  109. #define TOK_HOLE        4       /* "HOLE"                               */
  110. #define TOK_ROWCOLUMN   5       /* "(row,column)"                       */
  111. #define TOK_CONNECT     6       /* "CONNECT"                            */
  112. #define TOK_EQUAL       7       /* "="                                  */
  113. #define TOK_AND         8       /* "AND"                                */
  114. #define TOK_ALPHANUM    9       /* name (letters, digits, ':','.','\')  */
  115. #define TOK_CHIP        10      /* "CHIP"                               */
  116. #define TOK_NAME        11      /* "NAME"                               */
  117. #define TOK_PINS        12      /* "PINS"                               */
  118. #define TOK_HORIZONTAL  13      /* "HORIZONTAL"                         */
  119. #define TOK_VERTICAL    14      /* "VERTICAL"                           */
  120. #define TOK_INCLUDE     15      /* "INCLUDE"                            */
  121. #define TOK_CHIPAT      16      /* "CHIPAT"                             */
  122. #define TOK_TYPE        17      /* "TYPE"                               */
  123. #define TOK_ORIENTATION 18      /* "ORIENTATION"                        */
  124. #define TOK_NORMAL      19      /* "NORMAL"                             */
  125. #define TOK_UP          20      /* "UP"                                 */
  126. #define TOK_DOWN        21      /* "DOWN"                               */
  127. #define TOK_UPSIDEDOWN  22      /* "UPSIDEDOWN"                         */
  128. #define TOK_DIMENSION   23      /* "DIMENSION"                          */
  129. #define TOK_PRIORITY    24      /* "PRIORITY"                           */
  130.  
  131. struct reserved { /* reserved word input tokens */
  132.         char *tokenname;
  133.         int tokenvalue;
  134.         };
  135.  
  136. static struct reserved tokenmatch[] = { /* reserved word table */
  137.   { "HOLE",       TOK_HOLE       },  { "CONNECT",     TOK_CONNECT     },
  138.   { "AND",        TOK_AND        },  { "CHIP",        TOK_CHIP        },
  139.   { "NAME",       TOK_NAME       },  { "PINS",        TOK_PINS        },
  140.   { "HORIZONTAL", TOK_HORIZONTAL },  { "VERTICAL",    TOK_VERTICAL    },
  141.   { "INCLUDE",    TOK_INCLUDE    },  { "CHIPAT",      TOK_CHIPAT      },
  142.   { "TYPE",       TOK_TYPE       },  { "ORIENTATION", TOK_ORIENTATION },
  143.   { "NORMAL",     TOK_NORMAL     },  { "UP",          TOK_UP          },
  144.   { "DOWN",       TOK_DOWN       },  { "UPSIDEDOWN",  TOK_UPSIDEDOWN  },
  145.   { "DIMENSION",  TOK_DIMENSION  },  { "PRIORITY",    TOK_PRIORITY    }
  146.  };
  147.  
  148. #define MAXTOK  80      /* maximum token length (including null) */
  149.  
  150. static int numres = sizeof(tokenmatch) / sizeof(tokenmatch[0]);
  151. static char token[MAXTOK]; /* the current token is formed here */
  152.  
  153. struct pinassign { /* for assigning names to pins */
  154.         int                     index;
  155.         char far                *name;
  156.         struct pinassign far    *next;
  157.         };
  158.  
  159. struct template { /* for "CHIP" declarations */
  160.         char far                *type;
  161.         int                     pins;
  162.         int                     horizontal;
  163.         int                     vertical;
  164.         struct pinassign far    *pinlist;
  165.         struct template far     *next;
  166.         };
  167.  
  168. struct instance { /* for "CHIPAT" definitions */
  169.         int                     row;
  170.         int                     column;
  171.         char far                *name;
  172.         struct template far     *type;
  173.         int                     orientation;
  174.         struct instance far     *next;
  175.         };
  176.  
  177. static struct template far *chip = NULL; /* list of CHIPs */
  178. static struct instance far *chipat = NULL; /* list of CHIPATs */
  179.  
  180. extern void InitBoard( void );
  181. extern long GetCell( int, int, int );
  182. extern void SetCell( int, int, int, long );
  183. extern void InitWork( void );
  184. extern void SetWork( int, int, char far *, int, int, char far *, int );
  185. extern void SortWork( void );
  186. extern void Nomem( void );
  187.  
  188. void Initialize( FILE * );
  189. static void initfile( FILE * );
  190. static void initchip( struct instance far * );
  191. static void locate( char *, int *, int * );
  192. static int gettoken( FILE * );
  193. static char far *fcopy( char * );
  194. static int same( char far *, char far * );
  195. void Report( FILE * );
  196.  
  197. void Initialize ( fin ) /* get hole coordinates and connections */
  198.         FILE *fin;
  199.         {
  200.         InitWork(); /* clear work list */
  201.         initfile( fin ); /* read input file(s) */
  202.         SortWork(); /* arrange to do shortest ones first */
  203.         dbox_setnumeric(cmd_dbox, BYTES_BOARD, Ltotal );
  204.         dbox_setnumeric(cmd_dbox, BYTES_DIST, Itotal );
  205.         dbox_setnumeric(cmd_dbox, BYTES_DIR, Ctotal );
  206.         }
  207.  
  208. /* some useful macros (common code sequences) */
  209.  
  210. #define SkipRest        { while ((tok = gettoken( fin )) != TOK_EOF \
  211.                                 && tok != TOK_NEWLINE) ; }
  212.  
  213. #define SkipTokRest     { while (tok != TOK_EOF && tok != TOK_NEWLINE) \
  214.                                 tok = gettoken( fin ); } \
  215.                         continue;
  216.  
  217. #define CheckInit       { if (!InitBoardDone) { \
  218.                                 werr(0, "error: need dimensions first" ); \
  219.                                 SkipRest; \
  220.                                 continue; } }
  221.  
  222. static void initfile ( fin ) /* read and process input file(s) */
  223.         FILE *fin;
  224.         {
  225.         int tok, r1, c1, r2, c2, i;
  226.         char far *p;
  227.         char far *n1;
  228.         char far *n2;
  229.         long cell;
  230.         struct template far *p1;
  231.         struct pinassign far *p2;
  232.         struct pinassign far *p22;
  233.         struct instance far *p3;
  234.         FILE *fnew;
  235.  
  236.         while ((tok = gettoken( fin )) != TOK_EOF) {
  237.                 if (tok == TOK_DIMENSION) {
  238.                         if (InitBoardDone) { /* can only do it once */
  239.                                 werr(0, "error: redundant dimensions" );
  240.                                 SkipRest;
  241.                                 continue;
  242.                                 }
  243.                         if ((tok = gettoken( fin )) != TOK_ROWCOLUMN) {
  244.                                 werr(0, "expect (row,column)" );
  245.                                 SkipTokRest;
  246.                                 }
  247.                         sscanf( token, "(%d,%d)", &Nrows, &Ncols );
  248.                         if (Nrows <= 0 || Ncols <= 0)
  249.                                 werr(0, "dimension error" );
  250.                         else /* allocate memory for data structures */
  251.                                 InitBoard();
  252.                         }
  253.                 else if (tok == TOK_HOLE) {
  254.                         CheckInit; /* must get dimensions first */
  255.                         if ((tok = gettoken( fin )) != TOK_ROWCOLUMN) {
  256.                                 werr(0, "expect (row,column)" );
  257.                                 SkipTokRest;
  258.                                 }
  259.                         sscanf( token, "(%d,%d)", &r1, &c1 );
  260.                         if (r1 <= 0 || r1 > Nrows || c1 <= 0 || c1 > Ncols)
  261.                                 werr(0, "out of range" );
  262.                         else { /* position the hole on the board */
  263.                                 /* should check for neighbor holes (error) */
  264.                                 SetCell( r1-1, c1-1, TOP, HOLE );
  265.                                 SetCell( r1-1, c1-1, BOTTOM, HOLE );
  266.                                 }
  267.                         }
  268.                 else if (tok == TOK_CONNECT) {
  269.                         CheckInit; /* must get dimensions first */
  270.                         if ((tok = gettoken( fin )) == TOK_ROWCOLUMN)
  271.                                 sscanf( token, "(%d,%d)", &r1, &c1 );
  272.                         else if (tok == TOK_ALPHANUM)
  273.                                 locate( token, &r1, &c1 );
  274.                         else {
  275.                                 werr(0, "expect (row,column) or name" );
  276.                                 SkipTokRest;
  277.                                 }
  278.                         n1 = fcopy( token );
  279.                         if ((tok = gettoken( fin )) != TOK_EQUAL
  280.                                 && tok != TOK_AND) {
  281.                                 werr(0, "expect = or AND" );
  282.                                 SkipTokRest;
  283.                                 }
  284.                         if ((tok = gettoken( fin )) == TOK_ROWCOLUMN)
  285.                                 sscanf( token, "(%d,%d)", &r2, &c2 );
  286.                         else if (tok == TOK_ALPHANUM)
  287.                                 locate( token, &r2, &c2 );
  288.                         else {
  289.                                 werr(0, "expect (row,column) or name" );
  290.                                 SkipTokRest;
  291.                                 }
  292.                         n2 = fcopy( token );
  293.                         if (r1 <= 0 || r1 > Nrows || r2 <= 0 || r2 > Nrows
  294.                                 || c1 <= 0 || c1 > Ncols
  295.                                 || c2 <= 0 || c2 > Ncols) {
  296.                                 werr(0, "out of range" );
  297.                                 heap_free( n1 );
  298.                                 heap_free( n2 );
  299.                                 }
  300.                         else {
  301.                                 cell = GetCell( r1-1, c1-1, TOP );
  302.                                 if (!(cell & HOLE)) {
  303.                                         werr(0, "error: no source hole" );
  304.                                         heap_free( n1 );
  305.                                         heap_free( n2 );
  306.                                         SkipRest;
  307.                                         continue;
  308.                                         }
  309.                                 cell = GetCell( r2-1, c2-1, TOP );
  310.                                 if (!(cell & HOLE)) {
  311.                                         werr(0, "error: no target hole" );
  312.                                         heap_free( n1 );
  313.                                         heap_free( n2 );
  314.                                         SkipRest;
  315.                                         continue;
  316.                                         }
  317.                                 SetWork( r1-1, c1-1, n1, r2-1, c2-1, n2, 0 );
  318.                                 }
  319.                         }
  320.                 else if (tok == TOK_PRIORITY) {
  321.                         CheckInit; /* must get dimensions first */
  322.                         if ((tok = gettoken( fin )) != TOK_CONNECT) {
  323.                                 werr(0, "expect CONNECT" );
  324.                                 SkipTokRest;
  325.                                 }
  326.                         if ((tok = gettoken( fin )) == TOK_ROWCOLUMN)
  327.                                 sscanf( token, "(%d,%d)", &r1, &c1 );
  328.                         else if (tok == TOK_ALPHANUM)
  329.                                 locate( token, &r1, &c1 );
  330.                         else {
  331.                                 werr(0, "expect (row,column) or name" );
  332.                                 SkipTokRest;
  333.                                 }
  334.                         n1 = fcopy( token );
  335.                         if ((tok = gettoken( fin )) != TOK_EQUAL
  336.                                 && tok != TOK_AND) {
  337.                                 werr(0, "expect = or AND" );
  338.                                 SkipTokRest;
  339.                                 }
  340.                         if ((tok = gettoken( fin )) == TOK_ROWCOLUMN)
  341.                                 sscanf( token, "(%d,%d)", &r2, &c2 );
  342.                         else if (tok == TOK_ALPHANUM)
  343.                                 locate( token, &r2, &c2 );
  344.                         else {
  345.                                 werr(0, "expect (row,column) or name" );
  346.                                 SkipTokRest;
  347.                                 }
  348.                         n2 = fcopy( token );
  349.                         if (r1 <= 0 || r1 > Nrows || r2 <= 0 || r2 > Nrows
  350.                                 || c1 <= 0 || c1 > Ncols
  351.                                 || c2 <= 0 || c2 > Ncols) {
  352.                                 werr(0, "out of range" );
  353.                                 heap_free( n1 );
  354.                                 heap_free( n2 );
  355.                                 }
  356.                         else {
  357.                                 cell = GetCell( r1-1, c1-1, TOP );
  358.                                 if (!(cell & HOLE)) {
  359.                                         werr(0, "error: no source hole" );
  360.                                         heap_free( n1 );
  361.                                         heap_free( n2 );
  362.                                         SkipRest;
  363.                                         continue;
  364.                                         }
  365.                                 cell = GetCell( r2-1, c2-1, TOP );
  366.                                 if (!(cell & HOLE)) {
  367.                                         werr(0, "error: no target hole" );
  368.                                         heap_free( n1 );
  369.                                         heap_free( n2 );
  370.                                         SkipRest;
  371.                                         continue;
  372.                                         }
  373.                                 SetWork( r1-1, c1-1, n1, r2-1, c2-1, n2, 1 );
  374.                                 }
  375.                         }
  376.                 else if (tok == TOK_INCLUDE) {
  377.                         CheckInit; /* must get dimensions first */
  378.                         if ((tok = gettoken( fin )) != TOK_ALPHANUM) {
  379.                                 werr(0, "expect name for INCLUDE" );
  380.                                 SkipTokRest;
  381.                                 }
  382.                         if (!(fnew = fopen( token, "r" ))) {
  383.                                 werr(0, "can't open INCLUDE file %s",
  384.                                         token );
  385.                                 SkipRest;
  386.                                 continue;
  387.                                 }
  388.                         if ((tok = gettoken( fin )) != TOK_EOF
  389.                                 && tok != TOK_NEWLINE) {
  390.                                 werr(0, "extra chars on INCLUDE line" );
  391.                                 SkipRest;
  392.                                 }
  393.                         initfile( fnew ); /* recurse */
  394.                         if (fclose( fnew ))
  395.                                 werr(0, "error closing INCLUDE file" );
  396.                         continue; /* already ate the NEWLINE, if any */
  397.                         }
  398.                 else if (tok == TOK_CHIP) {
  399.                         CheckInit; /* must get dimensions first */
  400.                         if ((tok = gettoken( fin )) != TOK_TYPE
  401.                                 || (tok = gettoken( fin )) != TOK_EQUAL
  402.                                 || (tok = gettoken( fin )) != TOK_ALPHANUM) {
  403.                                 werr(0, "expect TYPE=type" );
  404.                                 SkipTokRest;
  405.                                 }
  406.                         if (!(p1 = (struct template far *)
  407.                                 heap_alloc( sizeof(struct template) )))
  408.                                 Nomem();
  409.                         p1->type = fcopy( token );
  410.                         if ((tok = gettoken( fin )) != TOK_PINS
  411.                                 || (tok = gettoken( fin )) != TOK_EQUAL
  412.                                 || (tok = gettoken( fin )) != TOK_NUMBER) {
  413.                                 werr(0, "expect PINS=number" );
  414.                                 heap_free( p1->type );
  415.                                 heap_free( p1 );
  416.                                 SkipTokRest;
  417.                                 }
  418.                         sscanf( token, "%d", &i );
  419.                         p1->pins = i;
  420.                         if ((p1->pins = i) < 0 || (i & 1))
  421.                                 werr(0, "PINS negative or odd" );
  422.                         if ((tok = gettoken( fin )) != TOK_HORIZONTAL
  423.                                 || (tok = gettoken( fin )) != TOK_EQUAL
  424.                                 || (tok = gettoken( fin )) != TOK_NUMBER) {
  425.                                 werr(0, "expect HORIZONTAL=number" );
  426.                                 heap_free( p1->type );
  427.                                 heap_free( p1 );
  428.                                 SkipTokRest;
  429.                                 }
  430.                         sscanf( token, "%d", &i );
  431.                         if ((p1->horizontal = i) <= 0)
  432.                                 werr(0, "HORIZONTAL nonpositive" );
  433.                         if ((tok = gettoken( fin )) != TOK_VERTICAL
  434.                                 || (tok = gettoken( fin )) != TOK_EQUAL
  435.                                 || (tok = gettoken( fin )) != TOK_NUMBER) {
  436.                                 werr(0, "expect VERTICAL=number" );
  437.                                 heap_free( p1->type );
  438.                                 heap_free( p1 );
  439.                                 SkipTokRest;
  440.                                 }
  441.                         sscanf( token, "%d", &i );
  442.                         if ((p1->vertical = i) < 0)
  443.                                 werr(0, "VERTICAL nonpositive" );
  444.                         p1->pinlist = NULL;
  445.                         p1->next = chip;
  446.                         chip = p1;
  447.                         }
  448.                 else if (tok == TOK_NUMBER) {
  449.                         CheckInit; /* must get dimensions first */
  450.                         if (!chip) {
  451.                                 werr(0, "no template" );
  452.                                 SkipRest;
  453.                                 continue;
  454.                                 }
  455.                         sscanf( token, "%d", &i );
  456.                         if ((tok = gettoken( fin )) != TOK_EQUAL
  457.                                 || (tok = gettoken( fin )) != TOK_ALPHANUM) {
  458.                                 werr(0, "expect number=name" );
  459.                                 SkipTokRest;
  460.                                 }
  461.                         if (!(p2 = (struct pinassign far *)
  462.                                 heap_alloc( sizeof(struct pinassign) )))
  463.                                 Nomem();
  464.                         p2->name = fcopy( token );
  465.                         p2->index = i;
  466.                         /* check uniqueness of name and index */
  467.                         for (p22 = chip->pinlist; p22; p22 = p22->next)
  468.                                 if (p22->index == i
  469.                                         || same( p22->name, p )) {
  470.                                         werr(0, "warning: repeated pin" );
  471.                                         break;
  472.                                         }
  473.                         p2->next = chip->pinlist;
  474.                         chip->pinlist = p2;
  475.                         }
  476.                 else if (tok == TOK_ALPHANUM) {
  477.                         CheckInit; /* must get dimensions first */
  478.                         if (!chip) {
  479.                                 werr(0, "no template" );
  480.                                 SkipRest;
  481.                                 continue;
  482.                                 }
  483.                         p = fcopy( token );
  484.                         if ((tok = gettoken( fin )) != TOK_EQUAL
  485.                                 || (tok = gettoken( fin )) != TOK_NUMBER) {
  486.                                 werr(0, "expect name=number" );
  487.                                 heap_free( p );
  488.                                 SkipTokRest;
  489.                                 }
  490.                         sscanf( token, "%d", &i );
  491.                         if (!(p2 = (struct pinassign far *)
  492.                                 heap_alloc( sizeof(struct pinassign) )))
  493.                                 Nomem();
  494.                         p2->name = p;
  495.                         p2->index = i;
  496.                         /* check uniqueness of name and index */
  497.                         for (p22 = chip->pinlist; p22; p22 = p22->next)
  498.                                 if (p22->index == i
  499.                                         || same( p22->name, p )) {
  500.                                         werr(0, "warning: repeated pin" );
  501.                                         break;
  502.                                         }
  503.                         p2->next = chip->pinlist;
  504.                         chip->pinlist = p2;
  505.                         }
  506.                 else if (tok == TOK_CHIPAT) {
  507.                         CheckInit; /* must get dimensions first */
  508.                         if ((tok = gettoken( fin )) != TOK_ROWCOLUMN) {
  509.                                 werr(0, "expect (row,column)" );
  510.                                 SkipTokRest;
  511.                                 }
  512.                         sscanf( token, "(%d,%d)", &r1, &c1 );
  513.                         if ((tok = gettoken( fin )) != TOK_NAME
  514.                                 || (tok = gettoken( fin )) != TOK_EQUAL
  515.                                 || (tok = gettoken( fin )) != TOK_ALPHANUM) {
  516.                                 werr(0, "expect NAME=name" );
  517.                                 SkipTokRest;
  518.                                 }
  519.                         if (!(p3 = (struct instance far *)
  520.                                 heap_alloc( sizeof(struct instance) )))
  521.                                 Nomem();
  522.                         p3->name = fcopy( token );
  523.                         p3->row = r1;
  524.                         p3->column = c1;
  525.                         if ((tok = gettoken( fin )) != TOK_TYPE
  526.                                 || (tok = gettoken( fin )) != TOK_EQUAL
  527.                                 || (tok = gettoken( fin )) != TOK_ALPHANUM) {
  528.                                 werr(0, "expect TYPE=type" );
  529.                                 heap_free( p3->name );
  530.                                 heap_free( p3 );
  531.                                 SkipTokRest;
  532.                                 }
  533.                         for (p3->type = chip; p3->type;
  534.                                 p3->type = p3->type->next)
  535.                                 if (same( token, p3->type->type ))
  536.                                         break;
  537.                         if (!(p3->type)) {
  538.                                 werr(0, "couldn't find chip type" );
  539.                                 heap_free( p3->name );
  540.                                 heap_free( p3 );
  541.                                 SkipTokRest;
  542.                                 }
  543.                         if ((tok = gettoken( fin )) != TOK_ORIENTATION
  544.                                 || (tok = gettoken( fin )) != TOK_EQUAL
  545.                                 || ((tok = gettoken( fin )) != TOK_NORMAL
  546.                                 && tok != TOK_UP && tok != TOK_DOWN
  547.                                 && tok != TOK_UPSIDEDOWN)) {
  548.                                 werr(0, "expect ORIENTATION=orientation" );
  549.                                 heap_free( p3->name );
  550.                                 heap_free( p3 );
  551.                                 SkipTokRest;
  552.                                 }
  553.                         switch (tok) {
  554.                         case TOK_NORMAL:
  555.                                 p3->orientation = ORIENT_NORMAL;        break;
  556.                         case TOK_UP:
  557.                                 p3->orientation = ORIENT_UP;            break;
  558.                         case TOK_DOWN:
  559.                                 p3->orientation = ORIENT_DOWN;          break;
  560.                         case TOK_UPSIDEDOWN:
  561.                                 p3->orientation = ORIENT_UPSIDEDOWN;    break;
  562.                         default:
  563.                                 werr(0, "internal error" );
  564.                                 exit( -1 );
  565.                                 break;
  566.                                 }
  567.                         p3->next = chipat;
  568.                         chipat = p3;
  569.                         initchip( p3 );
  570.                         }
  571.                 else if (tok == TOK_NEWLINE)
  572.                         continue;
  573.                 else /* something unexpected */
  574.                         werr(0, "syntax error: unexpected input" );
  575.                 if ((tok = gettoken( fin )) != TOK_EOF && tok != TOK_NEWLINE) {
  576.                         werr(0, "syntax error: expected end of line" );
  577.                         SkipRest;
  578.                         }
  579.                 }
  580.         }
  581.  
  582. static void initchip ( p ) /* initialize a chip definition (create holes) */
  583.         struct instance far *p;
  584.         {
  585.         int r, c, pin;
  586.         struct template far *t;
  587.  
  588.         pin = 1;
  589.         r = p->row;
  590.         c = p->column;
  591.         t = p->type;
  592.         /* should check for neighboring holes (warning if so) */
  593.         switch (p->orientation) {
  594.         case ORIENT_NORMAL:
  595.                 while (pin <= t->pins / 2) {
  596.                         SetCell( r-1, c-1, TOP, HOLE );
  597.                         SetCell( r-1, c-1, BOTTOM, HOLE );
  598.                         pin++;
  599.                         c += t->horizontal;
  600.                         }
  601.                 c -= t->horizontal;
  602.                 r += t->vertical;
  603.                 while (pin <= t->pins) {
  604.                         SetCell( r-1, c-1, TOP, HOLE );
  605.                         SetCell( r-1, c-1, BOTTOM, HOLE );
  606.                         pin++;
  607.                         c -= t->horizontal;
  608.                         }
  609.                 break;
  610.         case ORIENT_UP:
  611.                 while (pin <= t->pins / 2) {
  612.                         SetCell( r-1, c-1, TOP, HOLE );
  613.                         SetCell( r-1, c-1, BOTTOM, HOLE );
  614.                         pin++;
  615.                         r += t->horizontal;
  616.                         }
  617.                 r -= t->horizontal;
  618.                 c -= t->vertical;
  619.                 while (pin <= t->pins) {
  620.                         SetCell( r-1, c-1, TOP, HOLE );
  621.                         SetCell( r-1, c-1, BOTTOM, HOLE );
  622.                         pin++;
  623.                         r -= t->horizontal;
  624.                         }
  625.                 break;
  626.         case ORIENT_DOWN:
  627.                 while (pin <= t->pins / 2) {
  628.                         SetCell( r-1, c-1, TOP, HOLE );
  629.                         SetCell( r-1, c-1, BOTTOM, HOLE );
  630.                         pin++;
  631.                         r -= t->horizontal;
  632.                         }
  633.                 r += t->horizontal;
  634.                 c += t->vertical;
  635.                 while (pin <= t->pins) {
  636.                         SetCell( r-1, c-1, TOP, HOLE );
  637.                         SetCell( r-1, c-1, BOTTOM, HOLE );
  638.                         pin++;
  639.                         r += t->horizontal;
  640.                         }
  641.                 break;
  642.         case ORIENT_UPSIDEDOWN:
  643.                 while (pin <= t->pins / 2) {
  644.                         SetCell( r-1, c-1, TOP, HOLE );
  645.                         SetCell( r-1, c-1, BOTTOM, HOLE );
  646.                         pin++;
  647.                         c -= t->horizontal;
  648.                         }
  649.                 c += t->horizontal;
  650.                 r -= t->vertical;
  651.                 while (pin <= t->pins) {
  652.                         SetCell( r-1, c-1, TOP, HOLE );
  653.                         SetCell( r-1, c-1, BOTTOM, HOLE );
  654.                         pin++;
  655.                         c += t->horizontal;
  656.                         }
  657.                 break;
  658.         default:
  659.                 werr(0, "internal error: unexpected orientation" );
  660.                 exit( -1 );
  661.                 break;
  662.                 }
  663.         }
  664.  
  665. static void locate ( p, r, c ) /* find location of name1.{name2,number} */
  666.         char *p;
  667.         int *r, *c;
  668.         {
  669.         char *q;
  670.         int i;
  671.         struct instance far *s;
  672.         struct pinassign far *t;
  673.  
  674.         if (!(q = strchr( p, '.' ))) {
  675.                 werr(0, "expect name1.{name2,number}" );
  676.                 return;
  677.                 }
  678.         *q++ = 0; /* separate into two parts & point at second part */
  679.         for (s = chipat; s; s = s->next) /* find proper chip */
  680.                 if (same( p, s->name ))
  681.                         break;
  682.         if (!s || !(s->type)) {
  683.                 werr(0, "can't find chip or chip type" );
  684.                 return;
  685.                 }
  686.         if (isdigit( *q )) { /* get pin number */
  687.                 i = atoi( q );
  688.                 if (i <= 0 || i > s->type->pins) {
  689.                         werr(0, "pin out of range" );
  690.                         return;
  691.                         }
  692.                 }
  693.         else { /* get index of named pin via the template */
  694.                 for (t = s->type->pinlist; t; t = t->next)
  695.                         if (same( q, t->name ))
  696.                                 break;
  697.                 if (!t) {
  698.                         werr(0, "can't find pin" );
  699.                         return;
  700.                         }
  701.                 i = t->index;
  702.                 }
  703.         *r = s->row;
  704.         *c = s->column;
  705.         switch (s->orientation) {
  706.         case ORIENT_NORMAL:
  707.                 if (i <= s->type->pins / 2)
  708.                         *c += (i-1) * s->type->horizontal;
  709.                 else {
  710.                         *r += s->type->vertical;
  711.                         *c += (s->type->pins - i) * s->type->horizontal;
  712.                         }
  713.                 break;
  714.         case ORIENT_UP:
  715.                 if (i <= s->type->pins / 2)
  716.                         *r += (i-1) * s->type->horizontal;
  717.                 else {
  718.                         *c -= s->type->vertical;
  719.                         *r += (s->type->pins - i) * s->type->horizontal;
  720.                         }
  721.                 break;
  722.         case ORIENT_DOWN:
  723.                 if (i <= s->type->pins / 2)
  724.                         *r -= (i-1) * s->type->horizontal;
  725.                 else {
  726.                         *c += s->type->vertical;
  727.                         *r -= (s->type->pins - i) * s->type->horizontal;
  728.                         }
  729.                 break;
  730.         case ORIENT_UPSIDEDOWN:
  731.                 if (i <= s->type->pins / 2)
  732.                         *c -= (i-1) * s->type->horizontal;
  733.                 else {
  734.                         *r -= s->type->vertical;
  735.                         *c -= (s->type->pins - i) * s->type->horizontal;
  736.                         }
  737.                 break;
  738.         default:
  739.                 werr(0, "internal error: unexpected orientation" );
  740.                 exit( -1 );
  741.                 break;
  742.                 }
  743.         *--q = '.'; /* put back the separator */
  744.         }
  745.  
  746. static int gettoken ( fin ) /* get next token into token[], return value */
  747.         FILE *fin;
  748.         {
  749.         int ch, i;
  750.  
  751.         /* burn whitespace */
  752.         while ((ch = getc( fin )) == ' ' || ch == '\t') ;
  753.         if (ch == EOF)
  754.                 return( TOK_EOF );
  755.         else if (ch == '\n')
  756.                 return( TOK_NEWLINE );
  757.         else if (ch == ';') { /* comment; burn to end of line */
  758.                 while ((ch = getc( fin )) != EOF && ch != '\n') ;
  759.                 return( (ch == '\n') ? TOK_NEWLINE : TOK_EOF );
  760.                 }
  761.         else if (ch == '=')
  762.                 return( TOK_EQUAL );
  763.         else if (isdigit( ch )) { /* a number; move it to the buffer */
  764.                 i = 0;
  765.                 do {
  766.                         if (i < MAXTOK-1)
  767.                                 token[i++] = (char)ch;
  768.                         ch = getc( fin );
  769.                         } while (isdigit( ch ));
  770.                 token[i] = 0;
  771.                 if (ch != EOF)
  772.                         ungetc( ch, fin );
  773.                 return( TOK_NUMBER );
  774.                 }
  775.         else if (isalpha( ch ) || ch == '.' || ch == '\\') {
  776.                 /* a name; move it to the buffer */
  777.                 i = 0;
  778.                 do {
  779.                         if (i < MAXTOK-1)
  780.                                 token[i++] = (char)ch;
  781.                         ch = getc( fin );
  782.                         } while (isalnum( ch ) || ch == ':' || ch == '.'
  783.                                 || ch == '\\');
  784.                 token[i] = 0;
  785.                 if (ch != EOF)
  786.                         ungetc( ch, fin );
  787.                 /* uppercase it */
  788.                 strupr( token );
  789.                 /* try to identify it as a reserved word */
  790.                 for (i = 0; i < numres; i++) /* search table */
  791.                         if (!strcmp( tokenmatch[i].tokenname, token ))
  792.                                 return( tokenmatch[i].tokenvalue );
  793.                 /* it's not a reserved word; just return it */
  794.                 return( TOK_ALPHANUM );
  795.                 }
  796.         else if (ch == '(') { /* "(row,column)", move it to the buffer */
  797.                 token[0] = (char)ch;
  798.                 i = 1;
  799.                 while ((ch = getc( fin )) == ' ' || ch == '\t') ;
  800.                 if (!isdigit( ch )) {
  801.                         werr(0, "syntax error: expected digit" );
  802.                         exit( -1 );
  803.                         }
  804.                 do {
  805.                         if (i < MAXTOK-1)
  806.                                 token[i++] = (char)ch;
  807.                         ch = getc( fin );
  808.                         } while (isdigit( ch ));
  809.                 while (ch == ' ' || ch == '\t')
  810.                         ch = getc( fin );
  811.                 if (ch != ',') {
  812.                         werr(0, "syntax error: expected comma" );
  813.                         exit( -1 );
  814.                         }
  815.                 if (i < MAXTOK-1)
  816.                         token[i++] = (char)ch;
  817.                 while ((ch = getc( fin )) == ' ' || ch == '\t') ;
  818.                 if (!isdigit( ch )) {
  819.                         werr(0, "syntax error: expected digit" );
  820.                         exit( -1 );
  821.                         }
  822.                 do {
  823.                         if (i < MAXTOK-1)
  824.                                 token[i++] = (char)ch;
  825.                         ch = getc( fin );
  826.                         } while (isdigit( ch ));
  827.                 while (ch == ' ' || ch == '\t')
  828.                         ch = getc( fin );
  829.                 if (ch != ')') {
  830.                         werr(0, "syntax error: expected right paren" );
  831.                         exit( -1 );
  832.                         }
  833.                 if (i < MAXTOK-1)
  834.                         token[i++] = (char)ch;
  835.                 token[i] = 0;
  836.                 return( TOK_ROWCOLUMN );
  837.                 }
  838.         else {
  839.                 werr(0, "syntax error: unrecognized token" );
  840.                 exit( -1 );
  841.                 }
  842.         }
  843.  
  844. static char far *fcopy ( p ) /* return ptr to far string copy */
  845.         char *p;
  846.         {
  847.         char far *q;
  848.         char far *r;
  849.  
  850.         if (!(q = r = (char *)heap_alloc( strlen( p ) + 1 )))
  851.                 Nomem();
  852.         while (*r++ = *p++) ; /* copy string */
  853.         return( q );
  854.         }
  855.  
  856. static int same ( p, q ) /* return 1 if far strings are identical, else 0 */
  857.         char far *p;
  858.         char far *q;
  859.         {
  860.         while (*p && *p == *q) { /* compare bytes until mismatch or end */
  861.                 p++;
  862.                 q++;
  863.                 }
  864.         return( (*p || *q) ? 0 : 1 );
  865.         }
  866.  
  867. void Report ( fout ) /* output routed board */
  868.         FILE *fout;
  869.         {
  870.         int r, c;
  871.         char b;
  872.         long x;
  873.  
  874.         /* output dimensions first */
  875.         b = (char)Nrows;        putc( b, fout );
  876.         b = (char)(Nrows>>8);   putc( b, fout );
  877.         b = (char)Ncols;        putc( b, fout );
  878.         b = (char)(Ncols>>8);   putc( b, fout );
  879.         /* now do rows and columns */
  880.         for (r = 0; r < Nrows; r++)
  881.                 for (c = 0; c < Ncols; c++) {
  882.                         x = GetCell( r, c, TOP ); /* first do frontside */
  883.                         b = (char)x;            putc( b, fout );
  884.                         b = (char)(x>>8);       putc( b, fout );
  885.                         b = (char)(x>>16);      putc( b, fout );
  886.                         b = (char)(x>>24);      putc( b, fout );
  887.                         x = GetCell( r, c, BOTTOM ); /* then do backside */
  888.                         b = (char)x;            putc( b, fout );
  889.                         b = (char)(x>>8);       putc( b, fout );
  890.                         b = (char)(x>>16);      putc( b, fout );
  891.                         b = (char)(x>>24);      putc( b, fout );
  892.                         }
  893.         }
  894.  
  895. void strupr(char *s)
  896. {
  897.   int i;
  898.  
  899.   for (i = 0; i < strlen(s); i++)
  900.     s[i] = toupper(s[i]);
  901. }
  902.