home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
World of Shareware - Software Farm 2
/
wosw_2.zip
/
wosw_2
/
DATABASE
/
DPG.ZIP
/
DPG.C
next >
Wrap
C/C++ Source or Header
|
1992-05-04
|
47KB
|
2,767 lines
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>
#include "video.h"
#include "files.h"
#define MAXNAME 32 /* Maximum length of symbols */
#define MAXMENU 20 /* Maximum depth of submenus */
#define myisalpha(c) (isalpha (c) || (c) == '_')
#define myisalnum(c) (isalpha (c) || (c) == '_' || isdigit (c))
#define addlist(b,p) (p)->next = (b); (b) = (p)
#define align(n) n = (n+1) & ~1
/* Types of variables */
enum
{
V_INT,
V_FLOAT,
V_DATE,
V_STR,
V_PTR,
};
/* Types of lexical tokens */
enum
{
T_AND,
T_ASSIGN,
T_CLOSEBRACE,
T_CLOSEBRACKET,
T_COLON,
T_DOT,
T_EOF,
T_EQ,
T_FIELD,
T_FILE,
T_FLOAT,
T_GE,
T_GT,
T_INT,
T_KEYWORD,
T_LE,
T_LT,
T_MINUS,
T_NE,
T_NOT,
T_OPENBRACE,
T_OPENBRACKET,
T_OR,
T_PERCENT,
T_PLUS,
T_PROC,
T_SLASH,
T_STAR,
T_STR,
T_UNDEF,
T_VAR,
};
/* List of keywords */
enum
{
K_ATODATE,
K_ATOF,
K_ATOI,
K_BREAK,
K_CONTINUE,
K_CREATE,
K_CURSOR,
K_DATE,
K_DATEDAY,
K_DATEMONTH,
K_DATEYEAR,
K_DEL,
K_DELETE,
K_DO,
K_DOWN,
K_EDIT,
K_ELSE,
K_END,
K_ESC,
K_FILES,
K_FIND,
K_FLOAT,
K_GETKEY,
K_GOTO,
K_HOME,
K_IF,
K_INDEX,
K_INS,
K_INT,
K_LEFT,
K_LINK,
K_MAKEDATE,
K_ON,
K_PAUSE,
K_PGDN,
K_PGUP,
K_PRINTDATE,
K_PRINTFLOAT,
K_PRINTINT,
K_PRINTSTR,
K_PROCEDURES,
K_PTR,
K_READ,
K_RETURN,
K_RIGHT,
K_SCROLL,
K_SELECT,
K_SPRINTDATE,
K_SPRINTFLOAT,
K_SPRINTINT,
K_STR,
K_STRCMP,
K_STRCPY,
K_SWITCH,
K_TABLE,
K_UNLINK,
K_UP,
K_VAR,
K_WHILE,
K_WRITE,
};
typedef char str[MAXNAME];
/* Binary tree structure for symbol tables */
typedef struct symstruct
{
struct symstruct *left,*right;
str name;
void *p; /* Pointer to actual object denoted by symbol */
} sym;
struct filestruct;
typedef struct filestruct file;
/* Structure for file identifier ("name" field is required because
pointer may not be available initially */
typedef struct fileidstruct
{
struct fileidstruct *next;
str name;
file *p;
} fileid;
/* Structure for variable declarations */
typedef struct varstruct
{
struct varstruct *next;
str name;
char type;
char l; /* Length in characters or digits before decimal point */
char dec; /* Digits after decimal point (V_FLOAT only) */
} var;
/* Structure for data file */
struct filestruct
{
file *next;
str name;
var *fields;
sym *fieldnames;
var index; /* Index field if any */
fileid *on; /* Which files is this one linked on */
long table; /* If nonzero, this file is a table and the value is the
number of entries */
};
/* Structure for procedure declaration */
typedef struct procstruct
{
struct procstruct *next;
str name;
char *menuitem; /* Which menu item (if any) is used for access */
} proc;
/* Structures used in constructing menu tree */
struct menutreestruct;
typedef struct menutreestruct menutree;
typedef struct submenustruct
{
struct submenustruct *next;
menutree *mt;
} submenu;
struct menutreestruct
{
char *text;
char *func;
submenu *sm;
};
char *keywords[] =
{
"atodate",
"atof",
"atoi",
"break",
"continue",
"create",
"cursor",
"date",
"dateday",
"datemonth",
"dateyear",
"del",
"delete",
"do",
"down",
"edit",
"else",
"end",
"esc",
"files",
"find",
"float",
"getkey",
"goto",
"home",
"if",
"index",
"ins",
"int",
"left",
"link",
"makedate",
"on",
"pause",
"pgdn",
"pgup",
"printdate",
"printfloat",
"printint",
"printstr",
"procedures",
"ptr",
"read",
"return",
"right",
"scroll",
"select",
"sprintdate",
"sprintfloat",
"sprintint",
"str",
"strcmp",
"strcpy",
"switch",
"table",
"unlink",
"up",
"var",
"while",
"write",
};
/* Names of cursor directions used to move between fields
(duplicated in keywords above) */
char *dirname[] =
{
"RETURN",
"ESC",
"UP",
"DOWN",
"LEFT",
"RIGHT",
"PGUP",
"PGDN",
"HOME",
"END",
"INS",
"DEL",
};
FILE *infile; /* Source file */
FILE *outfile; /* Output file */
char outfilename[256]; /* Name of output file */
long line = 1; /* Current line number */
char buf[256]; /* Character buffer for lexical analyzer */
int nc; /* Next character (used by lexical analyzer) */
int nt; /* Next token type */
long ni; /* Next integer value if integer token */
double nf; /* Next floating point value if floating point token */
int nkeyword; /* Next keyword if keyword token */
var *nvar; /* Pointer to variable if variable name token */
file *nfile; /* Pointer to file if file name token */
proc *nproc; /* Pointer to procedure if procedure name token */
/* Labels for output switch statement depending on
cursor movement direction */
char dirlabel[MAXDIR][MAXNAME];
int indent; /* Current output indentation level */
int lastlen,lastdec; /* Number of characters/digits of last token */
var *globals; /* Global variables */
proc *procs; /* Procedures */
file *files; /* Files */
var *locals; /* Local variables for procedure currently being parsed */
sym *globalnames;
sym *procnames;
sym *filenames;
sym *localnames;
long miscoff; /* Offset for data in miscfile */
/* Text of menu items */
char *menutext[MAXMENU];
void parseexp (void);
void parsestatement (void);
/* Output error message and terminate */
void error (char *format,...)
{
va_list argptr;
va_start (argptr,format);
printf ("Error %ld: ",line);
vprintf (format,argptr);
va_end (argptr);
putchar ('\n');
fclose (outfile);
unlink (outfilename);
exit (1);
}
/* Output error message but keep compiling */
void warning (char *format,...)
{
va_list argptr;
va_start (argptr,format);
printf ("Warning %ld: ",line);
vprintf (format,argptr);
va_end (argptr);
putchar ('\n');
}
/* Allocate memory with error checking */
void *alloc (int n)
{
void *p;
p = malloc (n);
if (p == 0)
{
error ("Out of memory");
exit (1);
}
return p;
}
/* Add a symbol to a symbol table */
void addsym (char *name,sym **base,void *p)
{
sym *s;
sym *q;
int c;
s = alloc (sizeof (sym));
s->left = s->right = 0;
strcpy (s->name,name);
s->p = p;
if (*base == 0)
{
*base = s;
return;
}
q = *base;
for (;;)
{
c = strcmp (q->name,name);
if (c == 0)
{
warning ("Symbol '%s' redefined",name);
return;
}
if (c < 0)
{
if (q->right == 0)
{
q->right = s;
return;
}
q = q->right;
}
else
{
if (q->left == 0)
{
q->left = s;
return;
}
q = q->left;
}
}
}
/* Free a symbol table */
void freesym (sym *s)
{
if (s)
{
freesym (s->right);
freesym (s->left);
free (s);
}
}
/* Compare pointers to pointers to strings (used in calling bsearch ()) */
strpcmp (char **s1,char **s2)
{
return strcmp (*s1,*s2);
}
/* Locate the string in buf in a symbol table, if present */
void *findsym (sym *s)
{
int i;
if (s == 0)
return 0;
i = strcmp (buf,s->name);
if (i == 0)
return s->p;
if (i < 0)
return findsym (s->left);
else
return findsym (s->right);
}
/* Read next character into nc from input file */
void readc (void)
{
nc = fgetc (infile);
if (nc == '\n')
line++;
}
/* Read next lexical token */
void lex (void)
{
int i;
void *p;
LOOP:
/* Ignore leading white space */
while (isspace (nc))
readc ();
/* Next token is a symbol of some sort */
if (myisalpha (nc))
{
/* Read symbol into buf */
i = 0;
do
{
if (i != MAXNAME)
buf[i++] = tolower (nc);
readc ();
}
while (myisalnum (nc));
buf[i] = 0;
/* Is it a keyword? */
p = buf;
p = bsearch (&p,keywords,sizeof keywords / sizeof (char *),
sizeof (char *),strpcmp);
if (p)
{
nt = T_KEYWORD;
nkeyword = (char **)p - keywords;
return;
}
/* Is it the name of a local variable? */
p = findsym (localnames);
if (p)
{
nt = T_VAR;
nvar = p;
lastlen = nvar->l;
lastdec = nvar->dec;
return;
}
/* Is it the name of a global variable? */
p = findsym (globalnames);
if (p)
{
nt = T_VAR;
nvar = p;
lastlen = nvar->l;
lastdec = nvar->dec;
return;
}
/* Is it the name of a file? */
p = findsym (filenames);
if (p)
{
nt = T_FILE;
nfile = p;
return;
}
/* Is it the name of a procedure? */
p = findsym (procnames);
if (p)
{
nt = T_PROC;
nproc = p;
return;
}
/* Failing all this, if the last two tokens were the name of a file
followed by a dot, this must be the name of a field */
if (nt == T_DOT && nfile)
{
/* Is it a regular field? */
nt = T_FIELD;
p = findsym (nfile->fieldnames);
if (p)
{
nvar = p;
lastlen = nvar->l;
lastdec = nvar->dec;
}
else /* Is it the index variable? */
if (!strcmp (buf,nfile->index.name))
{
nvar = &nfile->index;
lastlen = nvar->l;
}
return;
}
/* Not identified, so return next token as unidentified symbol */
nt = T_UNDEF;
return;
}
/* Next token is a number */
if (isdigit (nc))
{
/* Read number into buf */
i = 0;
do
{
buf[i] = nc;
i++;
if (i == sizeof buf)
error ("Number too long");
readc ();
}
while (isdigit (nc));
lastlen = i;
/* Floating point number */
if (nc == '.')
{
buf[i] = '.';
i++;
if (i == sizeof buf)
error ("Number too long");
readc ();
while (isdigit (nc))
{
buf[i] = nc;
i++;
if (i == sizeof buf)
error ("Number too long");
readc ();
}
buf[i] = 0;
nt = T_FLOAT;
nf = atof (buf);
lastdec = i - lastlen - 1;
}
else /* Integer */
{
buf[i] = 0;
nt = T_INT;
ni = atol (buf);
}
return;
}
switch (nc)
{
case '.': /* Either a floating-point number or the dot operator */
readc ();
if (isdigit (nc))
{
buf[0] = '.';
i = 1;
do
{
buf[i] = nc;
i++;
if (i == sizeof buf)
error ("Number too long");
}
while (isdigit (nc));
buf[i] = 0;
nt = T_FLOAT;
nf = atof (buf);
lastlen = 0;
lastdec = i - 1;
}
else
nt = T_DOT;
break;
case '"': /* A string */
i = 0;
readc ();
while (nc != '"')
{
if (nc == EOF)
error ("Unterminated string");
buf[i] = nc;
i++;
if (i == sizeof buf)
error ("String too long");
readc ();
}
buf[i] = 0;
lastlen = i;
readc ();
nt = T_STR;
break;
case '&':
readc ();
if (nc != '&')
error ("'&' is not a valid token");
readc ();
nt = T_AND;
break;
case '|':
readc ();
if (nc != '|')
error ("'|' is not a valid token");
readc ();
nt = T_OR;
break;
case '=':
readc ();
nt = T_ASSIGN;
if (nc == '=')
{
readc ();
nt = T_EQ;
}
break;
case '>':
readc ();
nt = T_GT;
if (nc == '=')
{
readc ();
nt = T_GE;
}
break;
case '<':
readc ();
nt = T_LT;
if (nc == '=')
{
readc ();
nt = T_LE;
}
break;
case '!':
readc ();
nt = T_NOT;
if (nc == '=')
{
readc ();
nt = T_NE;
}
break;
case '{':
readc ();
nt = T_OPENBRACE;
break;
case '}':
readc ();
nt = T_CLOSEBRACE;
break;
case '(':
readc ();
nt = T_OPENBRACKET;
break;
case ')':
readc ();
nt = T_CLOSEBRACKET;
break;
case ':':
readc ();
nt = T_COLON;
break;
case '-':
readc ();
nt = T_MINUS;
break;
case '%':
readc ();
nt = T_PERCENT;
break;
case '+':
readc ();
nt = T_PLUS;
break;
case '/': /* Either a slash or a comment */
readc ();
if (nc == '*')
{
do
{
do
readc ();
while (nc != '*' && nc != EOF);
if (nc == EOF)
{
nt = T_EOF;
return;
}
readc ();
}
while (nc != '/');
readc ();
goto LOOP; /* Comment, so ignore it and get new token */
}
nt = T_SLASH;
break;
case '*':
readc ();
nt = T_STAR;
break;
case EOF:
nt = T_EOF;
break;
default:
error ("Unrecognized character %c",nc);
}
}
/* Check whether the next token is a given keyword, if so get new token */
iskeyword (int k)
{
if (nt == T_KEYWORD && nkeyword == k)
{
lex ();
return 1;
}
return 0;
}
/* Output a string */
void os (char *s)
{
fprintf (outfile,"%s",s);
}
/* Output an integer */
void oi (long n)
{
fprintf (outfile,"%ld",n);
}
/* Output a floating point number */
void of (double n)
{
fprintf (outfile,"%lf",n);
}
/* Go on to new line, and indent as necessary */
void nl (void)
{
int i;
fputc ('\n',outfile);
for (i=indent; i--;)
fputc ('\t',outfile);
}
/* Check that the next token is a label reference (labels are not
currently validated, so pass any sort of symbol */
void cklabel (void)
{
if ( nt != T_UNDEF &&
nt != T_KEYWORD &&
nt != T_VAR &&
nt != T_FILE &&
nt != T_PROC &&
nt != T_FIELD)
error ("Label expected");
}
/* Check that the next token is a file name */
void ckfile (void)
{
if (nt != T_FILE)
error ("File name expected");
}
/* Check that the next token is the appropriate keyword, and if so, get
new token */
void parsekeyword (int k)
{
if (!iskeyword (k))
{
strcpy (buf,keywords[k]);
strupr (buf);
error ("%s expected",buf);
}
}
/* Check that the next token is an integer constant, and if so, return
its value and get new token */
long parseconst (void)
{
long n;
if (nt != T_INT)
error ("Integer expected");
n = ni;
lex ();
return n;
}
/* Parse a list of variable declarations */
void parsevarlist (var **vl,sym **s)
{
var *v;
while (nt == T_KEYWORD &&
( nkeyword == K_INT ||
nkeyword == K_FLOAT ||
nkeyword == K_DATE ||
nkeyword == K_STR ||
nkeyword == K_PTR))
{
v = alloc (sizeof (var));
switch (nkeyword)
{
case K_INT:
lex ();
v->type = V_INT;
v->l = parseconst ();
break;
case K_FLOAT:
lex ();
v->type = V_FLOAT;
v->l = parseconst ();
v->dec = parseconst ();
break;
case K_DATE:
lex ();
v->type = V_DATE;
break;
case K_STR:
lex ();
v->type = V_STR;
v->l = parseconst ();
break;
case K_PTR:
lex ();
v->type = V_PTR;
break;
}
strcpy (v->name,buf);
lex ();
addsym (v->name,s,v);
addlist (*vl,v);
}
}
/* Routines for top-down expression parse */
void parsefactor (void)
{
switch (nt)
{
case T_MINUS:
os ("-");
lex ();
parsefactor ();
break;
case T_NOT:
os ("!");
lex ();
parsefactor ();
break;
case T_INT:
oi (ni);
lex ();
break;
case T_FLOAT:
of (nf);
lex ();
break;
case T_STR:
os ("\"");
os (buf);
os ("\"");
lex ();
break;
case T_OPENBRACKET:
os ("(");
lex ();
parseexp ();
if (nt != T_CLOSEBRACKET)
error ("')' expected");
lex ();
os (")");
break;
case T_VAR:
os (buf);
lex ();
break;
case T_FILE:
os (buf);
lex ();
if (nt != T_DOT)
error ("'.' expected");
lex ();
os (".");
if (nt != T_FIELD)
error ("Field name expected");
os (buf);
lex ();
break;
case T_KEYWORD:
switch (nkeyword)
{
case K_ATODATE:
case K_ATOF:
case K_ATOI:
case K_DATEDAY:
case K_DATEMONTH:
case K_DATEYEAR:
os (buf);
os (" (");
lex ();
parseexp ();
os (")");
break;
case K_MAKEDATE:
lex ();
os ("makedate (");
parseexp ();
os (",");
parseexp ();
os (",");
parseexp ();
os (")");
break;
case K_STRCMP:
lex ();
os ("memicmp (");
parseexp ();
os (",");
parseexp ();
os (",");
if (nt == T_INT)
parseexpr ();
else
oi (lastlen);
os (")");
break;
default:
error ("Expression expected");
}
break;
default:
error ("Expression expected");
}
}
void parseterm (void)
{
parsefactor ();
while (nt == T_STAR || nt == T_SLASH || nt == T_PERCENT)
{
switch (nt)
{
case T_STAR:
os ("*");
break;
case T_SLASH:
os ("/");
break;
case T_PERCENT:
os ("%");
break;
}
lex ();
parsefactor ();
}
}
void parsemathexp (void)
{
parseterm ();
while (nt == T_PLUS || nt == T_MINUS)
{
if (nt == T_PLUS)
os (" + ");
else
os (" - ");
lex ();
parseterm ();
}
}
void parserelexp (void)
{
parsemathexp ();
while (nt == T_GT || nt == T_LT || nt == T_GE || nt == T_LE)
{
switch (nt)
{
case T_GT:
os (" > ");
break;
case T_LT:
os (" < ");
break;
case T_GE:
os (" >= ");
break;
case T_LE:
os (" <= ");
break;
}
lex ();
parsemathexp ();
}
}
void parseeqexp (void)
{
parserelexp ();
while (nt == T_EQ || nt == T_NE)
{
if (nt == T_EQ)
os (" == ");
else
os (" != ");
lex ();
parserelexp ();
}
}
void parseandexp (void)
{
parseeqexp ();
while (nt == T_AND)
{
os (" && ");
lex ();
parseeqexp ();
}
}
void parseexp (void)
{
parseandexp ();
while (nt == T_OR)
{
os (" || ");
lex ();
parseandexp ();
}
}
/* Parse a statement, or zero or more statements surrounded by braces,
with appropriate output indentation */
void parseindentstatement (void)
{
if (nt == T_OPENBRACE)
parsestatement ();
else
{
indent++;
parsestatement ();
indent--;
}
}
/* Parse the section of a PRINT statement common to all data types */
void parseprint (void)
{
lex ();
parseexp (); /* X */
os (",");
parseexp (); /* Y */
os (",");
parseexp (); /* Expression to be displayed */
}
/* Parse the section of an SPRINT statement common to all data types */
void parsesprint (void)
{
lex ();
parseexp (); /* String variable */
os (",");
parseexp (); /* Expression to be printed */
}
/* Parse a direction keyword for an EDIT statement, optionally followed
by a label reference */
void parsedirection (void)
{
int i;
if (nt != T_KEYWORD)
error ("Direction expected");
for (i=0; i!=MAXDIR; i++)
if (!strcmpl (dirname[i],buf))
{
lex ();
dirlabel[i][0] = '*';
if (nt == T_ASSIGN) /* If label reference present, record it */
{
lex ();
cklabel ();
strupr (buf);
strcpy (dirlabel[i],buf);
lex ();
}
return;
}
error ("Direction expected");
}
/* Parse a direction for an EDIT statement, or zero or more directions
surrounded by braces */
void parsedirections (void)
{
int i;
int ndir;
os (",");
/* Read direction data */
memset (dirlabel,0,sizeof dirlabel);
if (nt == T_OPENBRACE)
{
lex ();
while (nt != T_CLOSEBRACE)
parsedirection ();
lex ();
}
else
parsedirection ();
/* Output flags indicating allowed directions */
ndir = 0;
for (i=0; i!=MAXDIR; i++)
if (dirlabel[i][0])
ndir++;
for (i=0; i!=MAXDIR; i++)
if (dirlabel[i][0])
{
os ("DF_");
os (dirname[i]);
ndir--;
if (ndir)
os (" | ");
}
os (");");
/* Output switch statement on direction */
nl ();
os ("switch (dir)");
nl ();
os ("{");
indent++;
for (i=0; i!=MAXDIR; i++)
if (dirlabel[i][0] != 0 && dirlabel[i][0] != '*')
{
nl ();
os ("case DIR_");
os (dirname[i]);
os (":");
indent++;
nl ();
os ("goto ");
os (dirlabel[i]);
os (";");
indent--;
}
indent--;
nl ();
os ("}");
}
/* Parse an EDIT statement */
void parseedit (void)
{
switch (nvar->type)
{
case V_INT:
switch (nvar->l)
{
case 1:
case 2:
os ("editbyte (&");
break;
case 3:
case 4:
os ("editshort (&");
break;
default:
os ("editlong (&");
}
break;
case V_FLOAT:
os ("editfloat (&");
break;
case V_DATE:
os ("editdate (&");
break;
case V_STR:
os ("editstr (");
break;
case V_PTR:
warning ("Can't edit a pointer variable");
break;
}
if (nt == T_FIELD)
{
if (nvar == &nfile->index)
warning ("Can't edit index field");
os (nfile->name);
os (".");
}
os (buf);
if (nvar->type != V_DATE)
{
os (",");
oi (nvar->l);
if (nvar->type == V_FLOAT)
{
os (",");
oi (nvar->dec);
}
}
lex ();
os (",");
parseexp ();
os (",");
parseexp ();
parsedirections ();
}
/* Parse a statement */
void parsestatement (void)
{
file *f,*f2;
int x,y,i;
str vname;
switch (nt)
{
case T_OPENBRACE: /* Zero or more statements surrounded by braces */
nl ();
os ("{");
lex ();
indent++;
while (nt != T_CLOSEBRACE)
parsestatement ();
indent--;
nl ();
os ("}");
lex ();
break;
case T_COLON: /* A label */
lex ();
cklabel ();
strupr (buf);
fprintf (outfile,"\n\n%s:",buf);
lex ();
if (nt == T_CLOSEBRACE)
os (";");
break;
case T_VAR: /* Assignment to a variable */
nl ();
os (buf);
lex ();
if (nt != T_ASSIGN)
error ("'=' expected");
lex ();
os (" = ");
parseexp ();
os (";");
break;
case T_FILE: /* Assignment to a field */
nl ();
os (buf);
lex ();
if (nt != T_DOT)
error ("'.' expected");
lex ();
os (".");
if (nt != T_FIELD)
error ("Field name expected");
os (buf);
if (nt != T_ASSIGN)
error ("'=' expected");
lex ();
os (" = ");
parseexp ();
os (";");
break;
case T_PROC: /* A procedure call */
nl ();
os (buf);
os (" ();");
lex ();
break;
case T_KEYWORD:
switch (nkeyword)
{
case K_EDIT: /* Edit a variable or field */
lex ();
nl ();
switch (nt)
{
case T_VAR:
parseedit ();
break;
case T_FILE:
lex ();
if (nt != T_DOT)
error ("'.' expected");
lex ();
if (nt != T_FIELD)
error ("Field name expected");
parseedit ();
break;
default:
error ("Variable name expected");
}
break;
case K_SELECT: /* Allow user to select a data record */
lex ();
ckfile ();
nl ();
os ("select (");
os (buf);
os ("file,");
os (buf);
os ("indexfile,&");
os (buf);
os ("ptr,&");
os (buf);
os (",sizeof ");
os (buf);
os (",");
os (buf);
os (".");
os (nfile->index.name);
os (",");
oi (nfile->index.l);
os (",");
lex ();
parseexp ();
os (",");
parseexp ();
parsedirections ();
break;
case K_FIND: /* Find a data record given the index value */
lex ();
ckfile ();
nl ();
os ("find (");
os (buf);
os ("file,");
os (buf);
os ("indexfile,&");
os (buf);
os (",sizeof ");
os (buf);
os (",");
oi (nfile->index.l);
os (",");
lex ();
parseexp ();
os (");");
break;
case K_READ: /* Read a data record */
lex ();
ckfile ();
nl ();
os ("Read (");
f = nfile;
if (f->table)
{
os ("miscfile,");
os (buf);
os ("miscoff + (");
lex ();
parseexp ();
os (")*sizeof ");
os (f->name);
os (",&");
os (f->name);
os (",sizeof ");
os (f->name);
os (");");
}
else
{
os (buf);
os ("file,");
if (nt == T_VAR)
{
if (nvar->type != V_PTR)
warning ("Variable '%s' is not of type PTR",buf);
strcpy (vname,buf);
lex ();
os (vname);
os (",&");
os (f->name);
os (",sizeof ");
os (f->name);
os (");");
nl ();
os (f->name);
os ("ptr = ");
}
else
{
if (nt != T_FILE)
error ("File read location must be a variable of type PTR");
f2 = nfile;
lex ();
if (nt != T_DOT)
error ("'.' expected");
lex ();
if (nt != T_FIELD)
error ("Field name expected");
strcpy (vname,buf);
lex ();
os (f2->name);
os (".");
os (vname);
os (",&");
os (f->name);
os (",sizeof ");
os (f->name);
os (");");
nl ();
os (f->name);
os ("ptr = ");
os (f2->name);
os (".");
}
os (vname);
os (";");
}
break;
case K_WRITE: /* Write back currently selected record to file */
lex ();
ckfile ();
nl ();
os ("Write (");
f = nfile;
if (f->table)
{
os ("miscfile,");
os (buf);
os ("miscoff + (");
lex ();
parseexp ();
os (")*sizeof ");
os (f->name);
os (",&");
os (f->name);
os (",sizeof ");
os (f->name);
os (");");
}
else
{
os (buf);
os ("file,");
os (buf);
os ("ptr,&");
os (buf);
os (",sizeof ");
os (buf);
os (");");
lex ();
}
break;
case K_CREATE: /* Create a new record */
lex ();
x = -1;
if (nt == T_INT)
{
x = parseconst ();
y = parseconst ();
}
ckfile ();
if (nfile->table)
warning ("Can't create record on table");
if (x >= 0 && !nfile->index.l)
warning ("X, Y parameters should only be provided for creation on indexed files");
if (x < 0 && nfile->index.l)
warning ("X, Y parameters should be provided for creation on indexed files");
nl ();
os (buf);
os (" = blank");
os (buf);
os (";");
nl ();
os ("create");
if (x >= 0)
os ("index");
os (" (");
os (buf);
os ("file,&");
os (buf);
os ("ptr,&");
os (buf);
os (",sizeof ");
os (buf);
os (",");
os (buf);
os ("miscoff");
if (x >= 0) /* File is indexed, so index value must be input */
{
os (",");
os (buf);
os (".");
os (nfile->index.name);
os (",");
oi (nfile->index.l);
os (",");
os (buf);
os ("indexfile,");
oi (x);
os (",");
oi (y);
lex ();
parsedirections ();
}
else
{
os (");");
lex ();
}
break;
case K_DELETE: /* Delete currently selected record */
lex ();
ckfile ();
if (nfile->table)
warning ("Can't delete record from table");
nl ();
if (nfile->index.l)
os ("deleteindex (");
else
os ("delete (");
os (buf);
os ("file,");
os (buf);
os ("ptr,&");
os (buf);
os (",");
os (buf);
os ("miscoff");
if (nfile->index.l)
{
os (",");
os (buf);
os (".");
os (nfile->index.name);
os (",");
oi (nfile->index.l);
os (",");
os (buf);
os ("indexfile");
}
os (");");
lex ();
break;
case K_LINK:
case K_UNLINK:
nl ();
os ("rec");
os (buf);
os (" (");
lex ();
ckfile ();
os (buf);
os ("file,");
os (buf);
os ("ptr,&");
os (buf);
os (".");
f = nfile;
lex ();
ckfile ();
os (buf);
os ("ptr,foffset (");
os (f->name);
os (",");
os (buf);
os ("ptr),");
os (buf);
os ("file,");
os (buf);
os ("ptr,&");
os (buf);
os (".");
os (f->name);
os ("first,foffset (");
os (buf);
os (",");
os (f->name);
os ("first));");
lex ();
break;
case K_SCROLL: /* Scrolling edit */
lex ();
nl ();
os ("scrolledit (");
ckfile ();
os (buf);
os ("file,&");
os (buf);
os ("ptr,&");
os (buf);
os (",foffset (");
os (buf);
os (",");
f = nfile;
lex ();
ckfile ();
os (buf);
os ("ptr),sizeof ");
os (f->name);
os (",");
os (buf);
os ("file,");
os (buf);
os ("ptr,&");
os (buf);
os (",foffset (");
os (buf);
os (",");
os (f->name);
os ("first),sizeof ");
os (buf);
os (",&blank");
os (f->name);
os (",");
os (f->name);
os ("miscoff,");
lex ();
parseexp ();
os (",");
if (nt != T_PROC)
error ("Procedure name expected");
os (buf);
os (",");
lex ();
switch (nt)
{
case T_PROC:
os (buf);
lex ();
break;
case T_INT:
if (parseconst () == 0)
{
os ("0");
break;
}
default:
error ("Procedure name or zero expected");
}
os (",");
parseexp ();
os (",");
parseexp ();
os (",");
parseexp ();
os (",");
parseexp ();
os (");");
break;
case K_GOTO: /* Jump to a label */
lex ();
cklabel ();
nl ();
os ("goto ");
strupr (buf);
os (buf);
os (";");
break;
case K_BREAK:
case K_CONTINUE:
case K_RETURN:
nl ();
os (buf);
os (";");
lex ();
break;
case K_IF: /* C-style IF */
nl ();
os ("if (");
lex ();
parseexp ();
os (")");
parseindentstatement ();
if (iskeyword (K_ELSE))
{
nl ();
os ("else");
parseindentstatement ();
}
break;
case K_WHILE: /* C-style WHILE */
nl ();
os ("while (");
lex ();
parseexp ();
os (")");
parseindentstatement ();
break;
case K_DO: /* C-style DO...WHILE */
nl ();
os ("do");
lex ();
parseindentstatement ();
parsekeyword (K_WHILE);
nl ();
os ("while (");
parseexp ();
os (");");
break;
case K_SWITCH: /* Limited CASE statement - list of labels to
jump to on values of an integer */
nl ();
os ("switch (");
lex ();
parseexp ();
os (")");
nl ();
os ("{");
indent++;
if (nt != T_OPENBRACE)
error ("'{' expected");
lex ();
i = 0;
while (nt != T_CLOSEBRACE)
{
cklabel ();
nl ();
os ("case ");
oi (i);
i++;
os (":");
indent++;
nl ();
os ("goto ");
strupr (buf);
os (buf);
os (";");
lex ();
indent--;
}
lex ();
indent--;
nl ();
os ("}");
break;
case K_PRINTINT: /* Display an integer expression */
nl ();
os ("printint (");
parseprint ();
os (",");
if (nt == T_INT)
parseexp ();
else
oi (lastlen);
os (");");
break;
/* Display a floating-point expression */
case K_PRINTFLOAT:
nl ();
os ("printfloat (");
parseprint ();
os (",");
if (nt == T_INT)
{
parseexp ();
os (",");
parseexp ();
}
else
{
oi (lastlen);
os (",");
oi (lastdec);
}
os (");");
break;
case K_PRINTDATE: /* Display a date expression */
nl ();
os ("printdate (");
parseprint ();
os (");");
break;
case K_PRINTSTR: /* Display a string expression */
nl ();
os ("printstr (");
parseprint ();
os (",");
if (nt == T_INT)
parseexp ();
else
oi (lastlen);
os (");");
break;
case K_SPRINTINT: /* Convert an integer expression to ASCII */
nl ();
os ("sprintint (");
parsesprint ();
os (",");
if (nt == T_INT)
parseexp ();
else
oi (lastlen);
os (");");
break;
/* Convert a floating point expression to ASCII */
case K_SPRINTFLOAT:
nl ();
os ("sprintfloat (");
parsesprint ();
os (",");
if (nt == T_INT)
{
parseexp ();
os (",");
parseexp ();
}
else
{
oi (lastlen);
os (",");
oi (lastdec);
}
os (");");
break;
/* Convert a date expression to ASCII */
case K_SPRINTDATE:
nl ();
os ("sprintdate (");
parsesprint ();
os (");");
break;
case K_CURSOR: /* Move the hardware cursor to a point on screen */
lex ();
nl ();
os ("cursor (");
parseexp ();
os (",");
parseexp ();
os (");");
break;
case K_PAUSE: /* Wait for a keypress */
lex ();
nl ();
os ("getkey ();");
break;
case K_GETKEY: /* Wait for a keypress, and put it into a string */
lex ();
nl ();
parseexpr ();
os ("[0] = getkey ();");
break;
case K_STRCPY: /* Copy one string to another */
lex ();
nl ();
os ("memcpy (");
parseexp ();
os (",");
parseexp ();
os (",");
if (nt == T_INT)
parseexpr ();
else
oi (lastlen);
os (");");
break;
default:
error ("Statement expected");
}
break;
default:
error ("Statement expected");
}
}
/* Output C code variable declarations */
void outvarlist (var *v)
{
while (v)
{
nl ();
switch (v->type)
{
case V_INT:
switch (v->l)
{
case 1:
case 2:
os ("signed char ");
break;
case 3:
case 4:
os ("short ");
break;
default:
os ("long ");
}
os (v->name);
os (";");
break;
case V_FLOAT:
os ("double ");
os (v->name);
os (";");
break;
case V_DATE:
os ("unsigned short ");
os (v->name);
os (";");
break;
case V_STR:
os ("char ");
os (v->name);
os ("[");
oi (v->l);
os ("];");
break;
case V_PTR:
os ("long ");
os (v->name);
os (";");
break;
}
v = v->next;
}
}
/* Output null pointer value */
void blankptr (void)
{
nl ();
os ("-1,");
}
/* Output null value for a variable */
void outblank (var *v)
{
int i;
nl ();
switch (v->type)
{
case V_DATE:
os ("BLANKDATE,");
break;
case V_STR:
for (i=v->l; i--;)
os ("' ',");
break;
default:
os ("0,");
}
}
/* Determine physical size of a data record */
recsize (file *f)
{
int n;
file *f2;
var *v;
fileid *fi;
/* Index field */
n = f->index.l;
/* Normal fields */
for (v=f->fields; v; v=v->next)
switch (v->type)
{
case V_INT:
switch (v->l)
{
case 1:
case 2:
n++;
break;
case 3:
case 4:
align (n);
n += sizeof (short);
break;
default:
align (n);
n += sizeof (long);
}
break;
case V_FLOAT:
align (n);
n += sizeof (double);
break;
case V_DATE:
align (n);
n += sizeof (short);
break;
case V_STR:
n += v->l;
break;
}
align (n);
/* Files this one is linked on */
for (fi=f->on; fi; fi=fi->next)
n += 3*sizeof (long);
/* Files that are linked on this one */
for (f2=files; f2; f2=f2->next)
for (fi=f2->on; fi; fi=fi->next)
if (fi->p == f)
{
n += 2*sizeof (long);
break;
}
return n;
}
/* Functions to output menu structure */
void addmenu (menutree *p,int i,char *func)
{
menutree *mt;
submenu *sm;
for (sm=p->sm; sm; sm=sm->next)
if (!strcmp (sm->mt->text,menutext[i]))
{
mt = sm->mt;
break;
}
if (sm)
{
i++;
if (menutext[i] == 0)
error ("Duplicate menu option '%s'",func);
addmenu (mt,i,func);
}
else
do
{
mt = alloc (sizeof (menutree));
mt->text = menutext[i];
mt->func = func;
mt->sm = 0;
sm = alloc (sizeof (submenu));
sm->mt = mt;
addlist (p->sm,sm);
p = mt;
i++;
}
while (menutext[i]);
}
void addoption (menutree *p,char *text,char *func)
{
int i;
char *s;
i = 0;
s = strtok (text,"!");
do
{
menutext[i++] = s;
if (i == MAXMENU)
error ("Menu tree too deep: '%s'",text);
s = strtok (0,"!");
}
while (s);
menutext[i] = 0;
addmenu (p,0,func);
}
void menuoutput (menutree *p,char *text)
{
char nexttext[4 + 1 + MAXMENU*2];
int i;
submenu *sm;
for (sm=p->sm,i=0; sm; sm=sm->next,i++)
if (sm->mt->sm)
{
sprintf (nexttext,"%s%02d",text,i);
menuoutput (sm->mt,nexttext);
}
nl ();
os ("execmenuitem ");
os (text);
os ("[] =");
nl ();
os ("{");
indent = 1;
for (sm=p->sm,i=0; sm; sm=sm->next,i++)
{
nl ();
os ("\"");
os (sm->mt->text);
os ("\",");
if (sm->mt->sm)
{
sprintf (nexttext,"%s%02d",text,i);
os (nexttext);
os (",0,");
}
else
{
os ("0,");
os (sm->mt->func);
os (",");
}
}
nl ();
os ("0");
indent = 0;
nl ();
os ("};");
nl ();
}
main (int argc,char **argv)
{
var *v,*v2;
file *f,*f2;
proc *p;
fileid *fi;
static menutree mt;
printf ("Database Program Generator v0.0 by Russell Wallace " __DATE__ "\n");
if (argc != 2)
{
printf ("Usage: dpg filename\n");
return 1;
}
/* Get output file name */
strcpy (outfilename,argv[1]);
if (!strchr (outfilename,'.'))
strcat (outfilename,".dpg");
/* Open input file */
infile = fopen (outfilename,"r");
if (infile == 0)
{
printf ("Can't open '%s'\n",outfilename);
return 1;
}
/* Create output file */
strcpy (strchr (outfilename,'.'),".c");
outfile = fopen (outfilename,"w");
if (outfile == 0)
{
printf ("Can't create '%s'\n",outfilename);
return 1;
}
/* Initialize lexical analyzer */
readc ();
lex ();
/* Standard stuff for output file */
os ("#include\t<stdio.h>");
nl ();
os ("#include\t<stdlib.h>");
nl ();
os ("#include\t<string.h>");
nl ();
os ("#include\t<fcntl.h>");
nl ();
os ("#include\t<io.h>");
nl ();
os ("#include\t\"video.h\"");
nl ();
os ("#include\t\"files.h\"");
nl ();
/* Global variables */
v = alloc (sizeof (var));
strcpy (v->name,"fieldno");
v->type = V_INT;
v->l = 4;
addsym ("fieldno",&globalnames,v);
addlist (globals,v);
parsevarlist (&globals,&globalnames);
outvarlist (globals);
if (globals)
nl ();
/* File definitions */
parsekeyword (K_FILES);
while (nt == T_UNDEF)
{
/* Create file structure */
f = alloc (sizeof (file));
memset (f,0,sizeof (file));
addsym (buf,&filenames,f);
addlist (files,f);
strcpy (f->name,buf);
lex ();
/* Fields */
if (nt != T_OPENBRACE)
error ("'{' expected");
lex ();
parsevarlist (&f->fields,&f->fieldnames);
if (nt != T_CLOSEBRACE)
error ("'}' expected");
lex ();
/* Index if any */
if (iskeyword (K_INDEX))
{
if (nt != T_UNDEF)
error ("Index field name expected");
strcpy (f->index.name,buf);
addsym (buf,&f->fieldnames,&f->index);
lex ();
f->index.type = V_STR;
f->index.l = parseconst ();
}
/* Is this file linked on other files? */
if (iskeyword (K_ON))
{
if (nt != T_OPENBRACE)
error ("'{' expected");
lex ();
while (nt != T_CLOSEBRACE)
{
fi = alloc (sizeof (fileid));
strcpy (fi->name,buf);
lex ();
addlist (f->on,fi);
}
lex ();
}
/* Is this file a table? */
if (iskeyword (K_TABLE))
f->table = parseconst ();
}
/* Fix up all file pointers to point to correct files */
for (f=files; f; f=f->next)
for (fi=f->on; fi; fi=fi->next)
{
strcpy (buf,fi->name);
fi->p = findsym (filenames);
if (fi->p == 0)
error ("'%s' is not the name of a file",buf);
}
/* Output file definitions */
for (f=files; f; f=f->next)
{
/* Structure definition */
nl ();
os ("typedef struct");
nl ();
os ("{");
indent = 1;
/* Links to next and previous records */
if (!f->table)
{
nl ();
os ("long next;");
nl ();
os ("long prev;");
nl ();
}
/* Index field */
if (f->index.l)
{
nl ();
os ("char ");
os (f->index.name);
os ("[");
oi (f->index.l);
os ("];");
nl ();
}
/* Files this one is linked on */
for (fi=f->on; fi; fi=fi->next)
{
nl ();
os ("long ");
os (fi->p->name);
os ("ptr;");
nl ();
os ("long ");
os (fi->p->name);
os ("next;");
nl ();
os ("long ");
os (fi->p->name);
os ("prev;");
nl ();
}
/* Files that are linked on this one */
for (f2=files; f2; f2=f2->next)
for (fi=f2->on; fi; fi=fi->next)
if (fi->p == f)
{
nl ();
os ("long ");
os (f2->name);
os ("first;");
nl ();
os ("long ");
os (f2->name);
os ("last;");
nl ();
break;
}
/* Normal fields */
outvarlist (f->fields);
/* End of structure definition */
indent = 0;
nl ();
os ("} ");
os (f->name);
os (";");
nl ();
/* Blank record */
nl ();
os (f->name);
os (" blank");
os (f->name);
os (" =");
nl ();
os ("{");
indent = 1;
/* Links to next and previous records */
if (!f->table)
{
blankptr ();
blankptr ();
nl ();
}
/* Index field */
if (f->index.l)
{
outblank (&f->index);
nl ();
}
/* Files this one is linked on */
for (fi=f->on; fi; fi=fi->next)
{
blankptr ();
blankptr ();
blankptr ();
nl ();
}
/* Files that are linked on this one */
for (f2=files; f2; f2=f2->next)
for (fi=f2->on; fi; fi=fi->next)
if (fi->p == f)
{
blankptr ();
blankptr ();
nl ();
break;
}
/* Normal fields */
for (v=f->fields; v; v=v->next)
outblank (v);
/* End of blank record */
indent = 0;
nl ();
os ("};");
nl ();
/* Record variable */
nl ();
os (f->name);
os (" ");
os (f->name);
os (";");
if (!f->table)
{
/* File handle */
nl ();
os ("int ");
os (f->name);
os ("file;");
/* Record pointer */
nl ();
os ("long ");
os (f->name);
os ("ptr;");
/* Index file handle */
if (f->index.l)
{
nl ();
os ("int ");
os (f->name);
os ("indexfile;");
}
nl ();
}
/* Data in miscfile */
nl ();
os ("#define\t");
os (f->name);
os ("miscoff\t");
oi (miscoff);
nl ();
if (f->table)
miscoff += recsize (f);
else
{
miscoff += 3*sizeof (long);
if (f->index.l)
miscoff += sizeof (long);
}
}
/* Procedures */
parsekeyword (K_PROCEDURES);
while (nt == T_UNDEF)
{
/* Create procedure structure */
p = alloc (sizeof (proc));
addsym (buf,&procnames,p);
addlist (procs,p);
strcpy (p->name,buf);
lex ();
/* Get menu item name if present */
p->menuitem = 0;
if (nt == T_STR)
{
p->menuitem = alloc (strlen (buf) + 1);
strcpy (p->menuitem,buf);
lex ();
}
/* Output procedure heading */
nl ();
os ("void ");
os (p->name);
os (" (void)");
nl ();
os ("{");
/* Indent one tab column within procedure */
indent = 1;
/* Local variables */
parsevarlist (&locals,&localnames);
outvarlist (locals);
if (locals)
nl ();
/* Procedure code */
if (nt != T_OPENBRACE)
error ("'{' expected");
lex ();
while (nt != T_CLOSEBRACE)
parsestatement ();
lex ();
/* Finish indented part */
indent = 0;
/* Close brace after code */
nl ();
os ("}");
/* Blank line before next procedure */
nl ();
/* Free local variable list */
v = locals;
while (v)
{
v2 = v->next;
free (v);
v = v2;
}
locals = 0;
/* Free local variable symbol table */
freesym (localnames);
localnames = 0;
}
if (nt != T_EOF)
error ("Procedure definition expected");
/* Menu structure */
for (p=procs; p; p=p->next)
if (p->menuitem)
addoption (&mt,p->menuitem,p->name);
menuoutput (&mt,"menu");
/* Main function */
nl ();
os ("main (void)");
nl ();
os ("{");
indent = 1;
nl ();
os ("long r;");
nl ();
/* Open or create files */
for (f=files; f; f=f->next)
if (!f->table)
{
nl ();
os (f->name);
os ("file = opencreate (\"");
os (f->name);
os (".dat\");");
if (f->index.l)
{
nl ();
os (f->name);
os ("indexfile = opencreate (\"");
os (f->name);
os (".idx\");");
}
}
nl ();
/* Initialize misc file */
nl ();
os ("miscfile = open (\"misc.dat\",O_RDWR);");
nl ();
os ("if (miscfile < 0)");
nl ();
os ("{");
indent++;
nl ();
os ("miscfile = open (\"misc.dat\",O_CREAT | O_TRUNC | O_RDWR,0777);");
nl ();
os ("if (miscfile < 0)");
nl ();
os ("{");
indent++;
nl ();
os ("printf (\"Can't create file misc.dat\\n\");");
nl ();
os ("return 1;");
indent--;
nl ();
os ("}");
for (f=files; f; f=f->next)
{
nl ();
if (f->table)
{
os ("for (r=0; r!=");
oi (f->table);
os ("; r++)");
indent++;
nl ();
os ("mwrite (&");
os (f->name);
os (",sizeof ");
os (f->name);
os (");");
indent--;
}
else
if (f->index.l)
os ("mblank4 ();");
else
os ("mblank3 ();");
}
indent--;
nl ();
os ("}");
nl ();
nl ();
os ("initvideo ();");
nl ();
os ("execmenu (menu,-1,-1,0,0);");
nl ();
os ("return 0;");
indent = 0;
nl ();
os ("}");
return 0;
}