home *** CD-ROM | disk | FTP | other *** search
/ World of Shareware - Software Farm 2 / wosw_2.zip / wosw_2 / DATABASE / DPG.ZIP / DPG.C next >
C/C++ Source or Header  |  1992-05-04  |  47KB  |  2,767 lines

  1. #include    <stdio.h>
  2. #include    <string.h>
  3. #include    <stdlib.h>
  4. #include    <stdarg.h>
  5. #include    "video.h"
  6. #include    "files.h"
  7.  
  8. #define    MAXNAME    32        /* Maximum length of symbols */
  9. #define    MAXMENU    20        /* Maximum depth of submenus */
  10.  
  11. #define    myisalpha(c)    (isalpha (c) || (c) == '_')
  12. #define    myisalnum(c)    (isalpha (c) || (c) == '_' || isdigit (c))
  13. #define    addlist(b,p)    (p)->next = (b); (b) = (p)
  14. #define    align(n)            n = (n+1) & ~1
  15.  
  16.         /* Types of variables */
  17.  
  18. enum
  19. {
  20.     V_INT,
  21.     V_FLOAT,
  22.     V_DATE,
  23.     V_STR,
  24.     V_PTR,
  25. };
  26.  
  27.         /* Types of lexical tokens */
  28.  
  29. enum
  30. {
  31.     T_AND,
  32.     T_ASSIGN,
  33.     T_CLOSEBRACE,
  34.     T_CLOSEBRACKET,
  35.     T_COLON,
  36.     T_DOT,
  37.     T_EOF,
  38.     T_EQ,
  39.     T_FIELD,
  40.     T_FILE,
  41.     T_FLOAT,
  42.     T_GE,
  43.     T_GT,
  44.     T_INT,
  45.     T_KEYWORD,
  46.     T_LE,
  47.     T_LT,
  48.     T_MINUS,
  49.     T_NE,
  50.     T_NOT,
  51.     T_OPENBRACE,
  52.     T_OPENBRACKET,
  53.     T_OR,
  54.     T_PERCENT,
  55.     T_PLUS,
  56.     T_PROC,
  57.     T_SLASH,
  58.     T_STAR,
  59.     T_STR,
  60.     T_UNDEF,
  61.     T_VAR,
  62. };
  63.  
  64.         /* List of keywords */
  65.  
  66. enum
  67. {
  68.     K_ATODATE,
  69.     K_ATOF,
  70.     K_ATOI,
  71.     K_BREAK,
  72.     K_CONTINUE,
  73.     K_CREATE,
  74.     K_CURSOR,
  75.     K_DATE,
  76.     K_DATEDAY,
  77.     K_DATEMONTH,
  78.     K_DATEYEAR,
  79.     K_DEL,
  80.     K_DELETE,
  81.     K_DO,
  82.     K_DOWN,
  83.     K_EDIT,
  84.     K_ELSE,
  85.     K_END,
  86.     K_ESC,
  87.     K_FILES,
  88.     K_FIND,
  89.     K_FLOAT,
  90.     K_GETKEY,
  91.     K_GOTO,
  92.     K_HOME,
  93.     K_IF,
  94.     K_INDEX,
  95.     K_INS,
  96.     K_INT,
  97.     K_LEFT,
  98.     K_LINK,
  99.     K_MAKEDATE,
  100.     K_ON,
  101.     K_PAUSE,
  102.     K_PGDN,
  103.     K_PGUP,
  104.     K_PRINTDATE,
  105.     K_PRINTFLOAT,
  106.     K_PRINTINT,
  107.     K_PRINTSTR,
  108.     K_PROCEDURES,
  109.     K_PTR,
  110.     K_READ,
  111.     K_RETURN,
  112.     K_RIGHT,
  113.     K_SCROLL,
  114.     K_SELECT,
  115.     K_SPRINTDATE,
  116.     K_SPRINTFLOAT,
  117.     K_SPRINTINT,
  118.     K_STR,
  119.     K_STRCMP,
  120.     K_STRCPY,
  121.     K_SWITCH,
  122.     K_TABLE,
  123.     K_UNLINK,
  124.     K_UP,
  125.     K_VAR,
  126.     K_WHILE,
  127.     K_WRITE,
  128. };
  129.  
  130. typedef char str[MAXNAME];
  131.  
  132.         /* Binary tree structure for symbol tables */
  133.  
  134. typedef struct symstruct
  135. {
  136.     struct symstruct *left,*right;
  137.     str name;
  138.     void *p;        /* Pointer to actual object denoted by symbol */
  139. } sym;
  140.  
  141. struct filestruct;
  142. typedef struct filestruct file;
  143.  
  144.         /* Structure for file identifier ("name" field is required because
  145.             pointer may not be available initially */
  146.  
  147. typedef struct fileidstruct
  148. {
  149.     struct fileidstruct *next;
  150.     str name;
  151.     file *p;
  152. } fileid;
  153.  
  154.         /* Structure for variable declarations */
  155.  
  156. typedef struct varstruct
  157. {
  158.     struct varstruct *next;
  159.     str name;
  160.     char type;
  161.     char l;        /* Length in characters or digits before decimal point */
  162.     char dec;    /* Digits after decimal point (V_FLOAT only) */
  163. } var;
  164.  
  165.         /* Structure for data file */
  166.  
  167. struct filestruct
  168. {
  169.     file *next;
  170.     str name;
  171.     var *fields;
  172.     sym *fieldnames;
  173.     var index;            /* Index field if any */
  174.     fileid *on;            /* Which files is this one linked on */
  175.     long table;            /* If nonzero, this file is a table and the value is the
  176.                                 number of entries */
  177. };
  178.  
  179.         /* Structure for procedure declaration */
  180.  
  181. typedef struct procstruct
  182. {
  183.     struct procstruct *next;
  184.     str name;
  185.     char *menuitem;    /* Which menu item (if any) is used for access */
  186. } proc;
  187.  
  188.         /* Structures used in constructing menu tree */
  189.  
  190. struct menutreestruct;
  191. typedef struct menutreestruct menutree;
  192.  
  193. typedef struct submenustruct
  194. {
  195.     struct submenustruct *next;
  196.     menutree *mt;
  197. } submenu;
  198.  
  199. struct menutreestruct
  200. {
  201.     char *text;
  202.     char *func;
  203.     submenu *sm;
  204. };
  205.  
  206. char *keywords[] =
  207. {
  208.     "atodate",
  209.     "atof",
  210.     "atoi",
  211.     "break",
  212.     "continue",
  213.     "create",
  214.     "cursor",
  215.     "date",
  216.     "dateday",
  217.     "datemonth",
  218.     "dateyear",
  219.     "del",
  220.     "delete",
  221.     "do",
  222.     "down",
  223.     "edit",
  224.     "else",
  225.     "end",
  226.     "esc",
  227.     "files",
  228.     "find",
  229.     "float",
  230.     "getkey",
  231.     "goto",
  232.     "home",
  233.     "if",
  234.     "index",
  235.     "ins",
  236.     "int",
  237.     "left",
  238.     "link",
  239.     "makedate",
  240.     "on",
  241.     "pause",
  242.     "pgdn",
  243.     "pgup",
  244.     "printdate",
  245.     "printfloat",
  246.     "printint",
  247.     "printstr",
  248.     "procedures",
  249.     "ptr",
  250.     "read",
  251.     "return",
  252.     "right",
  253.     "scroll",
  254.     "select",
  255.     "sprintdate",
  256.     "sprintfloat",
  257.     "sprintint",
  258.     "str",
  259.     "strcmp",
  260.     "strcpy",
  261.     "switch",
  262.     "table",
  263.     "unlink",
  264.     "up",
  265.     "var",
  266.     "while",
  267.     "write",
  268. };
  269.  
  270.         /* Names of cursor directions used to move between fields
  271.             (duplicated in keywords above) */
  272.  
  273. char *dirname[] =
  274. {
  275.     "RETURN",
  276.     "ESC",
  277.     "UP",
  278.     "DOWN",
  279.     "LEFT",
  280.     "RIGHT",
  281.     "PGUP",
  282.     "PGDN",
  283.     "HOME",
  284.     "END",
  285.     "INS",
  286.     "DEL",
  287. };
  288.  
  289. FILE *infile;                /* Source file */
  290. FILE *outfile;                /* Output file */
  291. char outfilename[256];    /* Name of output file */
  292.  
  293. long line = 1;                /* Current line number */
  294. char buf[256];                /* Character buffer for lexical analyzer */
  295.  
  296. int nc;                        /* Next character (used by lexical analyzer) */
  297. int nt;                        /* Next token type */
  298. long ni;                        /* Next integer value if integer token */
  299. double nf;                    /* Next floating point value if floating point token */
  300. int nkeyword;                /* Next keyword if keyword token */
  301. var *nvar;                    /* Pointer to variable if variable name token */
  302. file *nfile;                /* Pointer to file if file name token */
  303. proc *nproc;                /* Pointer to procedure if procedure name token */
  304.                                 /* Labels for output switch statement depending on
  305.                                     cursor movement direction */
  306. char dirlabel[MAXDIR][MAXNAME];
  307. int indent;                    /* Current output indentation level */
  308. int lastlen,lastdec;        /* Number of characters/digits of last token */
  309.  
  310. var *globals;                /* Global variables */
  311. proc *procs;                /* Procedures */
  312. file *files;                /* Files */
  313. var *locals;                /* Local variables for procedure currently being parsed */
  314.  
  315. sym *globalnames;
  316. sym *procnames;
  317. sym *filenames;
  318. sym *localnames;
  319.  
  320. long miscoff;                /* Offset for data in miscfile */
  321.  
  322.                                 /* Text of menu items */
  323. char *menutext[MAXMENU];
  324.  
  325. void parseexp (void);
  326. void parsestatement (void);
  327.  
  328.         /* Output error message and terminate */
  329.  
  330. void error (char *format,...)
  331. {
  332.     va_list argptr;
  333.  
  334.     va_start (argptr,format);
  335.     printf ("Error %ld: ",line);
  336.     vprintf (format,argptr);
  337.     va_end (argptr);
  338.     putchar ('\n');
  339.     fclose (outfile);
  340.     unlink (outfilename);
  341.     exit (1);
  342. }
  343.  
  344.         /* Output error message but keep compiling */
  345.  
  346. void warning (char *format,...)
  347. {
  348.     va_list argptr;
  349.  
  350.     va_start (argptr,format);
  351.     printf ("Warning %ld: ",line);
  352.     vprintf (format,argptr);
  353.     va_end (argptr);
  354.     putchar ('\n');
  355. }
  356.  
  357.         /* Allocate memory with error checking */
  358.  
  359. void *alloc (int n)
  360. {
  361.     void *p;
  362.  
  363.     p = malloc (n);
  364.     if (p == 0)
  365.     {
  366.         error ("Out of memory");
  367.         exit (1);
  368.     }
  369.     return p;
  370. }
  371.  
  372.         /* Add a symbol to a symbol table */
  373.  
  374. void addsym (char *name,sym **base,void *p)
  375. {
  376.     sym *s;
  377.     sym *q;
  378.     int c;
  379.  
  380.     s = alloc (sizeof (sym));
  381.     s->left = s->right = 0;
  382.     strcpy (s->name,name);
  383.     s->p = p;
  384.     if (*base == 0)
  385.     {
  386.         *base = s;
  387.         return;
  388.     }
  389.     q = *base;
  390.     for (;;)
  391.     {
  392.         c = strcmp (q->name,name);
  393.         if (c == 0)
  394.         {
  395.             warning ("Symbol '%s' redefined",name);
  396.             return;
  397.         }
  398.         if (c < 0)
  399.         {
  400.             if (q->right == 0)
  401.             {
  402.                 q->right = s;
  403.                 return;
  404.             }
  405.             q = q->right;
  406.         }
  407.         else
  408.         {
  409.             if (q->left == 0)
  410.             {
  411.                 q->left = s;
  412.                 return;
  413.             }
  414.             q = q->left;
  415.         }
  416.     }
  417. }
  418.  
  419.         /* Free a symbol table */
  420.  
  421. void freesym (sym *s)
  422. {
  423.     if (s)
  424.     {
  425.         freesym (s->right);
  426.         freesym (s->left);
  427.         free (s);
  428.     }
  429. }
  430.  
  431.         /* Compare pointers to pointers to strings (used in calling bsearch ()) */
  432.  
  433. strpcmp (char **s1,char **s2)
  434. {
  435.     return strcmp (*s1,*s2);
  436. }
  437.  
  438.         /* Locate the string in buf in a symbol table, if present */
  439.  
  440. void *findsym (sym *s)
  441. {
  442.     int i;
  443.  
  444.     if (s == 0)
  445.         return 0;
  446.     i = strcmp (buf,s->name);
  447.     if (i == 0)
  448.         return s->p;
  449.     if (i < 0)
  450.         return findsym (s->left);
  451.     else
  452.         return findsym (s->right);
  453. }
  454.  
  455.         /* Read next character into nc from input file */
  456.  
  457. void readc (void)
  458. {
  459.     nc = fgetc (infile);
  460.     if (nc == '\n')
  461.         line++;
  462. }
  463.  
  464.         /* Read next lexical token */
  465.  
  466. void lex (void)
  467. {
  468.     int i;
  469.     void *p;
  470.  
  471. LOOP:
  472.  
  473.             /* Ignore leading white space */
  474.  
  475.     while (isspace (nc))
  476.         readc ();
  477.  
  478.             /* Next token is a symbol of some sort */
  479.  
  480.     if (myisalpha (nc))
  481.     {
  482.                 /* Read symbol into buf */
  483.  
  484.         i = 0;
  485.         do
  486.         {
  487.             if (i != MAXNAME)
  488.                 buf[i++] = tolower (nc);
  489.             readc ();
  490.         }
  491.         while (myisalnum (nc));
  492.         buf[i] = 0;
  493.  
  494.                 /* Is it a keyword? */
  495.  
  496.         p = buf;
  497.         p = bsearch (&p,keywords,sizeof keywords / sizeof (char *),
  498.                 sizeof (char *),strpcmp);
  499.         if (p)
  500.         {
  501.             nt = T_KEYWORD;
  502.             nkeyword = (char **)p - keywords;
  503.             return;
  504.         }
  505.  
  506.                 /* Is it the name of a local variable? */
  507.  
  508.         p = findsym (localnames);
  509.         if (p)
  510.         {
  511.             nt = T_VAR;
  512.             nvar = p;
  513.             lastlen = nvar->l;
  514.             lastdec = nvar->dec;
  515.             return;
  516.         }
  517.  
  518.                 /* Is it the name of a global variable? */
  519.  
  520.         p = findsym (globalnames);
  521.         if (p)
  522.         {
  523.             nt = T_VAR;
  524.             nvar = p;
  525.             lastlen = nvar->l;
  526.             lastdec = nvar->dec;
  527.             return;
  528.         }
  529.  
  530.                 /* Is it the name of a file? */
  531.  
  532.         p = findsym (filenames);
  533.         if (p)
  534.         {
  535.             nt = T_FILE;
  536.             nfile = p;
  537.             return;
  538.         }
  539.  
  540.                 /* Is it the name of a procedure? */
  541.  
  542.         p = findsym (procnames);
  543.         if (p)
  544.         {
  545.             nt = T_PROC;
  546.             nproc = p;
  547.             return;
  548.         }
  549.  
  550.                 /* Failing all this, if the last two tokens were the name of a file
  551.                     followed by a dot, this must be the name of a field */
  552.  
  553.         if (nt == T_DOT && nfile)
  554.         {
  555.                     /* Is it a regular field? */
  556.  
  557.             nt = T_FIELD;
  558.             p = findsym (nfile->fieldnames);
  559.             if (p)
  560.             {
  561.                 nvar = p;
  562.                 lastlen = nvar->l;
  563.                 lastdec = nvar->dec;
  564.             }
  565.             else    /* Is it the index variable? */
  566.                 if (!strcmp (buf,nfile->index.name))
  567.                 {
  568.                     nvar = &nfile->index;
  569.                     lastlen = nvar->l;
  570.                 }
  571.             return;
  572.         }
  573.  
  574.                 /* Not identified, so return next token as unidentified symbol */
  575.  
  576.         nt = T_UNDEF;
  577.         return;
  578.     }
  579.  
  580.             /* Next token is a number */
  581.  
  582.     if (isdigit (nc))
  583.     {
  584.                 /* Read number into buf */
  585.  
  586.         i = 0;
  587.         do
  588.         {
  589.             buf[i] = nc;
  590.             i++;
  591.             if (i == sizeof buf)
  592.                 error ("Number too long");
  593.             readc ();
  594.         }
  595.         while (isdigit (nc));
  596.         lastlen = i;
  597.  
  598.                 /* Floating point number */
  599.  
  600.         if (nc == '.')
  601.         {
  602.             buf[i] = '.';
  603.             i++;
  604.             if (i == sizeof buf)
  605.                 error ("Number too long");
  606.             readc ();
  607.             while (isdigit (nc))
  608.             {
  609.                 buf[i] = nc;
  610.                 i++;
  611.                 if (i == sizeof buf)
  612.                     error ("Number too long");
  613.                 readc ();
  614.             }
  615.             buf[i] = 0;
  616.             nt = T_FLOAT;
  617.             nf = atof (buf);
  618.             lastdec = i - lastlen - 1;
  619.         }
  620.         else    /* Integer */
  621.         {
  622.             buf[i] = 0;
  623.             nt = T_INT;
  624.             ni = atol (buf);
  625.         }
  626.         return;
  627.     }
  628.     switch (nc)
  629.     {
  630.         case '.':        /* Either a floating-point number or the dot operator */
  631.             readc ();
  632.             if (isdigit (nc))
  633.             {
  634.                 buf[0] = '.';
  635.                 i = 1;
  636.                 do
  637.                 {
  638.                     buf[i] = nc;
  639.                     i++;
  640.                     if (i == sizeof buf)
  641.                         error ("Number too long");
  642.                 }
  643.                 while (isdigit (nc));
  644.                 buf[i] = 0;
  645.                 nt = T_FLOAT;
  646.                 nf = atof (buf);
  647.                 lastlen = 0;
  648.                 lastdec = i - 1;
  649.             }
  650.             else
  651.                 nt = T_DOT;
  652.             break;
  653.         case '"':        /* A string */
  654.             i = 0;
  655.             readc ();
  656.             while (nc != '"')
  657.             {
  658.                 if (nc == EOF)
  659.                     error ("Unterminated string");
  660.                 buf[i] = nc;
  661.                 i++;
  662.                 if (i == sizeof buf)
  663.                     error ("String too long");
  664.                 readc ();
  665.             }
  666.             buf[i] = 0;
  667.             lastlen = i;
  668.             readc ();
  669.             nt = T_STR;
  670.             break;
  671.         case '&':
  672.             readc ();
  673.             if (nc != '&')
  674.                 error ("'&' is not a valid token");
  675.             readc ();
  676.             nt = T_AND;
  677.             break;
  678.         case '|':
  679.             readc ();
  680.             if (nc != '|')
  681.                 error ("'|' is not a valid token");
  682.             readc ();
  683.             nt = T_OR;
  684.             break;
  685.         case '=':
  686.             readc ();
  687.             nt = T_ASSIGN;
  688.             if (nc == '=')
  689.             {
  690.                 readc ();
  691.                 nt = T_EQ;
  692.             }
  693.             break;
  694.         case '>':
  695.             readc ();
  696.             nt = T_GT;
  697.             if (nc == '=')
  698.             {
  699.                 readc ();
  700.                 nt = T_GE;
  701.             }
  702.             break;
  703.         case '<':
  704.             readc ();
  705.             nt = T_LT;
  706.             if (nc == '=')
  707.             {
  708.                 readc ();
  709.                 nt = T_LE;
  710.             }
  711.             break;
  712.         case '!':
  713.             readc ();
  714.             nt = T_NOT;
  715.             if (nc == '=')
  716.             {
  717.                 readc ();
  718.                 nt = T_NE;
  719.             }
  720.             break;
  721.         case '{':
  722.             readc ();
  723.             nt = T_OPENBRACE;
  724.             break;
  725.         case '}':
  726.             readc ();
  727.             nt = T_CLOSEBRACE;
  728.             break;
  729.         case '(':
  730.             readc ();
  731.             nt = T_OPENBRACKET;
  732.             break;
  733.         case ')':
  734.             readc ();
  735.             nt = T_CLOSEBRACKET;
  736.             break;
  737.         case ':':
  738.             readc ();
  739.             nt = T_COLON;
  740.             break;
  741.         case '-':
  742.             readc ();
  743.             nt = T_MINUS;
  744.             break;
  745.         case '%':
  746.             readc ();
  747.             nt = T_PERCENT;
  748.             break;
  749.         case '+':
  750.             readc ();
  751.             nt = T_PLUS;
  752.             break;
  753.         case '/':        /* Either a slash or a comment */
  754.             readc ();
  755.             if (nc == '*')
  756.             {
  757.                 do
  758.                 {
  759.                     do
  760.                         readc ();
  761.                     while (nc != '*' && nc != EOF);
  762.                     if (nc == EOF)
  763.                     {
  764.                         nt = T_EOF;
  765.                         return;
  766.                     }
  767.                     readc ();
  768.                 }
  769.                 while (nc != '/');
  770.                 readc ();
  771.                 goto LOOP;        /* Comment, so ignore it and get new token */
  772.             }
  773.             nt = T_SLASH;
  774.             break;
  775.         case '*':
  776.             readc ();
  777.             nt = T_STAR;
  778.             break;
  779.         case EOF:
  780.             nt = T_EOF;
  781.             break;
  782.         default:
  783.             error ("Unrecognized character %c",nc);
  784.     }
  785. }
  786.  
  787.         /* Check whether the next token is a given keyword, if so get new token */
  788.  
  789. iskeyword (int k)
  790. {
  791.     if (nt == T_KEYWORD && nkeyword == k)
  792.     {
  793.         lex ();
  794.         return 1;
  795.     }
  796.     return 0;
  797. }
  798.  
  799.         /* Output a string */
  800.  
  801. void os (char *s)
  802. {
  803.     fprintf (outfile,"%s",s);
  804. }
  805.  
  806.         /* Output an integer */
  807.  
  808. void oi (long n)
  809. {
  810.     fprintf (outfile,"%ld",n);
  811. }
  812.  
  813.         /* Output a floating point number */
  814.  
  815. void of (double n)
  816. {
  817.     fprintf (outfile,"%lf",n);
  818. }
  819.  
  820.         /* Go on to new line, and indent as necessary */
  821.  
  822. void nl (void)
  823. {
  824.     int i;
  825.  
  826.     fputc ('\n',outfile);
  827.     for (i=indent; i--;)
  828.         fputc ('\t',outfile);
  829. }
  830.  
  831.         /* Check that the next token is a label reference (labels are not
  832.             currently validated, so pass any sort of symbol */
  833.  
  834. void cklabel (void)
  835. {
  836.     if (    nt != T_UNDEF &&
  837.             nt != T_KEYWORD &&
  838.             nt != T_VAR &&
  839.             nt != T_FILE &&
  840.             nt != T_PROC &&
  841.             nt != T_FIELD)
  842.         error ("Label expected");
  843. }
  844.  
  845.         /* Check that the next token is a file name */
  846.  
  847. void ckfile (void)
  848. {
  849.     if (nt != T_FILE)
  850.         error ("File name expected");
  851. }
  852.  
  853.         /* Check that the next token is the appropriate keyword, and if so, get
  854.             new token */
  855.  
  856. void parsekeyword (int k)
  857. {
  858.     if (!iskeyword (k))
  859.     {
  860.         strcpy (buf,keywords[k]);
  861.         strupr (buf);
  862.         error ("%s expected",buf);
  863.     }
  864. }
  865.  
  866.         /* Check that the next token is an integer constant, and if so, return
  867.             its value and get new token */
  868.  
  869. long parseconst (void)
  870. {
  871.     long n;
  872.  
  873.     if (nt != T_INT)
  874.         error ("Integer expected");
  875.     n = ni;
  876.     lex ();
  877.     return n;
  878. }
  879.  
  880.         /* Parse a list of variable declarations */
  881.  
  882. void parsevarlist (var **vl,sym **s)
  883. {
  884.     var *v;
  885.  
  886.     while (nt == T_KEYWORD &&
  887.                 (    nkeyword == K_INT ||
  888.                     nkeyword == K_FLOAT ||
  889.                     nkeyword == K_DATE ||
  890.                     nkeyword == K_STR ||
  891.                     nkeyword == K_PTR))
  892.     {
  893.         v = alloc (sizeof (var));
  894.         switch (nkeyword)
  895.         {
  896.             case K_INT:
  897.                 lex ();
  898.                 v->type = V_INT;
  899.                 v->l = parseconst ();
  900.                 break;
  901.             case K_FLOAT:
  902.                 lex ();
  903.                 v->type = V_FLOAT;
  904.                 v->l = parseconst ();
  905.                 v->dec = parseconst ();
  906.                 break;
  907.             case K_DATE:
  908.                 lex ();
  909.                 v->type = V_DATE;
  910.                 break;
  911.             case K_STR:
  912.                 lex ();
  913.                 v->type = V_STR;
  914.                 v->l = parseconst ();
  915.                 break;
  916.             case K_PTR:
  917.                 lex ();
  918.                 v->type = V_PTR;
  919.                 break;
  920.         }
  921.         strcpy (v->name,buf);
  922.         lex ();
  923.         addsym (v->name,s,v);
  924.         addlist (*vl,v);
  925.     }
  926. }
  927.  
  928.         /* Routines for top-down expression parse */
  929.  
  930. void parsefactor (void)
  931. {
  932.     switch (nt)
  933.     {
  934.         case T_MINUS:
  935.             os ("-");
  936.             lex ();
  937.             parsefactor ();
  938.             break;
  939.         case T_NOT:
  940.             os ("!");
  941.             lex ();
  942.             parsefactor ();
  943.             break;
  944.         case T_INT:
  945.             oi (ni);
  946.             lex ();
  947.             break;
  948.         case T_FLOAT:
  949.             of (nf);
  950.             lex ();
  951.             break;
  952.         case T_STR:
  953.             os ("\"");
  954.             os (buf);
  955.             os ("\"");
  956.             lex ();
  957.             break;
  958.         case T_OPENBRACKET:
  959.             os ("(");
  960.             lex ();
  961.             parseexp ();
  962.             if (nt != T_CLOSEBRACKET)
  963.                 error ("')' expected");
  964.             lex ();
  965.             os (")");
  966.             break;
  967.         case T_VAR:
  968.             os (buf);
  969.             lex ();
  970.             break;
  971.         case T_FILE:
  972.             os (buf);
  973.             lex ();
  974.             if (nt != T_DOT)
  975.                 error ("'.' expected");
  976.             lex ();
  977.             os (".");
  978.             if (nt != T_FIELD)
  979.                 error ("Field name expected");
  980.             os (buf);
  981.             lex ();
  982.             break;
  983.         case T_KEYWORD:
  984.             switch (nkeyword)
  985.             {
  986.                 case K_ATODATE:
  987.                 case K_ATOF:
  988.                 case K_ATOI:
  989.                 case K_DATEDAY:
  990.                 case K_DATEMONTH:
  991.                 case K_DATEYEAR:
  992.                     os (buf);
  993.                     os (" (");
  994.                     lex ();
  995.                     parseexp ();
  996.                     os (")");
  997.                     break;
  998.                 case K_MAKEDATE:
  999.                     lex ();
  1000.                     os ("makedate (");
  1001.                     parseexp ();
  1002.                     os (",");
  1003.                     parseexp ();
  1004.                     os (",");
  1005.                     parseexp ();
  1006.                     os (")");
  1007.                     break;
  1008.                 case K_STRCMP:
  1009.                     lex ();
  1010.                     os ("memicmp (");
  1011.                     parseexp ();
  1012.                     os (",");
  1013.                     parseexp ();
  1014.                     os (",");
  1015.                     if (nt == T_INT)
  1016.                         parseexpr ();
  1017.                     else
  1018.                         oi (lastlen);
  1019.                     os (")");
  1020.                     break;
  1021.                 default:
  1022.                     error ("Expression expected");
  1023.             }
  1024.             break;
  1025.         default:
  1026.             error ("Expression expected");
  1027.     }
  1028. }
  1029.  
  1030. void parseterm (void)
  1031. {
  1032.     parsefactor ();
  1033.     while (nt == T_STAR || nt == T_SLASH || nt == T_PERCENT)
  1034.     {
  1035.         switch (nt)
  1036.         {
  1037.             case T_STAR:
  1038.                 os ("*");
  1039.                 break;
  1040.             case T_SLASH:
  1041.                 os ("/");
  1042.                 break;
  1043.             case T_PERCENT:
  1044.                 os ("%");
  1045.                 break;
  1046.         }
  1047.         lex ();
  1048.         parsefactor ();
  1049.     }
  1050. }
  1051.  
  1052. void parsemathexp (void)
  1053. {
  1054.     parseterm ();
  1055.     while (nt == T_PLUS || nt == T_MINUS)
  1056.     {
  1057.         if (nt == T_PLUS)
  1058.             os (" + ");
  1059.         else
  1060.             os (" - ");
  1061.         lex ();
  1062.         parseterm ();
  1063.     }
  1064. }
  1065.  
  1066. void parserelexp (void)
  1067. {
  1068.     parsemathexp ();
  1069.     while (nt == T_GT || nt == T_LT || nt == T_GE || nt == T_LE)
  1070.     {
  1071.         switch (nt)
  1072.         {
  1073.             case T_GT:
  1074.                 os (" > ");
  1075.                 break;
  1076.             case T_LT:
  1077.                 os (" < ");
  1078.                 break;
  1079.             case T_GE:
  1080.                 os (" >= ");
  1081.                 break;
  1082.             case T_LE:
  1083.                 os (" <= ");
  1084.                 break;
  1085.         }
  1086.         lex ();
  1087.         parsemathexp ();
  1088.     }
  1089. }
  1090.  
  1091. void parseeqexp (void)
  1092. {
  1093.     parserelexp ();
  1094.     while (nt == T_EQ || nt == T_NE)
  1095.     {
  1096.         if (nt == T_EQ)
  1097.             os (" == ");
  1098.         else
  1099.             os (" != ");
  1100.         lex ();
  1101.         parserelexp ();
  1102.     }
  1103. }
  1104.  
  1105. void parseandexp (void)
  1106. {
  1107.     parseeqexp ();
  1108.     while (nt == T_AND)
  1109.     {
  1110.         os (" && ");
  1111.         lex ();
  1112.         parseeqexp ();
  1113.     }
  1114. }
  1115.  
  1116. void parseexp (void)
  1117. {
  1118.     parseandexp ();
  1119.     while (nt == T_OR)
  1120.     {
  1121.         os (" || ");
  1122.         lex ();
  1123.         parseandexp ();
  1124.     }
  1125. }
  1126.  
  1127.         /* Parse a statement, or zero or more statements surrounded by braces,
  1128.             with appropriate output indentation */
  1129.  
  1130. void parseindentstatement (void)
  1131. {
  1132.     if (nt == T_OPENBRACE)
  1133.         parsestatement ();
  1134.     else
  1135.     {
  1136.         indent++;
  1137.         parsestatement ();
  1138.         indent--;
  1139.     }
  1140. }
  1141.  
  1142.         /* Parse the section of a PRINT statement common to all data types */
  1143.  
  1144. void parseprint (void)
  1145. {
  1146.     lex ();
  1147.     parseexp ();        /* X */
  1148.     os (",");
  1149.     parseexp ();        /* Y */
  1150.     os (",");
  1151.     parseexp ();        /* Expression to be displayed */
  1152. }
  1153.  
  1154.         /* Parse the section of an SPRINT statement common to all data types */
  1155.  
  1156. void parsesprint (void)
  1157. {
  1158.     lex ();
  1159.     parseexp ();        /* String variable */
  1160.     os (",");
  1161.     parseexp ();        /* Expression to be printed */
  1162. }
  1163.  
  1164.         /* Parse a direction keyword for an EDIT statement, optionally followed
  1165.             by a label reference */
  1166.  
  1167. void parsedirection (void)
  1168. {
  1169.     int i;
  1170.  
  1171.     if (nt != T_KEYWORD)
  1172.         error ("Direction expected");
  1173.     for (i=0; i!=MAXDIR; i++)
  1174.         if (!strcmpl (dirname[i],buf))
  1175.         {
  1176.             lex ();
  1177.             dirlabel[i][0] = '*';
  1178.             if (nt == T_ASSIGN)        /* If label reference present, record it */
  1179.             {
  1180.                 lex ();
  1181.                 cklabel ();
  1182.                 strupr (buf);
  1183.                 strcpy (dirlabel[i],buf);
  1184.                 lex ();
  1185.             }
  1186.             return;
  1187.         }
  1188.     error ("Direction expected");
  1189. }
  1190.  
  1191.         /* Parse a direction for an EDIT statement, or zero or more directions
  1192.             surrounded by braces */
  1193.  
  1194. void parsedirections (void)
  1195. {
  1196.     int i;
  1197.     int ndir;
  1198.  
  1199.     os (",");
  1200.  
  1201.             /* Read direction data */
  1202.  
  1203.     memset (dirlabel,0,sizeof dirlabel);
  1204.     if (nt == T_OPENBRACE)
  1205.     {
  1206.         lex ();
  1207.         while (nt != T_CLOSEBRACE)
  1208.             parsedirection ();
  1209.         lex ();
  1210.     }
  1211.     else
  1212.         parsedirection ();
  1213.  
  1214.             /* Output flags indicating allowed directions */
  1215.  
  1216.     ndir = 0;
  1217.     for (i=0; i!=MAXDIR; i++)
  1218.         if (dirlabel[i][0])
  1219.             ndir++;
  1220.     for (i=0; i!=MAXDIR; i++)
  1221.         if (dirlabel[i][0])
  1222.         {
  1223.             os ("DF_");
  1224.             os (dirname[i]);
  1225.             ndir--;
  1226.             if (ndir)
  1227.                 os (" | ");
  1228.         }
  1229.     os (");");
  1230.  
  1231.             /* Output switch statement on direction */
  1232.  
  1233.     nl ();
  1234.     os ("switch (dir)");
  1235.     nl ();
  1236.     os ("{");
  1237.     indent++;
  1238.     for (i=0; i!=MAXDIR; i++)
  1239.         if (dirlabel[i][0] != 0 && dirlabel[i][0] != '*')
  1240.         {
  1241.             nl ();
  1242.             os ("case DIR_");
  1243.             os (dirname[i]);
  1244.             os (":");
  1245.             indent++;
  1246.             nl ();
  1247.             os ("goto ");
  1248.             os (dirlabel[i]);
  1249.             os (";");
  1250.             indent--;
  1251.         }
  1252.     indent--;
  1253.     nl ();
  1254.     os ("}");
  1255. }
  1256.  
  1257.         /* Parse an EDIT statement */
  1258.  
  1259. void parseedit (void)
  1260. {
  1261.     switch (nvar->type)
  1262.     {
  1263.         case V_INT:
  1264.             switch (nvar->l)
  1265.             {
  1266.                 case 1:
  1267.                 case 2:
  1268.                     os ("editbyte (&");
  1269.                     break;
  1270.                 case 3:
  1271.                 case 4:
  1272.                     os ("editshort (&");
  1273.                     break;
  1274.                 default:
  1275.                     os ("editlong (&");
  1276.             }
  1277.             break;
  1278.         case V_FLOAT:
  1279.             os ("editfloat (&");
  1280.             break;
  1281.         case V_DATE:
  1282.             os ("editdate (&");
  1283.             break;
  1284.         case V_STR:
  1285.             os ("editstr (");
  1286.             break;
  1287.         case V_PTR:
  1288.             warning ("Can't edit a pointer variable");
  1289.             break;
  1290.     }
  1291.     if (nt == T_FIELD)
  1292.     {
  1293.         if (nvar == &nfile->index)
  1294.             warning ("Can't edit index field");
  1295.         os (nfile->name);
  1296.         os (".");
  1297.     }
  1298.     os (buf);
  1299.     if (nvar->type != V_DATE)
  1300.     {
  1301.         os (",");
  1302.         oi (nvar->l);
  1303.         if (nvar->type == V_FLOAT)
  1304.         {
  1305.             os (",");
  1306.             oi (nvar->dec);
  1307.         }
  1308.     }
  1309.     lex ();
  1310.     os (",");
  1311.     parseexp ();
  1312.     os (",");
  1313.     parseexp ();
  1314.     parsedirections ();
  1315. }
  1316.  
  1317.         /* Parse a statement */
  1318.  
  1319. void parsestatement (void)
  1320. {
  1321.     file *f,*f2;
  1322.     int x,y,i;
  1323.     str vname;
  1324.  
  1325.     switch (nt)
  1326.     {
  1327.         case T_OPENBRACE:        /* Zero or more statements surrounded by braces */
  1328.             nl ();
  1329.             os ("{");
  1330.             lex ();
  1331.             indent++;
  1332.             while (nt != T_CLOSEBRACE)
  1333.                 parsestatement ();
  1334.             indent--;
  1335.             nl ();
  1336.             os ("}");
  1337.             lex ();
  1338.             break;
  1339.         case T_COLON:            /* A label */
  1340.             lex ();
  1341.             cklabel ();
  1342.             strupr (buf);
  1343.             fprintf (outfile,"\n\n%s:",buf);
  1344.             lex ();
  1345.             if (nt == T_CLOSEBRACE)
  1346.                 os (";");
  1347.             break;
  1348.         case T_VAR:                /* Assignment to a variable */
  1349.             nl ();
  1350.             os (buf);
  1351.             lex ();
  1352.             if (nt != T_ASSIGN)
  1353.                 error ("'=' expected");
  1354.             lex ();
  1355.             os (" = ");
  1356.             parseexp ();
  1357.             os (";");
  1358.             break;
  1359.         case T_FILE:            /* Assignment to a field */
  1360.             nl ();
  1361.             os (buf);
  1362.             lex ();
  1363.             if (nt != T_DOT)
  1364.                 error ("'.' expected");
  1365.             lex ();
  1366.             os (".");
  1367.             if (nt != T_FIELD)
  1368.                 error ("Field name expected");
  1369.             os (buf);
  1370.             if (nt != T_ASSIGN)
  1371.                 error ("'=' expected");
  1372.             lex ();
  1373.             os (" = ");
  1374.             parseexp ();
  1375.             os (";");
  1376.             break;
  1377.         case T_PROC:            /* A procedure call */
  1378.             nl ();
  1379.             os (buf);
  1380.             os (" ();");
  1381.             lex ();
  1382.             break;
  1383.         case T_KEYWORD:
  1384.             switch (nkeyword)
  1385.             {
  1386.                 case K_EDIT:        /* Edit a variable or field */
  1387.                     lex ();
  1388.                     nl ();
  1389.                     switch (nt)
  1390.                     {
  1391.                         case T_VAR:
  1392.                             parseedit ();
  1393.                             break;
  1394.                         case T_FILE:
  1395.                             lex ();
  1396.                             if (nt != T_DOT)
  1397.                                 error ("'.' expected");
  1398.                             lex ();
  1399.                             if (nt != T_FIELD)
  1400.                                 error ("Field name expected");
  1401.                             parseedit ();
  1402.                             break;
  1403.                         default:
  1404.                             error ("Variable name expected");
  1405.                     }
  1406.                     break;
  1407.                 case K_SELECT:        /* Allow user to select a data record */
  1408.                     lex ();
  1409.                     ckfile ();
  1410.                     nl ();
  1411.                     os ("select (");
  1412.                     os (buf);
  1413.                     os ("file,");
  1414.                     os (buf);
  1415.                     os ("indexfile,&");
  1416.                     os (buf);
  1417.                     os ("ptr,&");
  1418.                     os (buf);
  1419.                     os (",sizeof ");
  1420.                     os (buf);
  1421.                     os (",");
  1422.                     os (buf);
  1423.                     os (".");
  1424.                     os (nfile->index.name);
  1425.                     os (",");
  1426.                     oi (nfile->index.l);
  1427.                     os (",");
  1428.                     lex ();
  1429.                     parseexp ();
  1430.                     os (",");
  1431.                     parseexp ();
  1432.                     parsedirections ();
  1433.                     break;
  1434.                 case K_FIND:        /* Find a data record given the index value */
  1435.                     lex ();
  1436.                     ckfile ();
  1437.                     nl ();
  1438.                     os ("find (");
  1439.                     os (buf);
  1440.                     os ("file,");
  1441.                     os (buf);
  1442.                     os ("indexfile,&");
  1443.                     os (buf);
  1444.                     os (",sizeof ");
  1445.                     os (buf);
  1446.                     os (",");
  1447.                     oi (nfile->index.l);
  1448.                     os (",");
  1449.                     lex ();
  1450.                     parseexp ();
  1451.                     os (");");
  1452.                     break;
  1453.                 case K_READ:        /* Read a data record */
  1454.                     lex ();
  1455.                     ckfile ();
  1456.                     nl ();
  1457.                     os ("Read (");
  1458.                     f = nfile;
  1459.                     if (f->table)
  1460.                     {
  1461.                         os ("miscfile,");
  1462.                         os (buf);
  1463.                         os ("miscoff + (");
  1464.                         lex ();
  1465.                         parseexp ();
  1466.                         os (")*sizeof ");
  1467.                         os (f->name);
  1468.                         os (",&");
  1469.                         os (f->name);
  1470.                         os (",sizeof ");
  1471.                         os (f->name);
  1472.                         os (");");
  1473.                     }
  1474.                     else
  1475.                     {
  1476.                         os (buf);
  1477.                         os ("file,");
  1478.                         if (nt == T_VAR)
  1479.                         {
  1480.                             if (nvar->type != V_PTR)
  1481.                                 warning ("Variable '%s' is not of type PTR",buf);
  1482.                             strcpy (vname,buf);
  1483.                             lex ();
  1484.                             os (vname);
  1485.                             os (",&");
  1486.                             os (f->name);
  1487.                             os (",sizeof ");
  1488.                             os (f->name);
  1489.                             os (");");
  1490.                             nl ();
  1491.                             os (f->name);
  1492.                             os ("ptr = ");
  1493.                         }
  1494.                         else
  1495.                         {
  1496.                             if (nt != T_FILE)
  1497.                                 error ("File read location must be a variable of type PTR");
  1498.                             f2 = nfile;
  1499.                             lex ();
  1500.                             if (nt != T_DOT)
  1501.                                 error ("'.' expected");
  1502.                             lex ();
  1503.                             if (nt != T_FIELD)
  1504.                                 error ("Field name expected");
  1505.                             strcpy (vname,buf);
  1506.                             lex ();
  1507.                             os (f2->name);
  1508.                             os (".");
  1509.                             os (vname);
  1510.                             os (",&");
  1511.                             os (f->name);
  1512.                             os (",sizeof ");
  1513.                             os (f->name);
  1514.                             os (");");
  1515.                             nl ();
  1516.                             os (f->name);
  1517.                             os ("ptr = ");
  1518.                             os (f2->name);
  1519.                             os (".");
  1520.                         }
  1521.                         os (vname);
  1522.                         os (";");
  1523.                     }
  1524.                     break;
  1525.                 case K_WRITE:        /* Write back currently selected record to file */
  1526.                     lex ();
  1527.                     ckfile ();
  1528.                     nl ();
  1529.                     os ("Write (");
  1530.                     f = nfile;
  1531.                     if (f->table)
  1532.                     {
  1533.                         os ("miscfile,");
  1534.                         os (buf);
  1535.                         os ("miscoff + (");
  1536.                         lex ();
  1537.                         parseexp ();
  1538.                         os (")*sizeof ");
  1539.                         os (f->name);
  1540.                         os (",&");
  1541.                         os (f->name);
  1542.                         os (",sizeof ");
  1543.                         os (f->name);
  1544.                         os (");");
  1545.                     }
  1546.                     else
  1547.                     {
  1548.                         os (buf);
  1549.                         os ("file,");
  1550.                         os (buf);
  1551.                         os ("ptr,&");
  1552.                         os (buf);
  1553.                         os (",sizeof ");
  1554.                         os (buf);
  1555.                         os (");");
  1556.                         lex ();
  1557.                     }
  1558.                     break;
  1559.                 case K_CREATE:        /* Create a new record */
  1560.                     lex ();
  1561.                     x = -1;
  1562.                     if (nt == T_INT)
  1563.                     {
  1564.                         x = parseconst ();
  1565.                         y = parseconst ();
  1566.                     }
  1567.                     ckfile ();
  1568.                     if (nfile->table)
  1569.                         warning ("Can't create record on table");
  1570.                     if (x >= 0 && !nfile->index.l)
  1571.                         warning ("X, Y parameters should only be provided for creation on indexed files");
  1572.                     if (x < 0 && nfile->index.l)
  1573.                         warning ("X, Y parameters should be provided for creation on indexed files");
  1574.                     nl ();
  1575.                     os (buf);
  1576.                     os (" = blank");
  1577.                     os (buf);
  1578.                     os (";");
  1579.                     nl ();
  1580.                     os ("create");
  1581.                     if (x >= 0)
  1582.                         os ("index");
  1583.                     os (" (");
  1584.                     os (buf);
  1585.                     os ("file,&");
  1586.                     os (buf);
  1587.                     os ("ptr,&");
  1588.                     os (buf);
  1589.                     os (",sizeof ");
  1590.                     os (buf);
  1591.                     os (",");
  1592.                     os (buf);
  1593.                     os ("miscoff");
  1594.                     if (x >= 0)        /* File is indexed, so index value must be input */
  1595.                     {
  1596.                         os (",");
  1597.                         os (buf);
  1598.                         os (".");
  1599.                         os (nfile->index.name);
  1600.                         os (",");
  1601.                         oi (nfile->index.l);
  1602.                         os (",");
  1603.                         os (buf);
  1604.                         os ("indexfile,");
  1605.                         oi (x);
  1606.                         os (",");
  1607.                         oi (y);
  1608.                         lex ();
  1609.                         parsedirections ();
  1610.                     }
  1611.                     else
  1612.                     {
  1613.                         os (");");
  1614.                         lex ();
  1615.                     }
  1616.                     break;
  1617.                 case K_DELETE:        /* Delete currently selected record */
  1618.                     lex ();
  1619.                     ckfile ();
  1620.                     if (nfile->table)
  1621.                         warning ("Can't delete record from table");
  1622.                     nl ();
  1623.                     if (nfile->index.l)
  1624.                         os ("deleteindex (");
  1625.                     else
  1626.                         os ("delete (");
  1627.                     os (buf);
  1628.                     os ("file,");
  1629.                     os (buf);
  1630.                     os ("ptr,&");
  1631.                     os (buf);
  1632.                     os (",");
  1633.                     os (buf);
  1634.                     os ("miscoff");
  1635.                     if (nfile->index.l)
  1636.                     {
  1637.                         os (",");
  1638.                         os (buf);
  1639.                         os (".");
  1640.                         os (nfile->index.name);
  1641.                         os (",");
  1642.                         oi (nfile->index.l);
  1643.                         os (",");
  1644.                         os (buf);
  1645.                         os ("indexfile");
  1646.                     }
  1647.                     os (");");
  1648.                     lex ();
  1649.                     break;
  1650.                 case K_LINK:
  1651.                 case K_UNLINK:
  1652.                     nl ();
  1653.                     os ("rec");
  1654.                     os (buf);
  1655.                     os (" (");
  1656.                     lex ();
  1657.                     ckfile ();
  1658.                     os (buf);
  1659.                     os ("file,");
  1660.                     os (buf);
  1661.                     os ("ptr,&");
  1662.                     os (buf);
  1663.                     os (".");
  1664.                     f = nfile;
  1665.                     lex ();
  1666.                     ckfile ();
  1667.                     os (buf);
  1668.                     os ("ptr,foffset (");
  1669.                     os (f->name);
  1670.                     os (",");
  1671.                     os (buf);
  1672.                     os ("ptr),");
  1673.                     os (buf);
  1674.                     os ("file,");
  1675.                     os (buf);
  1676.                     os ("ptr,&");
  1677.                     os (buf);
  1678.                     os (".");
  1679.                     os (f->name);
  1680.                     os ("first,foffset (");
  1681.                     os (buf);
  1682.                     os (",");
  1683.                     os (f->name);
  1684.                     os ("first));");
  1685.                     lex ();
  1686.                     break;
  1687.                 case K_SCROLL:        /* Scrolling edit */
  1688.                     lex ();
  1689.                     nl ();
  1690.                     os ("scrolledit (");
  1691.                     ckfile ();
  1692.                     os (buf);
  1693.                     os ("file,&");
  1694.                     os (buf);
  1695.                     os ("ptr,&");
  1696.                     os (buf);
  1697.                     os (",foffset (");
  1698.                     os (buf);
  1699.                     os (",");
  1700.                     f = nfile;
  1701.                     lex ();
  1702.                     ckfile ();
  1703.                     os (buf);
  1704.                     os ("ptr),sizeof ");
  1705.                     os (f->name);
  1706.                     os (",");
  1707.                     os (buf);
  1708.                     os ("file,");
  1709.                     os (buf);
  1710.                     os ("ptr,&");
  1711.                     os (buf);
  1712.                     os (",foffset (");
  1713.                     os (buf);
  1714.                     os (",");
  1715.                     os (f->name);
  1716.                     os ("first),sizeof ");
  1717.                     os (buf);
  1718.                     os (",&blank");
  1719.                     os (f->name);
  1720.                     os (",");
  1721.                     os (f->name);
  1722.                     os ("miscoff,");
  1723.                     lex ();
  1724.                     parseexp ();
  1725.                     os (",");
  1726.                     if (nt != T_PROC)
  1727.                         error ("Procedure name expected");
  1728.                     os (buf);
  1729.                     os (",");
  1730.                     lex ();
  1731.                     switch (nt)
  1732.                     {
  1733.                         case T_PROC:
  1734.                             os (buf);
  1735.                             lex ();
  1736.                             break;
  1737.                         case T_INT:
  1738.                             if (parseconst () == 0)
  1739.                             {
  1740.                                 os ("0");
  1741.                                 break;
  1742.                             }
  1743.                         default:
  1744.                             error ("Procedure name or zero expected");
  1745.                     }
  1746.                     os (",");
  1747.                     parseexp ();
  1748.                     os (",");
  1749.                     parseexp ();
  1750.                     os (",");
  1751.                     parseexp ();
  1752.                     os (",");
  1753.                     parseexp ();
  1754.                     os (");");
  1755.                     break;
  1756.                 case K_GOTO:        /* Jump to a label */
  1757.                     lex ();
  1758.                     cklabel ();
  1759.                     nl ();
  1760.                     os ("goto ");
  1761.                     strupr (buf);
  1762.                     os (buf);
  1763.                     os (";");
  1764.                     break;
  1765.                 case K_BREAK:
  1766.                 case K_CONTINUE:
  1767.                 case K_RETURN:
  1768.                     nl ();
  1769.                     os (buf);
  1770.                     os (";");
  1771.                     lex ();
  1772.                     break;
  1773.                 case K_IF:            /* C-style IF */
  1774.                     nl ();
  1775.                     os ("if (");
  1776.                     lex ();
  1777.                     parseexp ();
  1778.                     os (")");
  1779.                     parseindentstatement ();
  1780.                     if (iskeyword (K_ELSE))
  1781.                     {
  1782.                         nl ();
  1783.                         os ("else");
  1784.                         parseindentstatement ();
  1785.                     }
  1786.                     break;
  1787.                 case K_WHILE:        /* C-style WHILE */
  1788.                     nl ();
  1789.                     os ("while (");
  1790.                     lex ();
  1791.                     parseexp ();
  1792.                     os (")");
  1793.                     parseindentstatement ();
  1794.                     break;
  1795.                 case K_DO:            /* C-style DO...WHILE */
  1796.                     nl ();
  1797.                     os ("do");
  1798.                     lex ();
  1799.                     parseindentstatement ();
  1800.                     parsekeyword (K_WHILE);
  1801.                     nl ();
  1802.                     os ("while (");
  1803.                     parseexp ();
  1804.                     os (");");
  1805.                     break;
  1806.                 case K_SWITCH:        /* Limited CASE statement - list of labels to
  1807.                                             jump to on values of an integer */
  1808.                     nl ();
  1809.                     os ("switch (");
  1810.                     lex ();
  1811.                     parseexp ();
  1812.                     os (")");
  1813.                     nl ();
  1814.                     os ("{");
  1815.                     indent++;
  1816.                     if (nt != T_OPENBRACE)
  1817.                         error ("'{' expected");
  1818.                     lex ();
  1819.                     i = 0;
  1820.                     while (nt != T_CLOSEBRACE)
  1821.                     {
  1822.                         cklabel ();
  1823.                         nl ();
  1824.                         os ("case ");
  1825.                         oi (i);
  1826.                         i++;
  1827.                         os (":");
  1828.                         indent++;
  1829.                         nl ();
  1830.                         os ("goto ");
  1831.                         strupr (buf);
  1832.                         os (buf);
  1833.                         os (";");
  1834.                         lex ();
  1835.                         indent--;
  1836.                     }
  1837.                     lex ();
  1838.                     indent--;
  1839.                     nl ();
  1840.                     os ("}");
  1841.                     break;
  1842.                 case K_PRINTINT:    /* Display an integer expression */
  1843.                     nl ();
  1844.                     os ("printint (");
  1845.                     parseprint ();
  1846.                     os (",");
  1847.                     if (nt == T_INT)
  1848.                         parseexp ();
  1849.                     else
  1850.                         oi (lastlen);
  1851.                     os (");");
  1852.                     break;
  1853.                                         /* Display a floating-point expression */
  1854.                 case K_PRINTFLOAT:
  1855.                     nl ();
  1856.                     os ("printfloat (");
  1857.                     parseprint ();
  1858.                     os (",");
  1859.                     if (nt == T_INT)
  1860.                     {
  1861.                         parseexp ();
  1862.                         os (",");
  1863.                         parseexp ();
  1864.                     }
  1865.                     else
  1866.                     {
  1867.                         oi (lastlen);
  1868.                         os (",");
  1869.                         oi (lastdec);
  1870.                     }
  1871.                     os (");");
  1872.                     break;
  1873.                 case K_PRINTDATE:    /* Display a date expression */
  1874.                     nl ();
  1875.                     os ("printdate (");
  1876.                     parseprint ();
  1877.                     os (");");
  1878.                     break;
  1879.                 case K_PRINTSTR:    /* Display a string expression */
  1880.                     nl ();
  1881.                     os ("printstr (");
  1882.                     parseprint ();
  1883.                     os (",");
  1884.                     if (nt == T_INT)
  1885.                         parseexp ();
  1886.                     else
  1887.                         oi (lastlen);
  1888.                     os (");");
  1889.                     break;
  1890.                 case K_SPRINTINT:    /* Convert an integer expression to ASCII */
  1891.                     nl ();
  1892.                     os ("sprintint (");
  1893.                     parsesprint ();
  1894.                     os (",");
  1895.                     if (nt == T_INT)
  1896.                         parseexp ();
  1897.                     else
  1898.                         oi (lastlen);
  1899.                     os (");");
  1900.                     break;
  1901.                                         /* Convert a floating point expression to ASCII */
  1902.                 case K_SPRINTFLOAT:
  1903.                     nl ();
  1904.                     os ("sprintfloat (");
  1905.                     parsesprint ();
  1906.                     os (",");
  1907.                     if (nt == T_INT)
  1908.                     {
  1909.                         parseexp ();
  1910.                         os (",");
  1911.                         parseexp ();
  1912.                     }
  1913.                     else
  1914.                     {
  1915.                         oi (lastlen);
  1916.                         os (",");
  1917.                         oi (lastdec);
  1918.                     }
  1919.                     os (");");
  1920.                     break;
  1921.                                         /* Convert a date expression to ASCII */
  1922.                 case K_SPRINTDATE:
  1923.                     nl ();
  1924.                     os ("sprintdate (");
  1925.                     parsesprint ();
  1926.                     os (");");
  1927.                     break;
  1928.                 case K_CURSOR:        /* Move the hardware cursor to a point on screen */
  1929.                     lex ();
  1930.                     nl ();
  1931.                     os ("cursor (");
  1932.                     parseexp ();
  1933.                     os (",");
  1934.                     parseexp ();
  1935.                     os (");");
  1936.                     break;
  1937.                 case K_PAUSE:        /* Wait for a keypress */
  1938.                     lex ();
  1939.                     nl ();
  1940.                     os ("getkey ();");
  1941.                     break;
  1942.                 case K_GETKEY:        /* Wait for a keypress, and put it into a string */
  1943.                     lex ();
  1944.                     nl ();
  1945.                     parseexpr ();
  1946.                     os ("[0] = getkey ();");
  1947.                     break;
  1948.                 case K_STRCPY:        /* Copy one string to another */
  1949.                     lex ();
  1950.                     nl ();
  1951.                     os ("memcpy (");
  1952.                     parseexp ();
  1953.                     os (",");
  1954.                     parseexp ();
  1955.                     os (",");
  1956.                     if (nt == T_INT)
  1957.                         parseexpr ();
  1958.                     else
  1959.                         oi (lastlen);
  1960.                     os (");");
  1961.                     break;
  1962.                 default:
  1963.                     error ("Statement expected");
  1964.             }
  1965.             break;
  1966.         default:
  1967.             error ("Statement expected");
  1968.     }
  1969. }
  1970.  
  1971.         /* Output C code variable declarations */
  1972.  
  1973. void outvarlist (var *v)
  1974. {
  1975.     while (v)
  1976.     {
  1977.         nl ();
  1978.         switch (v->type)
  1979.         {
  1980.             case V_INT:
  1981.                 switch (v->l)
  1982.                 {
  1983.                     case 1:
  1984.                     case 2:
  1985.                         os ("signed char ");
  1986.                         break;
  1987.                     case 3:
  1988.                     case 4:
  1989.                         os ("short ");
  1990.                         break;
  1991.                     default:
  1992.                         os ("long ");
  1993.                 }
  1994.                 os (v->name);
  1995.                 os (";");
  1996.                 break;
  1997.             case V_FLOAT:
  1998.                 os ("double ");
  1999.                 os (v->name);
  2000.                 os (";");
  2001.                 break;
  2002.             case V_DATE:
  2003.                 os ("unsigned short ");
  2004.                 os (v->name);
  2005.                 os (";");
  2006.                 break;
  2007.             case V_STR:
  2008.                 os ("char ");
  2009.                 os (v->name);
  2010.                 os ("[");
  2011.                 oi (v->l);
  2012.                 os ("];");
  2013.                 break;
  2014.             case V_PTR:
  2015.                 os ("long ");
  2016.                 os (v->name);
  2017.                 os (";");
  2018.                 break;
  2019.         }
  2020.         v = v->next;
  2021.     }
  2022. }
  2023.  
  2024.         /* Output null pointer value */
  2025.  
  2026. void blankptr (void)
  2027. {
  2028.     nl ();
  2029.     os ("-1,");
  2030. }
  2031.  
  2032.         /* Output null value for a variable */
  2033.  
  2034. void outblank (var *v)
  2035. {
  2036.     int i;
  2037.  
  2038.     nl ();
  2039.     switch (v->type)
  2040.     {
  2041.         case V_DATE:
  2042.             os ("BLANKDATE,");
  2043.             break;
  2044.         case V_STR:
  2045.             for (i=v->l; i--;)
  2046.                 os ("' ',");
  2047.             break;
  2048.         default:
  2049.             os ("0,");
  2050.     }
  2051. }
  2052.  
  2053.         /* Determine physical size of a data record */
  2054.  
  2055. recsize (file *f)
  2056. {
  2057.     int n;
  2058.     file *f2;
  2059.     var *v;
  2060.     fileid *fi;
  2061.  
  2062.             /* Index field */
  2063.  
  2064.     n = f->index.l;
  2065.  
  2066.             /* Normal fields */
  2067.  
  2068.     for (v=f->fields; v; v=v->next)
  2069.         switch (v->type)
  2070.         {
  2071.             case V_INT:
  2072.                 switch (v->l)
  2073.                 {
  2074.                     case 1:
  2075.                     case 2:
  2076.                         n++;
  2077.                         break;
  2078.                     case 3:
  2079.                     case 4:
  2080.                         align (n);
  2081.                         n += sizeof (short);
  2082.                         break;
  2083.                     default:
  2084.                         align (n);
  2085.                         n += sizeof (long);
  2086.                 }
  2087.                 break;
  2088.             case V_FLOAT:
  2089.                 align (n);
  2090.                 n += sizeof (double);
  2091.                 break;
  2092.             case V_DATE:
  2093.                 align (n);
  2094.                 n += sizeof (short);
  2095.                 break;
  2096.             case V_STR:
  2097.                 n += v->l;
  2098.                 break;
  2099.         }
  2100.  
  2101.     align (n);
  2102.  
  2103.             /* Files this one is linked on */
  2104.  
  2105.     for (fi=f->on; fi; fi=fi->next)
  2106.         n += 3*sizeof (long);
  2107.  
  2108.             /* Files that are linked on this one */
  2109.  
  2110.     for (f2=files; f2; f2=f2->next)
  2111.         for (fi=f2->on; fi; fi=fi->next)
  2112.             if (fi->p == f)
  2113.             {
  2114.                 n += 2*sizeof (long);
  2115.                 break;
  2116.             }
  2117.  
  2118.     return n;
  2119. }
  2120.  
  2121.         /* Functions to output menu structure */
  2122.  
  2123. void addmenu (menutree *p,int i,char *func)
  2124. {
  2125.     menutree *mt;
  2126.     submenu *sm;
  2127.  
  2128.     for (sm=p->sm; sm; sm=sm->next)
  2129.         if (!strcmp (sm->mt->text,menutext[i]))
  2130.         {
  2131.             mt = sm->mt;
  2132.             break;
  2133.         }
  2134.     if (sm)
  2135.     {
  2136.         i++;
  2137.         if (menutext[i] == 0)
  2138.             error ("Duplicate menu option '%s'",func);
  2139.         addmenu (mt,i,func);
  2140.     }
  2141.     else
  2142.         do
  2143.         {
  2144.             mt = alloc (sizeof (menutree));
  2145.             mt->text = menutext[i];
  2146.             mt->func = func;
  2147.             mt->sm = 0;
  2148.             sm = alloc (sizeof (submenu));
  2149.             sm->mt = mt;
  2150.             addlist (p->sm,sm);
  2151.             p = mt;
  2152.             i++;
  2153.         }
  2154.         while (menutext[i]);
  2155. }
  2156.  
  2157. void addoption (menutree *p,char *text,char *func)
  2158. {
  2159.     int i;
  2160.     char *s;
  2161.  
  2162.     i = 0;
  2163.     s = strtok (text,"!");
  2164.     do
  2165.     {
  2166.         menutext[i++] = s;
  2167.         if (i == MAXMENU)
  2168.             error ("Menu tree too deep: '%s'",text);
  2169.         s = strtok (0,"!");
  2170.     }
  2171.     while (s);
  2172.     menutext[i] = 0;
  2173.     addmenu (p,0,func);
  2174. }
  2175.  
  2176. void menuoutput (menutree *p,char *text)
  2177. {
  2178.     char nexttext[4 + 1 + MAXMENU*2];
  2179.     int i;
  2180.     submenu *sm;
  2181.  
  2182.     for (sm=p->sm,i=0; sm; sm=sm->next,i++)
  2183.         if (sm->mt->sm)
  2184.         {
  2185.             sprintf (nexttext,"%s%02d",text,i);
  2186.             menuoutput (sm->mt,nexttext);
  2187.         }
  2188.     nl ();
  2189.     os ("execmenuitem ");
  2190.     os (text);
  2191.     os ("[] =");
  2192.     nl ();
  2193.     os ("{");
  2194.     indent = 1;
  2195.     for (sm=p->sm,i=0; sm; sm=sm->next,i++)
  2196.     {
  2197.         nl ();
  2198.         os ("\"");
  2199.         os (sm->mt->text);
  2200.         os ("\",");
  2201.         if (sm->mt->sm)
  2202.         {
  2203.             sprintf (nexttext,"%s%02d",text,i);
  2204.             os (nexttext);
  2205.             os (",0,");
  2206.         }
  2207.         else
  2208.         {
  2209.             os ("0,");
  2210.             os (sm->mt->func);
  2211.             os (",");
  2212.         }
  2213.     }
  2214.     nl ();
  2215.     os ("0");
  2216.     indent = 0;
  2217.     nl ();
  2218.     os ("};");
  2219.     nl ();
  2220. }
  2221.  
  2222. main (int argc,char **argv)
  2223. {
  2224.     var *v,*v2;
  2225.     file *f,*f2;
  2226.     proc *p;
  2227.     fileid *fi;
  2228.     static menutree mt;
  2229.  
  2230.     printf ("Database Program Generator v0.0 by Russell Wallace  " __DATE__ "\n");
  2231.  
  2232.     if (argc != 2)
  2233.     {
  2234.         printf ("Usage: dpg filename\n");
  2235.         return 1;
  2236.     }
  2237.  
  2238.             /* Get output file name */
  2239.  
  2240.     strcpy (outfilename,argv[1]);
  2241.     if (!strchr (outfilename,'.'))
  2242.         strcat (outfilename,".dpg");
  2243.  
  2244.             /* Open input file */
  2245.  
  2246.     infile = fopen (outfilename,"r");
  2247.     if (infile == 0)
  2248.     {
  2249.         printf ("Can't open '%s'\n",outfilename);
  2250.         return 1;
  2251.     }
  2252.  
  2253.             /* Create output file */
  2254.  
  2255.     strcpy (strchr (outfilename,'.'),".c");
  2256.     outfile = fopen (outfilename,"w");
  2257.     if (outfile == 0)
  2258.     {
  2259.         printf ("Can't create '%s'\n",outfilename);
  2260.         return 1;
  2261.     }
  2262.  
  2263.             /* Initialize lexical analyzer */
  2264.  
  2265.     readc ();
  2266.     lex ();
  2267.  
  2268.             /* Standard stuff for output file */
  2269.  
  2270.     os ("#include\t<stdio.h>");
  2271.     nl ();
  2272.     os ("#include\t<stdlib.h>");
  2273.     nl ();
  2274.     os ("#include\t<string.h>");
  2275.     nl ();
  2276.     os ("#include\t<fcntl.h>");
  2277.     nl ();
  2278.     os ("#include\t<io.h>");
  2279.     nl ();
  2280.     os ("#include\t\"video.h\"");
  2281.     nl ();
  2282.     os ("#include\t\"files.h\"");
  2283.     nl ();
  2284.  
  2285.             /* Global variables */
  2286.  
  2287.     v = alloc (sizeof (var));
  2288.     strcpy (v->name,"fieldno");
  2289.     v->type = V_INT;
  2290.     v->l = 4;
  2291.     addsym ("fieldno",&globalnames,v);
  2292.     addlist (globals,v);
  2293.  
  2294.     parsevarlist (&globals,&globalnames);
  2295.  
  2296.     outvarlist (globals);
  2297.     if (globals)
  2298.         nl ();
  2299.  
  2300.             /* File definitions */
  2301.  
  2302.     parsekeyword (K_FILES);
  2303.  
  2304.     while (nt == T_UNDEF)
  2305.     {
  2306.                 /* Create file structure */
  2307.  
  2308.         f = alloc (sizeof (file));
  2309.         memset (f,0,sizeof (file));
  2310.         addsym (buf,&filenames,f);
  2311.         addlist (files,f);
  2312.         strcpy (f->name,buf);
  2313.         lex ();
  2314.  
  2315.                 /* Fields */
  2316.  
  2317.         if (nt != T_OPENBRACE)
  2318.             error ("'{' expected");
  2319.         lex ();
  2320.         parsevarlist (&f->fields,&f->fieldnames);
  2321.         if (nt != T_CLOSEBRACE)
  2322.             error ("'}' expected");
  2323.         lex ();
  2324.  
  2325.                 /* Index if any */
  2326.  
  2327.         if (iskeyword (K_INDEX))
  2328.         {
  2329.             if (nt != T_UNDEF)
  2330.                 error ("Index field name expected");
  2331.             strcpy (f->index.name,buf);
  2332.             addsym (buf,&f->fieldnames,&f->index);
  2333.             lex ();
  2334.             f->index.type = V_STR;
  2335.             f->index.l = parseconst ();
  2336.         }
  2337.  
  2338.                 /* Is this file linked on other files? */
  2339.  
  2340.         if (iskeyword (K_ON))
  2341.         {
  2342.             if (nt != T_OPENBRACE)
  2343.                 error ("'{' expected");
  2344.             lex ();
  2345.             while (nt != T_CLOSEBRACE)
  2346.             {
  2347.                 fi = alloc (sizeof (fileid));
  2348.                 strcpy (fi->name,buf);
  2349.                 lex ();
  2350.                 addlist (f->on,fi);
  2351.             }
  2352.             lex ();
  2353.         }
  2354.  
  2355.                 /* Is this file a table? */
  2356.  
  2357.         if (iskeyword (K_TABLE))
  2358.             f->table = parseconst ();
  2359.     }
  2360.  
  2361.             /* Fix up all file pointers to point to correct files */
  2362.  
  2363.     for (f=files; f; f=f->next)
  2364.         for (fi=f->on; fi; fi=fi->next)
  2365.         {
  2366.             strcpy (buf,fi->name);
  2367.             fi->p = findsym (filenames);
  2368.             if (fi->p == 0)
  2369.                 error ("'%s' is not the name of a file",buf);
  2370.         }
  2371.  
  2372.             /* Output file definitions */
  2373.  
  2374.     for (f=files; f; f=f->next)
  2375.     {
  2376.                 /* Structure definition */
  2377.  
  2378.         nl ();
  2379.         os ("typedef struct");
  2380.         nl ();
  2381.         os ("{");
  2382.         indent = 1;
  2383.  
  2384.                 /* Links to next and previous records */
  2385.  
  2386.         if (!f->table)
  2387.         {
  2388.             nl ();
  2389.             os ("long next;");
  2390.             nl ();
  2391.             os ("long prev;");
  2392.             nl ();
  2393.         }
  2394.  
  2395.                 /* Index field */
  2396.  
  2397.         if (f->index.l)
  2398.         {
  2399.             nl ();
  2400.             os ("char ");
  2401.             os (f->index.name);
  2402.             os ("[");
  2403.             oi (f->index.l);
  2404.             os ("];");
  2405.             nl ();
  2406.         }
  2407.  
  2408.                 /* Files this one is linked on */
  2409.  
  2410.         for (fi=f->on; fi; fi=fi->next)
  2411.         {
  2412.             nl ();
  2413.             os ("long ");
  2414.             os (fi->p->name);
  2415.             os ("ptr;");
  2416.             nl ();
  2417.             os ("long ");
  2418.             os (fi->p->name);
  2419.             os ("next;");
  2420.             nl ();
  2421.             os ("long ");
  2422.             os (fi->p->name);
  2423.             os ("prev;");
  2424.             nl ();
  2425.         }
  2426.  
  2427.                 /* Files that are linked on this one */
  2428.  
  2429.         for (f2=files; f2; f2=f2->next)
  2430.             for (fi=f2->on; fi; fi=fi->next)
  2431.                 if (fi->p == f)
  2432.                 {
  2433.                     nl ();
  2434.                     os ("long ");
  2435.                     os (f2->name);
  2436.                     os ("first;");
  2437.                     nl ();
  2438.                     os ("long ");
  2439.                     os (f2->name);
  2440.                     os ("last;");
  2441.                     nl ();
  2442.                     break;
  2443.                 }
  2444.  
  2445.                 /* Normal fields */
  2446.  
  2447.         outvarlist (f->fields);
  2448.  
  2449.                 /* End of structure definition */
  2450.  
  2451.         indent = 0;
  2452.         nl ();
  2453.         os ("} ");
  2454.         os (f->name);
  2455.         os (";");
  2456.         nl ();
  2457.  
  2458.                 /* Blank record */
  2459.  
  2460.         nl ();
  2461.         os (f->name);
  2462.         os (" blank");
  2463.         os (f->name);
  2464.         os (" =");
  2465.         nl ();
  2466.         os ("{");
  2467.         indent = 1;
  2468.  
  2469.                 /* Links to next and previous records */
  2470.  
  2471.         if (!f->table)
  2472.         {
  2473.             blankptr ();
  2474.             blankptr ();
  2475.             nl ();
  2476.         }
  2477.  
  2478.                 /* Index field */
  2479.  
  2480.         if (f->index.l)
  2481.         {
  2482.             outblank (&f->index);
  2483.             nl ();
  2484.         }
  2485.  
  2486.                 /* Files this one is linked on */
  2487.  
  2488.         for (fi=f->on; fi; fi=fi->next)
  2489.         {
  2490.             blankptr ();
  2491.             blankptr ();
  2492.             blankptr ();
  2493.             nl ();
  2494.         }
  2495.  
  2496.                 /* Files that are linked on this one */
  2497.  
  2498.         for (f2=files; f2; f2=f2->next)
  2499.             for (fi=f2->on; fi; fi=fi->next)
  2500.                 if (fi->p == f)
  2501.                 {
  2502.                     blankptr ();
  2503.                     blankptr ();
  2504.                     nl ();
  2505.                     break;
  2506.                 }
  2507.  
  2508.                 /* Normal fields */
  2509.  
  2510.         for (v=f->fields; v; v=v->next)
  2511.             outblank (v);
  2512.  
  2513.                 /* End of blank record */
  2514.  
  2515.         indent = 0;
  2516.         nl ();
  2517.         os ("};");
  2518.         nl ();
  2519.  
  2520.                 /* Record variable */
  2521.  
  2522.         nl ();
  2523.         os (f->name);
  2524.         os (" ");
  2525.         os (f->name);
  2526.         os (";");
  2527.  
  2528.         if (!f->table)
  2529.         {
  2530.  
  2531.                     /* File handle */
  2532.  
  2533.             nl ();
  2534.             os ("int ");
  2535.             os (f->name);
  2536.             os ("file;");
  2537.  
  2538.                     /* Record pointer */
  2539.  
  2540.             nl ();
  2541.             os ("long ");
  2542.             os (f->name);
  2543.             os ("ptr;");
  2544.  
  2545.                     /* Index file handle */
  2546.  
  2547.             if (f->index.l)
  2548.             {
  2549.                 nl ();
  2550.                 os ("int ");
  2551.                 os (f->name);
  2552.                 os ("indexfile;");
  2553.             }
  2554.  
  2555.             nl ();
  2556.         }
  2557.  
  2558.                 /* Data in miscfile */
  2559.  
  2560.         nl ();
  2561.         os ("#define\t");
  2562.         os (f->name);
  2563.         os ("miscoff\t");
  2564.         oi (miscoff);
  2565.         nl ();
  2566.  
  2567.         if (f->table)
  2568.             miscoff += recsize (f);
  2569.         else
  2570.         {
  2571.             miscoff += 3*sizeof (long);
  2572.             if (f->index.l)
  2573.                 miscoff += sizeof (long);
  2574.         }
  2575.     }
  2576.  
  2577.             /* Procedures */
  2578.  
  2579.     parsekeyword (K_PROCEDURES);
  2580.  
  2581.     while (nt == T_UNDEF)
  2582.     {
  2583.                 /* Create procedure structure */
  2584.  
  2585.         p = alloc (sizeof (proc));
  2586.         addsym (buf,&procnames,p);
  2587.         addlist (procs,p);
  2588.         strcpy (p->name,buf);
  2589.         lex ();
  2590.  
  2591.                 /* Get menu item name if present */
  2592.  
  2593.         p->menuitem = 0;
  2594.         if (nt == T_STR)
  2595.         {
  2596.             p->menuitem = alloc (strlen (buf) + 1);
  2597.             strcpy (p->menuitem,buf);
  2598.             lex ();
  2599.         }
  2600.  
  2601.                 /* Output procedure heading */
  2602.  
  2603.         nl ();
  2604.         os ("void ");
  2605.         os (p->name);
  2606.         os (" (void)");
  2607.         nl ();
  2608.         os ("{");
  2609.  
  2610.                 /* Indent one tab column within procedure */
  2611.  
  2612.         indent = 1;
  2613.  
  2614.                 /* Local variables */
  2615.  
  2616.         parsevarlist (&locals,&localnames);
  2617.  
  2618.         outvarlist (locals);
  2619.         if (locals)
  2620.             nl ();
  2621.  
  2622.                 /* Procedure code */
  2623.  
  2624.         if (nt != T_OPENBRACE)
  2625.             error ("'{' expected");
  2626.         lex ();
  2627.         while (nt != T_CLOSEBRACE)
  2628.             parsestatement ();
  2629.         lex ();
  2630.  
  2631.                 /* Finish indented part */
  2632.  
  2633.         indent = 0;
  2634.  
  2635.                 /* Close brace after code */
  2636.  
  2637.         nl ();
  2638.         os ("}");
  2639.  
  2640.                 /* Blank line before next procedure */
  2641.  
  2642.         nl ();
  2643.  
  2644.                 /* Free local variable list */
  2645.  
  2646.         v = locals;
  2647.         while (v)
  2648.         {
  2649.             v2 = v->next;
  2650.             free (v);
  2651.             v = v2;
  2652.         }
  2653.         locals = 0;
  2654.  
  2655.                 /* Free local variable symbol table */
  2656.  
  2657.         freesym (localnames);
  2658.         localnames = 0;
  2659.     }
  2660.  
  2661.     if (nt != T_EOF)
  2662.         error ("Procedure definition expected");
  2663.  
  2664.             /* Menu structure */
  2665.  
  2666.     for (p=procs; p; p=p->next)
  2667.         if (p->menuitem)
  2668.             addoption (&mt,p->menuitem,p->name);
  2669.  
  2670.     menuoutput (&mt,"menu");
  2671.  
  2672.             /* Main function */
  2673.  
  2674.     nl ();
  2675.     os ("main (void)");
  2676.     nl ();
  2677.     os ("{");
  2678.     indent = 1;
  2679.     nl ();
  2680.     os ("long r;");
  2681.     nl ();
  2682.  
  2683.             /* Open or create files */
  2684.  
  2685.     for (f=files; f; f=f->next)
  2686.         if (!f->table)
  2687.         {
  2688.             nl ();
  2689.             os (f->name);
  2690.             os ("file = opencreate (\"");
  2691.             os (f->name);
  2692.             os (".dat\");");
  2693.             if (f->index.l)
  2694.             {
  2695.                 nl ();
  2696.                 os (f->name);
  2697.                 os ("indexfile = opencreate (\"");
  2698.                 os (f->name);
  2699.                 os (".idx\");");
  2700.             }
  2701.         }
  2702.     nl ();
  2703.  
  2704.             /* Initialize misc file */
  2705.  
  2706.     nl ();
  2707.     os ("miscfile = open (\"misc.dat\",O_RDWR);");
  2708.     nl ();
  2709.     os ("if (miscfile < 0)");
  2710.     nl ();
  2711.     os ("{");
  2712.     indent++;
  2713.     nl ();
  2714.     os ("miscfile = open (\"misc.dat\",O_CREAT | O_TRUNC | O_RDWR,0777);");
  2715.     nl ();
  2716.     os ("if (miscfile < 0)");
  2717.     nl ();
  2718.     os ("{");
  2719.     indent++;
  2720.     nl ();
  2721.     os ("printf (\"Can't create file misc.dat\\n\");");
  2722.     nl ();
  2723.     os ("return 1;");
  2724.     indent--;
  2725.     nl ();
  2726.     os ("}");
  2727.     for (f=files; f; f=f->next)
  2728.     {
  2729.         nl ();
  2730.         if (f->table)
  2731.         {
  2732.             os ("for (r=0; r!=");
  2733.             oi (f->table);
  2734.             os ("; r++)");
  2735.             indent++;
  2736.             nl ();
  2737.             os ("mwrite (&");
  2738.             os (f->name);
  2739.             os (",sizeof ");
  2740.             os (f->name);
  2741.             os (");");
  2742.             indent--;
  2743.         }
  2744.         else
  2745.             if (f->index.l)
  2746.                 os ("mblank4 ();");
  2747.             else
  2748.                 os ("mblank3 ();");
  2749.     }
  2750.     indent--;
  2751.     nl ();
  2752.     os ("}");
  2753.     nl ();
  2754.  
  2755.     nl ();
  2756.     os ("initvideo ();");
  2757.     nl ();
  2758.     os ("execmenu (menu,-1,-1,0,0);");
  2759.     nl ();
  2760.     os ("return 0;");
  2761.     indent = 0;
  2762.     nl ();
  2763.     os ("}");
  2764.  
  2765.     return 0;
  2766. }
  2767.