Digital Research
This commit is contained in:
2020-11-06 18:50:37 +01:00
parent 621ed8ccaf
commit 31738079c4
8481 changed files with 1888323 additions and 0 deletions

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1 @@
This archive conitains the above PLM2C translator, cleaned up, and buildable on a unix system. It contains PLM2C.ZIP, which is the PLM to C translator, and PLM.ZIP, which is frontend parser for gcc.

View File

@@ -0,0 +1,19 @@
# makefile for tree stuff
# vix 24jul87 [stripped down from as makefile]
CFLAGS = -O
TRTEST_OBJ = t_trtest.o tree.o
all : t_trtest
t_trtest : $(TRTEST_OBJ)
cc -o t_trtest $(TRTEST_OBJ)
clean : FRC
rm -f core a.out t_trtest $(TRTEST_OBJ)
FRC :
tree.o : tree.c tree.h vixie.h
t_trtest.o : t_trtest.c tree.h vixie.h

View File

@@ -0,0 +1,23 @@
AVL Trees V1.0
24-July-1987
Paul Vixie
This library and test program are useful for creating and using balanced
binary trees (AVL trees). The tree is held in memory, using malloc(3) to
allocate storage. A better version would allow file-based trees in
addition; once memory mapped files hit the UNIX(tm) community, this will
be much easier to do. In the meanwhile, these routines have been very
useful to be for symbol tables and the like. (Yes, I'm sure hashing is
better in some way, but I've used this for symbol tables, just the same.)
I cannot take credit for the algorithms. See "Algorithms & Data Structures,"
Niklaus Wirth, Prentice-Hall 1986, ISBN 0-13-022005-1. This is an update of
Wirth's previous book, titled "Algorythms + Data Structures = Programs,"
which used Pascal as the language for examples. This later book uses the
newer Modula-2 for it's examples; this tree code was created using the
Modula-2 examples as guidelines. At the time I typed this stuff in (about
a year ago, in July 1987), I understood how it all worked. Today, well...
This code is hereby placed in the public domain, unless restrictions apply
from Prentice-Hall on the algorithms themselves. If you use or redistribute
this code, please leave my name (and Wirth's) in the comments.

View File

@@ -0,0 +1,126 @@
/* t_trtest - test the tree functions
* vix 24jul87 [documented, added savestr for net distribution]
*/
#define MAIN
#include <stdio.h>
#include "vixie.h"
#include "tree.h"
main()
{
tree *t;
char line[100];
tree_init(&t);
while (printf("line (or .): "), gets(line), line[0] != '.')
{
if (strncmp(line, "~r ", 3)) {
trtest(&t, line, 1);
}
else {
FILE *f;
if (!(f = fopen(&line[3], "r")))
perror(&line[3]);
else {
while (fgets(line, 100, f)) {
line[strlen(line)-1] = '\0';
printf("(%s)\n", line);
trtest(&t, line, 0);
}
fclose(f);
}
}
}
}
trtest(tt, line, inter)
tree **tt;
char *line;
{
char opts[100], *tree_srch(), *pc, *n;
int uar_print(), duar(), compar(), opt, status;
pc = tree_srch(tt, compar, line);
printf("tree_srch=%08lx\n", pc);
if (pc)
{
printf(" <%s>\n", pc);
if (inter) {
printf("delete? "); gets(opts); opt = (opts[0]=='y');
}
else
opt = 1;
if (opt) {
status = tree_delete(tt, compar, line, duar);
printf("delete=%d\n", status);
}
}
else
{
if (inter) {
printf("add? "); gets(opts); opt = (opts[0]=='y');
}
else
opt = 1;
if (opt) {
char *savestr();
n = savestr(line);
tree_add(tt, compar, n, duar);
}
}
tree_trav1(*tt, 0);
}
duar(pc)
char *pc;
{
printf("duar called, pc=%08X: <%s>\n", pc, pc?pc:"");
free(pc);
}
tree_trav1(t, l)
tree *t;
{
int i;
if (!t) return;
tree_trav1(t->tree_l, l+1);
for (i=0; i<l; i++) printf(" ");
printf("%08lx (%s)\n", t->tree_p, t->tree_p);
tree_trav1(t->tree_r, l+1);
}
uar_print(pc)
char *pc;
{
printf("uar_print(%08lx)", pc);
if (pc)
printf(" '%s'", pc);
putchar('\n');
return 1;
}
compar(l, r)
char *l, *r;
{
printf("compar(%s,%s)=%d\n", l, r, strcmp(l, r));
return strcmp(l, r);
}
char *
savestr(str)
char *str;
{
char *save;
save = malloc(strlen(str) + 1);
strcpy(save, str);
return save;
}

View File

@@ -0,0 +1,511 @@
/* as_tree - tree library for as
* vix 14dec85 [written]
* vix 02feb86 [added tree balancing from wirth "a+ds=p" p. 220-221]
* vix 06feb86 [added tree_mung()]
* vix 20jun86 [added tree_delete per wirth a+ds (mod2 v.) p. 224]
* vix 23jun86 [added delete uar to add for replaced nodes]
*/
/* This program text was created by Paul Vixie using examples from the book:
* "Algorithms & Data Structures," Niklaus Wirth, Prentice-Hall, 1986, ISBN
* 0-13-022005-1. This code and associated documentation is hereby placed
* in the public domain.
*/
/*#define DEBUG "tree"*/
#include <stdio.h>
#include "vixie.h"
#include "tree.h"
#ifdef DEBUG
#define MSG(msg) printf("DEBUG: '%s'\n", msg);
#else
#define MSG(msg)
#endif
void tree_init(ppr_tree)
tree **ppr_tree;
{
ENTER("tree_init")
*ppr_tree = NULL;
EXITV
}
char *tree_srch(ppr_tree, pfi_compare, pc_user)
tree **ppr_tree;
int (*pfi_compare)();
char *pc_user;
{
register int i_comp;
register tree *pr_new;
ENTER("tree_srch")
if (*ppr_tree)
{
i_comp = (*pfi_compare)(pc_user, (**ppr_tree).tree_p);
if (i_comp > 0)
EXIT(tree_srch(
&(**ppr_tree).tree_r,
pfi_compare,
pc_user
))
if (i_comp < 0)
EXIT(tree_srch(
&(**ppr_tree).tree_l,
pfi_compare,
pc_user
))
/* not higher, not lower... this must be the one.
*/
EXIT((**ppr_tree).tree_p)
}
/* grounded. NOT found.
*/
EXIT(NULL)
}
void tree_add(ppr_tree, pfi_compare, pc_user, pfi_delete)
tree **ppr_tree;
int (*pfi_compare)();
char *pc_user;
int (*pfi_delete)();
{
void sprout();
int i_balance = FALSE;
ENTER("tree_add")
sprout(ppr_tree, pc_user, &i_balance, pfi_compare, pfi_delete);
EXITV
}
static void sprout(ppr, pc_data, pi_balance, pfi_compare, pfi_delete)
tree **ppr;
char *pc_data;
int *pi_balance;
int (*pfi_compare)();
int (*pfi_delete)();
{
tree *p1, *p2;
int cmp;
ENTER("sprout")
/* are we grounded? if so, add the node "here" and set the rebalance
* flag, then exit.
*/
if (!*ppr) {
MSG("grounded. adding new node, setting h=true")
*ppr = (tree *) malloc(sizeof(tree));
(*ppr)->tree_l = NULL;
(*ppr)->tree_r = NULL;
(*ppr)->tree_b = 0;
(*ppr)->tree_p = pc_data;
*pi_balance = TRUE;
EXITV
}
/* compare the data using routine passed by caller.
*/
cmp = (*pfi_compare)(pc_data, (*ppr)->tree_p);
/* if LESS, prepare to move to the left.
*/
if (cmp < 0) {
MSG("LESS. sprouting left.")
sprout(&(*ppr)->tree_l, pc_data, pi_balance,
pfi_compare, pfi_delete);
if (*pi_balance) { /* left branch has grown longer */
MSG("LESS: left branch has grown")
switch ((*ppr)->tree_b)
{
case 1: /* right branch WAS longer; balance is ok now */
MSG("LESS: case 1.. balnce restored implicitly")
(*ppr)->tree_b = 0;
*pi_balance = FALSE;
break;
case 0: /* balance WAS okay; now left branch longer */
MSG("LESS: case 0.. balnce bad but still ok")
(*ppr)->tree_b = -1;
break;
case -1:
/* left branch was already too long. rebalnce */
MSG("LESS: case -1: rebalancing")
p1 = (*ppr)->tree_l;
if (p1->tree_b == -1) { /* LL */
MSG("LESS: single LL")
(*ppr)->tree_l = p1->tree_r;
p1->tree_r = *ppr;
(*ppr)->tree_b = 0;
*ppr = p1;
}
else { /* double LR */
MSG("LESS: double LR")
p2 = p1->tree_r;
p1->tree_r = p2->tree_l;
p2->tree_l = p1;
(*ppr)->tree_l = p2->tree_r;
p2->tree_r = *ppr;
if (p2->tree_b == -1)
(*ppr)->tree_b = 1;
else
(*ppr)->tree_b = 0;
if (p2->tree_b == 1)
p1->tree_b = -1;
else
p1->tree_b = 0;
*ppr = p2;
} /*else*/
(*ppr)->tree_b = 0;
*pi_balance = FALSE;
} /*switch*/
} /*if*/
EXITV
} /*if*/
/* if MORE, prepare to move to the right.
*/
if (cmp > 0) {
MSG("MORE: sprouting to the right")
sprout(&(*ppr)->tree_r, pc_data, pi_balance,
pfi_compare, pfi_delete);
if (*pi_balance) { /* right branch has grown longer */
MSG("MORE: right branch has grown")
switch ((*ppr)->tree_b)
{
case -1:MSG("MORE: balance was off, fixed implicitly")
(*ppr)->tree_b = 0;
*pi_balance = FALSE;
break;
case 0: MSG("MORE: balance was okay, now off but ok")
(*ppr)->tree_b = 1;
break;
case 1: MSG("MORE: balance was off, need to rebalance")
p1 = (*ppr)->tree_r;
if (p1->tree_b == 1) { /* RR */
MSG("MORE: single RR")
(*ppr)->tree_r = p1->tree_l;
p1->tree_l = *ppr;
(*ppr)->tree_b = 0;
*ppr = p1;
}
else { /* double RL */
MSG("MORE: double RL")
p2 = p1->tree_l;
p1->tree_l = p2->tree_r;
p2->tree_r = p1;
(*ppr)->tree_r = p2->tree_l;
p2->tree_l = *ppr;
if (p2->tree_b == 1)
(*ppr)->tree_b = -1;
else
(*ppr)->tree_b = 0;
if (p2->tree_b == -1)
p1->tree_b = 1;
else
p1->tree_b = 0;
*ppr = p2;
} /*else*/
(*ppr)->tree_b = 0;
*pi_balance = FALSE;
} /*switch*/
} /*if*/
EXITV
} /*if*/
/* not less, not more: this is the same key! replace...
*/
MSG("I found it! Replacing data value")
*pi_balance = FALSE;
if (pfi_delete)
(*pfi_delete)((*ppr)->tree_p);
(*ppr)->tree_p = pc_data;
EXITV
}
int tree_delete(ppr_p, pfi_compare, pc_user, pfi_uar)
tree **ppr_p;
int (*pfi_compare)();
char *pc_user;
int (*pfi_uar)();
{
int i_balance = FALSE, i_uar_called = FALSE;
ENTER("tree_delete");
EXIT(delete(ppr_p, pfi_compare, pc_user, pfi_uar,
&i_balance, &i_uar_called))
}
static int delete(ppr_p, pfi_compare, pc_user, pfi_uar,
pi_balance, pi_uar_called)
tree **ppr_p;
int (*pfi_compare)();
char *pc_user;
int (*pfi_uar)();
int *pi_balance;
int *pi_uar_called;
{
void del(), balanceL(), balanceR();
tree *pr_q;
int i_comp, i_ret;
ENTER("delete")
if (*ppr_p == NULL) {
MSG("key not in tree")
EXIT(FALSE)
}
i_comp = (*pfi_compare)((*ppr_p)->tree_p, pc_user);
if (i_comp > 0) {
MSG("too high - scan left")
i_ret = delete(&(*ppr_p)->tree_l, pfi_compare, pc_user, pfi_uar,
pi_balance, pi_uar_called);
if (*pi_balance)
balanceL(ppr_p, pi_balance);
}
else if (i_comp < 0) {
MSG("too low - scan right")
i_ret = delete(&(*ppr_p)->tree_r, pfi_compare, pc_user, pfi_uar,
pi_balance, pi_uar_called);
if (*pi_balance)
balanceR(ppr_p, pi_balance);
}
else {
MSG("equal")
pr_q = *ppr_p;
if (pr_q->tree_r == NULL) {
MSG("right subtree null")
*ppr_p = pr_q->tree_l;
*pi_balance = TRUE;
}
else if (pr_q->tree_l == NULL) {
MSG("right subtree non-null, left subtree null")
*ppr_p = pr_q->tree_r;
*pi_balance = TRUE;
}
else {
MSG("neither subtree null")
del(&pr_q->tree_l, pi_balance, &pr_q, pfi_uar,
pi_uar_called);
if (*pi_balance)
balanceL(ppr_p, pi_balance);
}
free(pr_q);
if (!*pi_uar_called && *pfi_uar)
(*pfi_uar)(pr_q->tree_p);
i_ret = TRUE;
}
EXIT(i_ret)
}
static void del(ppr_r, pi_balance, ppr_q, pfi_uar, pi_uar_called)
tree **ppr_r;
int *pi_balance;
tree **ppr_q;
int (*pfi_uar)();
int *pi_uar_called;
{
void balanceR();
ENTER("del")
if ((*ppr_r)->tree_r != NULL) {
del(&(*ppr_r)->tree_r, pi_balance, ppr_q, pfi_uar,
pi_uar_called);
if (*pi_balance)
balanceR(ppr_r, pi_balance);
} else {
if (pfi_uar)
(*pfi_uar)((*ppr_q)->tree_p);
*pi_uar_called = TRUE;
(*ppr_q)->tree_p = (*ppr_r)->tree_p;
*ppr_q = *ppr_r;
*ppr_r = (*ppr_r)->tree_l;
*pi_balance = TRUE;
}
EXITV
}
static void balanceL(ppr_p, pi_balance)
tree **ppr_p;
int *pi_balance;
{
tree *p1, *p2;
int b1, b2;
ENTER("balanceL")
MSG("left branch has shrunk")
switch ((*ppr_p)->tree_b)
{
case -1: MSG("was imbalanced, fixed implicitly")
(*ppr_p)->tree_b = 0;
break;
case 0: MSG("was okay, is now one off")
(*ppr_p)->tree_b = 1;
*pi_balance = FALSE;
break;
case 1: MSG("was already off, this is too much")
p1 = (*ppr_p)->tree_r;
b1 = p1->tree_b;
if (b1 >= 0) {
MSG("single RR")
(*ppr_p)->tree_r = p1->tree_l;
p1->tree_l = *ppr_p;
if (b1 == 0) {
MSG("b1 == 0")
(*ppr_p)->tree_b = 1;
p1->tree_b = -1;
*pi_balance = FALSE;
} else {
MSG("b1 != 0")
(*ppr_p)->tree_b = 0;
p1->tree_b = 0;
}
*ppr_p = p1;
} else {
MSG("double RL")
p2 = p1->tree_l;
b2 = p2->tree_b;
p1->tree_l = p2->tree_r;
p2->tree_r = p1;
(*ppr_p)->tree_r = p2->tree_l;
p2->tree_l = *ppr_p;
if (b2 == 1)
(*ppr_p)->tree_b = -1;
else
(*ppr_p)->tree_b = 0;
if (b2 == -1)
p1->tree_b = 1;
else
p1->tree_b = 0;
*ppr_p = p2;
p2->tree_b = 0;
}
}
EXITV
}
static void balanceR(ppr_p, pi_balance)
tree **ppr_p;
int *pi_balance;
{
tree *p1, *p2;
int b1, b2;
ENTER("balanceR")
MSG("right branch has shrunk")
switch ((*ppr_p)->tree_b)
{
case 1: MSG("was imbalanced, fixed implicitly")
(*ppr_p)->tree_b = 0;
break;
case 0: MSG("was okay, is now one off")
(*ppr_p)->tree_b = -1;
*pi_balance = FALSE;
break;
case -1: MSG("was already off, this is too much")
p1 = (*ppr_p)->tree_l;
b1 = p1->tree_b;
if (b1 <= 0) {
MSG("single LL")
(*ppr_p)->tree_l = p1->tree_r;
p1->tree_r = *ppr_p;
if (b1 == 0) {
MSG("b1 == 0")
(*ppr_p)->tree_b = -1;
p1->tree_b = 1;
*pi_balance = FALSE;
} else {
MSG("b1 != 0")
(*ppr_p)->tree_b = 0;
p1->tree_b = 0;
}
*ppr_p = p1;
} else {
MSG("double LR")
p2 = p1->tree_r;
b2 = p2->tree_b;
p1->tree_r = p2->tree_l;
p2->tree_l = p1;
(*ppr_p)->tree_l = p2->tree_r;
p2->tree_r = *ppr_p;
if (b2 == -1)
(*ppr_p)->tree_b = 1;
else
(*ppr_p)->tree_b = 0;
if (b2 == 1)
p1->tree_b = -1;
else
p1->tree_b = 0;
*ppr_p = p2;
p2->tree_b = 0;
}
}
EXITV
}
int tree_trav(ppr_tree, pfi_uar)
tree **ppr_tree;
int (*pfi_uar)();
{
ENTER("tree_trav")
if (!*ppr_tree)
EXIT(TRUE)
if (!tree_trav(&(**ppr_tree).tree_l, pfi_uar))
EXIT(FALSE)
if (!(*pfi_uar)((**ppr_tree).tree_p))
EXIT(FALSE)
if (!tree_trav(&(**ppr_tree).tree_r, pfi_uar))
EXIT(FALSE)
EXIT(TRUE)
}
void tree_mung(ppr_tree, pfi_uar)
tree **ppr_tree;
int (*pfi_uar)();
{
ENTER("tree_mung")
if (*ppr_tree)
{
tree_mung(&(**ppr_tree).tree_l, pfi_uar);
tree_mung(&(**ppr_tree).tree_r, pfi_uar);
if (pfi_uar)
(*pfi_uar)((**ppr_tree).tree_p);
free(*ppr_tree);
*ppr_tree = NULL;
}
EXITV
}

View File

@@ -0,0 +1,19 @@
/* tree.h - declare structures used by tree.c
* vix 27jun86 [broken out of tree.c]
*/
#ifndef _TREE_FLAG
#define _TREE_FLAG
typedef struct tree_s
{
struct tree_s *tree_l, *tree_r;
short tree_b;
char *tree_p;
}
tree;
#endif _TREE_FLAG

View File

@@ -0,0 +1,124 @@
.TH TREE 2 "23 June 1986"
.UC 4
.SH NAME
tree_init, tree_mung, tree_srch, tree_add, tree_delete, tree_trav \- balanced binary tree routines
.SH SYNOPSIS
.nf
.B void
.B tree_init(tree)
.B int **tree;
.PP
.B int *
.B tree_srch(tree, compare, data)
.B int **tree, (*compare)(), *data;
.PP
.B void
.B tree_add(tree, compare, data, del_uar)
.B int **tree, (*compare)(), *data, (*del_uar)();
.PP
.B int
.B tree_delete(tree, compare, data, del_uar)
.B int **tree, (*compare)(), *data, (*del_uar)();
.PP
.B int
.B tree_trav(tree, trav_uar)
.B int **tree, (*trav_uar)();
.PP
.B void
.B tree_mung(tree, del_uar)
.B int **tree, (*del_uar)();
.fi
.SH DESCRIPTION
These functions create and manipulate a balanced binary (AVL) tree. Each node
of the tree contains the expected left & right subtree pointers, a short-int
balance indicator, and a pointer to the user-data. On a 32-bit system, this
means an overhead of 4+4+2+4 bytes per node. There is no key data type
enforced by this package; a caller-supplied compare routine is used to compare
user-data blocks.
.PP
.I Tree_init
creates an empty tree and binds it to
.I tree
(which for this and all other routines in this package should be declared as
a pointer to integer and passed by reference), which can then be used by other
routines in this package. Note that more than one
.I tree
variable can exist at once; thus multiple trees can be manipulated
simultaneously.
.PP
.I Tree_srch
searches a tree for a specific node and returns either
.I NULL
if no node was found, or the address of the user-data for that node if one was
found.
.I compare
is the address of a function to compare two user-data blocks. This routine
should work much the way
.IR strcmp 2
does; in fact,
.I strcmp
could be used if the user-data was a null-terminated string.
.I data
is the address of a user-data block to be used via
.I compare
as the search criteria. The tree is searched for a node where
.I compare
returns 0.
.PP
.I Tree_add
inserts or replaces a node in the specified tree. The tree specified by
.I tree
is searched as in
.I tree_srch,
and if a node is found to match
.I data,
then the
.I del_uar
function is called with the address of the user-data block for the node
(this routine should deallocate any dynamic memory which is pointed to
exclusively by the node); the user-data pointer for the node is then
replaced by the value of
.I data.
If no node is found to match, a new node is added (which may or may not
cause a transparent rebalance operation), with a user-data pointer equal
to
.I data.
.PP
.I Tree_delete
deletes a node from
.I tree.
A rebalance may or may not occur, depending on where the node is removed from
and what the rest of the tree looks like.
.I Tree_delete
returns TRUE if a node was deleted, FALSE otherwise.
.PP
.I Tree_trav
traverses all of
.I tree,
calling
.I trav_uar
with the address of each user-data block. If
.I trav_uar
returns FALSE at any time,
.I tree_trav
will immediately return FALSE to its caller. Otherwise all nodes will be
reached and
.I tree_trav
will return TRUE.
.PP
.I Tree_mung
deletes every node in
.I tree,
calling
.I del_uar
with the user-data address from each node (see
.I tree_add
and
.I tree_delete
above). The tree is left in the same state that
.I tree_init
leaves it in \- i.e., empty.
.SH AUTHOR
Paul Vixie, converted and augumented from Modula-2 examples in
.I Algorithms & Data Structures,
Niklaus Wirth, Prentice-Hall, ISBN 0-13-022005-1.

View File

@@ -0,0 +1,73 @@
/* vixie.h - include file to define general vixie-type things
* v1.0 vix 21jun86 [broken out of as.h]
*/
#ifdef DOCUMENTATION
There are two macros you can define before including this file which can
change the things defined by this file.
DEBUG: if defined, will cause enter/exit messages to be printed by the
ENTER/EXIT/EXITV macros. If not defined, causes ENTER to do nothing,
and EXIT/EXITV to generate 'return' without any messages.
If defined, should be set to the name of the including module.
MAIN: Should be defined for a program containing a main() function which
is linked with other modules which include this file.
Value is not important, only existence/nonexistence matters.
#endif DOCUMENTATION
#ifndef _VIXIE_FLAG
#define _VIXIE_FLAG
/*--- debugging stuff ---*/
#define MAXPROC 256
#ifdef DEBUG
#define ENTER(proc) { \
APC_PROCS[I_PROC] = proc; \
printf("ENTER(%d:%s.%s)\n", \
I_PROC, DEBUG, APC_PROCS[I_PROC]); \
I_PROC++; \
}
#define EXIT(value) { \
I_PROC--; \
printf("EXIT(%d:%s.%s)\n", \
I_PROC, DEBUG, \
APC_PROCS[I_PROC]); \
return value; \
}
#define EXITV { \
I_PROC--; \
printf("EXITV(%d:%s.%s)\n", \
I_PROC, DEBUG, \
APC_PROCS[I_PROC]); \
return value; \
}
#else
#define ENTER(proc)
#define EXIT(value) {return value;}
#define EXITV return;
#endif
#ifdef MAIN
int I_PROC = 0;
char *APC_PROCS[MAXPROC];
#else
extern int I_PROC;
extern char *APC_PROCS[MAXPROC];
#endif
/*--- why didn't k&r put these into stdio.h? ---*/
#define TRUE 1
#define FALSE 0
extern char *malloc(), *calloc();
#endif _VIXIE_FLAG

View File

@@ -0,0 +1,44 @@
# $Id: Makefile,v 1.3 1994/02/28 22:28:36 hays Exp $
LEX=flex
LEXFLAGS= -v
YACC=bison
YACCFLAGS= -y -v -d
CFLAGS= -g
DIST=README Makefile plm-lex.l plm-manifest.h plm-parse.y scope.c scope.h
OBJS= plm-lex.o plm-parse.o scope.o tree.o
#NOTE: tree.o and tree.h come from Paul Vixie's PD AVL Tree package,
# comp.sources.unix Volume 27, Issue 34.
.y.c:
plm: $(OBJS)
$(CC) $(CFLAGS) -o $@ $(OBJS)
plm-parse.h: plm-parse.c
plm-lex.c: plm-lex.l
$(LEX) $(LEXFLAGS) -t $< > $@
plm-parse.c: plm-parse.y
$(YACC) $(YACCFLAGS) $< -o $@
plm-lex.o: plm-lex.c plm-manifest.h plm-parse.h scope.h
plm-parse.o: plm-parse.c plm-manifest.h scope.h
scope.o: scope.c tree.h scope.h
clean:
rm -f plm-parse.c plm-parse.h plm-parse.output \
plm-*.o scope.o lex.backtrack tmp *~ plm-lex.c core plm \
plm.shar
source:
$(CO) $(DIST)
dist: source
shar $(DIST) > plm.shar

View File

@@ -0,0 +1,189 @@
$Id: README,v 1.4 1994/04/05 20:33:58 hays Exp $
Ah, the wisdom of the ages...
Introduction
------------
What you are looking at is a basic (very basic) parser for a PL/M
language.
The parser does nothing useful, and it isn't even a terribly wonderful
example. On the other hand, it appears that no one else has bothered
to publish even this much, before.
However, the parser does recognize a language very like PL/M-86,
PL/M-286, or PL/M-386, as best we can determine.
All the information used to derive this parser comes from published
manuals, sold to the public. No proprietary information, trade
secrets, patented information, corporate assets, or skulduggery was
used to develop this parser. Neither of the authors has ever seen the
source to a working PL/M compiler (or, for that matter, to a
non-working PL/M compiler).
Implementation Limits
---------------------
This PL/M parser was developed and tested on a 486DX2/66 clone PC
running Linux. The C code is written for an ANSI-compliant C
compiler; GCC was used in our testing. Also, flex and bison were
used, not lex and yacc. Paul Vixie's comp.sources.unix implementation
of AVL trees was used to implement symbol table lookups.
You should expect some problems if you plan on building this parser
with a K&R style C compiler. Using yacc and/or lex may be
problematic, as well.
This parser does not support any of the "dollar" directives of a
proper PL/M compiler. In fact, it will croak with the helpful message
"parse error". Thus, implementing include files and compiler
directives is left as an exercise for the reader.
The macro facility (aka "literally" declarations) depends on the
lexical analysis skeleton allowing multiple characters of push-back on
the input stream. This is a very, very poor assumption, but, with
flex, at least, workable for this example. A real PL/M compiler would
allow literals of unlimited length. To find the offending code, grep
for the string "very weak" in the file "plm-lex.l".
No error recovery is implemented in the parser, at all.
There are no shift-reduce conflicts, nor reduce-reduce conflicts.
There are a couple of places in the parser where similar constructs
cannot be distinguished, except by semantic analysis. These are
marked by appropriate comments in the parser source file.
The "scoped literal table" implementation depends on Paul Vixie's
(paul@vix.com) public domain AVL tree code, available as
comp.sources.unix Volume 27, Issue 34 (`avl-subs'), at a friendly ftp
site near you. We use "gatekeeper.dec.com". The benefits of using
AVL trees for a symbol table (versus, say, hashing) are not subject to
discussion. We used the avl-subs source code because it is reliable
and easy to use.
This grammar has been validated against about 10,000 lines of real and
artificial PL/M code.
PL/M Quirks
-----------
PL/M has some very interesting quirks. For example, a value is
considered to be "true", for the purposes of an `if' test, if it is
odd (low bit set). Thus, the value 0x3 is true, whereas 0x4 is not.
The language itself, given a boolean expression, generates the value
0xff for true. [This factoid doesn't affect the parser per se, but
does appear to be the main pitfall for those whose hubris leads them
to translate PL/M to C.]
String constants can contain any ASCII value, excepting a single
apostrophe, a newline, or 0x81. The latter, presumably, has something
to do with Kanji support.
To embed a single apostrophe in a string constant, two apostrophes may
be used. Thus, 'k''s' is a string consisting of a letter k, a single
apostrophe, and a letter s. Strings are not null terminated, so our
example string, 'k''s', requires just three bytes of storage.
PL/M supports a macro language, of sorts, that is integrated into the
language's declaration syntax:
declare Ford literally 'Edsel';
declare Mercury literally 'Ford';
After the above declarations, any instance of the identifier "Ford"
will be replaced with the string "Edsel", and any occurrence of the
identifier "Mercury" will be replaced by the string "Ford", which will
then be replaced by the string "Edsel". The literal string can be
more complicated, of course. Only identifiers are subject to
substitution - substitution does not occur inside string constants.
Literal macros are parameterless, and obey the scoping rules of the
language. Thus, it is possible to have different values for the same
macro in different, non-nested scopes. [Exercise: Why can't you have
different values for literals in nested scopes?]
Keywords, of course, cannot be macro names, because they are not
allowed as variable names.
PL/M allows dollar signs ("$") to be used inside keywords,
identifiers, and numerical constants. PL/M is also case insensitive.
Thus, the following two identifiers are the "same":
my_very_own_variable_02346
m$Y_$$$VeRy_$$O$$$$$W$$$$$$N_varIABLE$$$$$$$$$$_$02$346
Loverly, eh? Obfuscated C, stand to the side.
Casting in PL/M (a relatively late addition to the language) is
provided by a motley assortment of functions with the same names as
the basic types to which they are casting, accepting a single argument
of some other (or even the same) type.
Note that the EBNF grammar published in what must be considered the
definitive work, _PL/M Programmer's Guide_, Intel order number
452161-003, Appendix C, is incorrect in several respects. If you're
interested in the differences, we've preserved, as much as is
possible, the production names of that EBNF in the YACCable grammar.
Some known problems with the published, Appendix C, EBNF grammar:
- One of the productions is an orphan, ("scoping_statements").
- unary minus is shown as a prefix operator, and unary plus as a
postfix operator ("secondary").
- Casting does not appear in the published grammar.
- Nested structures do not appear in the published grammar, and
the reference syntax for selecting a nested structure member
is also missing.
- The WORD type is missing from the "basic_type" production.
- The "initialization" production allows the initial value list
only after the INITIAL keyword, when, in fact, the initial value
list may follow the DATA keyword, as well.
On the other hand, the precedence of the expression operators is
correct as written in the EBNF grammar, the dangling else problem is
non-existent, and there are no associativity problems, as all
operators associate left-to-right.
To complicate matters, the above referenced manual may be out of
print. A more recent version, which covers the PL/M-386 dialect only,
is _PL/M-386 Programmer's Guide_, Intel order number 611052-001.
The latter manual has some corrections, but has some introduced errors
in the EBNF, as well. The problems with the unary minus and the
"initialization" production are repaired, but the definition for a
"binary_number" is malformed, as are the definitions for the
"fractional_part", "string_body_element", "variable_element", and
"if_condition" productions.
We're right, they're wrong.
The Authors
-----------
Gary Funck (gary@intrepid.com) was responsible for starting this
effort. He authored the original grammar.
Kirk Hays (hays@ichips.intel.com) wrote the lexical analyzer and the
scoped literal table implementation. He also validated and corrected
the grammar, and extended it to cover documented features not
appearing in the published EBNF.
Future Plans
------------
If there is enough interest (or, even if there isn't), Kirk is
planning on producing a PL/M front end for the GNU compiler. Contact
him at the above Email address for further information. Donations of
PL/M source code of any dialect (including PL/M-80, PL/M-51, and
PL/M-96)(yes, we already have the Kermit implementations), or a
willingness to be a pre-alpha tester with code you cannot donate, are
sufficient grounds to contact Kirk.

View File

@@ -0,0 +1,301 @@
%{
/* lexer for PL/M syntax.
$Id: plm-lex.l,v 1.2 1994/02/28 22:24:34 hays Exp $
Copyright 1994 by Kirk Hays (hays@ichips.intel.com) and Gary Funck
(gary@intrepid.com)
USE AT YOUR OWN RISK. NO WARRANTY EXPRESSED OR IMPLIED.
This code is distributed in the hope that it will be useful,
but without any warranty. Further, there is no implied warranty of
merchantability or fitness for a particular purpose.
*/
/* This file defines the syntax of PL/M. */
#include <ctype.h>
#include <string.h>
#include "plm-manifest.h"
#include "plm-parse.h"
#include "scope.h"
int lineno = 1;
/* forward references */
char * canonical_string (char *);
char * canonical_identifier (char *);
static void error (char *);
%}
DIGIT_STRING [0-9][0-9$]*
A [Aa]($)*
B [Bb]($)*
C [Cc]($)*
D [Dd]($)*
E [Ee]($)*
F [Ff]($)*
G [Gg]($)*
H [Hh]($)*
I [Ii]($)*
L [Ll]($)*
M [Mm]($)*
N [Nn]($)*
O [Oo]($)*
P [Pp]($)*
Q [Qq]($)*
R [Rr]($)*
S [Ss]($)*
T [Tt]($)*
U [Uu]($)*
W [Ww]($)*
X [Xx]($)*
Y [Yy]($)*
%%
{A}{D}{D}{R}{E}{S}{S} return ADDRESS;
{A}{N}{D} return AND;
{A}{T} return AT;
{B}{A}{S}{E}{D} return BASED;
{B}{Y} return BY;
{B}{Y}{T}{E} return BYTE;
{C}{A}{L}{L} return CALL;
{C}{A}{S}{E} return CASE;
{C}{A}{U}{S}{E}{I}{N}{T}{E}{R}{R}{U}{P}{T} return CAUSE_INTERRUPT;
{C}{H}{A}{R}{I}{N}{T} return CHARINT;
{D}{A}{T}{A} return DATA;
{D}{E}{C}{L}{A}{R}{E} return DECLARE;
{D}{I}{S}{A}{B}{L}{E} return DISABLE;
{D}{O} return DO;
{D}{W}{O}{R}{D} return DWORD;
{E}{L}{S}{E} return ELSE;
{E}{N}{A}{B}{L}{E} return ENABLE;
{E}{N}{D} return END;
{E}{O}{F} return EOF_KW;
{E}{X}{T}{E}{R}{N}{A}{L} return EXTERNAL;
{G}{O} return GO;
{G}{O}{T}{O} return GOTO;
{H}{A}{L}{T} return HALT;
{H}{W}{O}{R}{D} return HWORD;
{I}{F} return IF;
{I}{N}{I}{T}{I}{A}{L} return INITIAL_KW;
{I}{N}{T}{E}{G}{E}{R} return INTEGER;
{I}{N}{T}{E}{R}{R}{U}{P}{T} return INTERRUPT;
{L}{A}{B}{E}{L} return LABEL;
{L}{I}{T}{E}{R}{A}{L}{L}{Y} return LITERALLY;
{L}{O}{N}{G}{I}{N}{T} return LONGINT;
{M}{I}{N}{U}{S} return MINUS;
{M}{O}{D} return MOD;
{N}{O}{T} return NOT;
{O}{F}{F}{S}{E}{T} return OFFSET;
{O}{R} return OR;
{P}{L}{U}{S} return PLUS;
{P}{O}{I}{N}{T}{E}{R} return POINTER;
{P}{R}{O}{C}{E}{D}{U}{R}{E} return PROCEDURE;
{P}{U}{B}{L}{I}{C} return PUBLIC;
{Q}{W}{O}{R}{D} return QWORD;
{R}{E}{A}{L} return REAL;
{R}{E}{E}{N}{T}{R}{A}{N}{T} return REENTRANT;
{R}{E}{T}{U}{R}{N} return RETURN;
{S}{E}{L}{E}{C}{T}{O}{R} return SELECTOR;
{S}{H}{O}{R}{T}{I}{N}{T} return SHORTINT;
{S}{T}{R}{U}{C}{T}{U}{R}{E} return STRUCTURE;
{T}{H}{E}{N} return THEN;
{T}{O} return TO;
{W}{H}{I}{L}{E} return WHILE;
{W}{O}{R}{D} return WORD;
{X}{O}{R} return XOR;
[_A-Za-z][_$0-9A-Za-z]* {
char * string;
int i;
yylval = canonical_identifier(yytext);
string = lookup_literal(yylval);
if (!string)
{
return IDENTIFIER;
}
free(yylval);
yylval=0; /*excessive neatness*/
/* push the string back onto the input
stream - it is necessary to push
from right to left */
for (i = strlen (string);
i >= 0;
i--)
{
/* very weak - depends on lexical
generator allowing sufficient
push-back */
unput (string[i]);
}
}
[0-9][0-9$]*(d)? return DECIMAL_NUMBER;
{DIGIT_STRING}\.({DIGIT_STRING})?([E|e][+|-]?{DIGIT_STRING})? return FLOATING_POINT_NUMBER;
[01][01$]*[bB] return BINARY_NUMBER;
[0-9][0-9a-fA-F$]*[hH] return HEX_NUMBER;
[0-7][0-7$]*[OoQq] return OCTAL_NUMBER;
'([^'\n\201]|(''))+' {
yylval = canonical_string(yytext);
return STRING;
}
:= return ASSIGN_OP;
[\@] return AT_SIGN;
: return COLON;
, return COMMA;
[\.] return DOT;
= return EQ;
>= return GE;
> return GT;
"<=" return LE;
\( return LPAREN;
"<" return LT;
- return MINUS_SIGN;
"<>" return NE;
"+" return PLUS_SIGN;
\) return RPAREN;
; return SEMI;
"/" return SLASH;
\* return STAR;
\f
\n lineno++;
[\t ]*
"/*" {
register int c;
for ( ; ; )
{
while ( (c = input()) != '*' &&
c != EOF )
if (c == '\n') lineno++;
/* eat up text of comment */
if ( c == '*' )
{
while ( (c = input()) == '*' )
;
if ( c == '/' )
break; /* found the end */
}
if (c == '\n') lineno++;
if ( c == EOF )
{
error( "EOF in comment" );
break;
}
}
}
.
%%
static void error (char * x) {printf (x);}
/* Strip the single quotes from a pl/m string, and
compress any single quote pairs to one quote.
Allocates new storage for the string.
*/
char *
canonical_string (char * s)
{
int i, i_ret;
char * ret;
int len = strlen (s);
ret = malloc (len+1);
if (!ret)
return 0;
for (i = 1, i_ret = 0; i < (len-1); i++)
{
ret[i_ret++] = s[i];
if (s[i] == '\'')
{
i++;
}
}
ret[i_ret] = 0;
return ret;
}
/* Strip the dollar signs from a pl/m identifier or
numeric constant, and force all alphabetic characters
to lower case.
Allocates new storage for the identifier string.
*/
char *
canonical_identifier (char * s)
{
int i, i_ret;
char * ret;
int len = strlen (s);
ret = malloc (len+1);
if (!ret)
return 0;
for (i = 0, i_ret = 0; i < len; i++)
{
if (s[i] == '$')
{
continue;
}
ret[i_ret++] = tolower (s[i]);
}
ret[i_ret] = 0;
return ret;
}
#ifdef LEX_ONLY
main() {
for (;;)
yylex();
}
#endif

View File

@@ -0,0 +1,21 @@
/* manifest constants/types for PL/M lexer/parser.
$Id: plm-manifest.h,v 1.1 1994/02/28 20:54:26 hays Exp $
Copyright 1994 by Kirk Hays (hays@ichips.intel.com)
USE AT YOUR OWN RISK. NO WARRANTY EXPRESSED OR IMPLIED.
This code is distributed in the hope that it will be useful,
but without any warranty. Further, there is no implied warranty of
merchantability or fitness for a particular purpose.
*/
extern int lineno;
/* brute force type the value stack - this would not be appropriate in
a real compiler, but suits our purposes just fine */
typedef char * CHAR_PTR;
#define YYSTYPE CHAR_PTR

View File

@@ -0,0 +1,634 @@
/* YACC parser for PL/M syntax.
$Id: plm-parse.y,v 1.1 1994/02/28 20:54:56 hays Exp $
Copyright 1994 by Kirk Hays (hays@ichips.intel.com) and Gary Funck
(gary@intrepid.com)
USE AT YOUR OWN RISK. NO WARRANTY EXPRESSED OR IMPLIED.
This code is distributed in the hope that it will be useful,
but without any warranty. Further, there is no implied warranty of
merchantability or fitness for a particular purpose.
*/
/* This file defines the grammar of PL/M. */
%{
/*
* YACC grammar of PL/M
*/
#include <stdio.h>
#include <stdlib.h>
#include "plm-manifest.h"
#include "scope.h"
void yyerror ();
/* Cause the `yydebug' variable to be defined. */
#define YYDEBUG (1)
%}
%token ADDRESS AND ASSIGN_OP AT AT_SIGN BASED
%token BINARY_NUMBER BY BYTE CALL CASE
%token CAUSE_INTERRUPT CHARINT COLON COMMA DATA
%token DECIMAL_NUMBER DECLARE DISABLE DO DOT
%token DWORD ELSE ENABLE END EOF_KW EQ
%token EXTERNAL FLOATING_POINT_NUMBER GE GO
%token GOTO GT HALT HEX_NUMBER HWORD
%token IDENTIFIER
%token IF INITIAL_KW INTEGER INTERRUPT
%token LABEL LE LITERALLY LONGINT LPAREN LT
%token MINUS MINUS_SIGN MOD NE NOT
%token OCTAL_NUMBER OFFSET OR PLUS PLUS_SIGN
%token POINTER PROCEDURE PUBLIC QWORD
%token REAL REENTRANT RETURN RPAREN SELECTOR
%token SEMI SHORTINT SLASH STAR STRING
%token STRUCTURE THEN TO WHILE WORD XOR
%start compilation
%%
actual_parameters:
LPAREN expression_list RPAREN
;
adding_operator:
MINUS
| MINUS_SIGN
| PLUS
| PLUS_SIGN
;
and_operator:
AND
;
arithmetic_expression:
term
| arithmetic_expression adding_operator term
;
array_specifier:
explicit_dimension
| implicit_dimension
;
assignment_statement:
left_part EQ expression SEMI
;
base_specifier:
IDENTIFIER
| IDENTIFIER DOT IDENTIFIER
;
basic_statement:
assignment_statement
| call_statement
| goto_statement
| microprocessor_dependent_statement
| null_statement
| return_statement
;
basic_type:
ADDRESS
| BYTE
| CHARINT
| DWORD
| HWORD
| INTEGER
| LONGINT
| OFFSET
| POINTER
| QWORD
| REAL
| SELECTOR
| SHORTINT
| WORD
;
bound_expression:
expression
;
by_part:
BY step_expression
;
call_statement:
CALL simple_variable SEMI
| CALL simple_variable actual_parameters SEMI
;
cast_type:
basic_type
;
cause_interrupt_statement:
CAUSE_INTERRUPT LPAREN integer_constant RPAREN SEMI
;
compilation:
module
| module EOF_KW
;
conditional_clause:
if_condition true_unit
| if_condition true_element ELSE false_element
;
constant:
STRING
| numeric_constant
;
constant_attribute:
DATA
;
constant_list:
constant
| constant_list COMMA constant
;
declaration:
declare_statement
| procedure_definition
;
declaration_sequence:
declaration
| declaration_sequence declaration
;
declare_element:
factored_element
| unfactored_element
;
declare_element_list:
declare_element
| declare_element_list COMMA declare_element
;
declare_statement:
DECLARE declare_element_list SEMI
;
disable_statement:
DISABLE SEMI
;
do_block:
do_case_block
| do_while_block
| iterative_do_block
| simple_do_block
;
do_case_block:
do_case_statement ending
| do_case_statement unit_sequence ending
;
do_case_statement:
DO CASE expression SEMI {
push_scope();
}
;
do_while_block:
do_while_statement ending
| do_while_statement unit_sequence ending
;
do_while_statement:
DO WHILE expression SEMI {
push_scope();
}
;
embedded_assignment:
variable_reference ASSIGN_OP logical_expression
;
enable_statement:
ENABLE SEMI
;
end_statement:
END opt_identifier SEMI {
pop_scope();
}
;
ending:
end_statement
| label_definition_sequence end_statement
;
explicit_dimension:
LPAREN numeric_constant RPAREN
;
expression:
embedded_assignment
| logical_expression
;
expression_list:
expression
| expression_list COMMA expression
;
factored_element:
factored_label_element
| factored_variable_element
;
/*
* factored_label_element doesn't permit based variables,
* yet factored_variable_element does. This can't be disambiguated
* syntactically. Thus, the factored_label element will have to
* make the proper semantic checks to make the sure that the
* variable_name_specifier_list is in fact an identifier_list.
*/
factored_label_element:
LPAREN variable_name_specifier_list RPAREN LABEL opt_public_or_external
;
factored_member:
LPAREN member_name_list RPAREN opt_explicit_dimension variable_type
;
factored_variable_element:
LPAREN variable_name_specifier_list RPAREN opt_explicit_dimension variable_type opt_variable_attributes
;
false_element:
unit
;
formal_parameter:
IDENTIFIER
;
formal_parameter_list:
formal_parameter
| formal_parameter_list COMMA formal_parameter
;
formal_parameter_specifier:
LPAREN formal_parameter_list RPAREN
;
go_to:
GOTO
| GO TO
;
goto_statement:
go_to IDENTIFIER SEMI
;
halt_statement:
HALT SEMI
;
id_colon:
IDENTIFIER COLON
;
if_condition:
IF expression THEN
;
implicit_dimension:
LPAREN STAR RPAREN
;
index_part:
index_variable EQ start_expression
;
index_variable:
simple_variable
;
initial_value:
expression
;
initial_value_list:
initial_value
| initial_value_list COMMA initial_value
;
initialization:
DATA LPAREN initial_value_list RPAREN
| INITIAL_KW LPAREN initial_value_list RPAREN
;
integer_constant:
BINARY_NUMBER
| DECIMAL_NUMBER
| HEX_NUMBER
| OCTAL_NUMBER
;
interrupt:
INTERRUPT opt_interrupt_number
;
interrupt_number:
integer_constant
;
iterative_do_block:
iterative_do_statement ending
| iterative_do_statement unit_sequence ending
;
iterative_do_statement:
DO index_part to_part opt_by_part SEMI {
push_scope();
}
;
label_definition:
id_colon
;
label_definition_sequence:
label_definition
| label_definition_sequence label_definition
;
label_element:
IDENTIFIER LABEL opt_public_or_external
;
left_part:
variable_reference_list
;
literal_element:
IDENTIFIER LITERALLY STRING {
enter_literal ($1, $3);
}
;
location_reference:
AT_SIGN variable_reference
| AT_SIGN LPAREN constant_list RPAREN
| DOT variable_reference
| DOT LPAREN constant_list RPAREN
;
locator:
AT LPAREN expression RPAREN
;
locator_initialization:
locator
| initialization
| locator initialization
;
logical_expression:
logical_factor
| logical_expression or_operator logical_factor
;
logical_factor:
logical_secondary
| logical_factor and_operator logical_secondary
;
logical_primary:
arithmetic_expression
| arithmetic_expression relation_operator arithmetic_expression
;
logical_secondary:
logical_primary
| NOT logical_primary
;
member_element:
structure_type
| factored_member
| unfactored_member
;
member_element_list:
member_element
| member_element_list COMMA member_element
;
member_name:
IDENTIFIER
;
member_name_list:
member_name
| member_name_list COMMA member_name
;
member_specifier:
DOT member_name
| DOT member_name subscript
;
member_specifier_sequence:
member_specifier_sequence member_specifier
| member_specifier
;
microprocessor_dependent_statement:
cause_interrupt_statement
| disable_statement
| enable_statement
| halt_statement
;
module:
module_name COLON simple_do_block
;
module_name:
IDENTIFIER
;
multiplying_operator:
MOD
| SLASH
| STAR
;
null_statement:
SEMI
;
numeric_constant:
FLOATING_POINT_NUMBER
| integer_constant
;
opt_array_specifier:
/* empty */
| array_specifier
;
opt_by_part:
/* empty */
| by_part
;
opt_explicit_dimension:
/* empty */
| explicit_dimension
;
opt_formal_parameter_specifier:
/* empty */
| formal_parameter_specifier
;
opt_identifier:
/* empty */
| IDENTIFIER
;
opt_interrupt_number:
/* empty */
| interrupt_number
;
opt_procedure_attribute_sequence:
/* empty */
| procedure_attribute_sequence
;
opt_procedure_type:
/* empty */
| procedure_type
;
opt_public_or_external:
/* empty */
| EXTERNAL
| PUBLIC
;
opt_variable_attributes:
/* empty */
| variable_attributes
;
or_operator:
OR
| XOR
;
primary:
constant
| location_reference
| subexpression
| variable_reference
;
procedure_attribute:
EXTERNAL
| PUBLIC
| REENTRANT
| interrupt PUBLIC
| interrupt EXTERNAL
;
procedure_attribute_sequence:
procedure_attribute
| procedure_attribute_sequence procedure_attribute
;
procedure_definition:
procedure_statement ending
| procedure_statement declaration_sequence ending
| procedure_statement unit_sequence ending
| procedure_statement declaration_sequence unit_sequence ending
;
procedure_statement:
id_colon PROCEDURE opt_formal_parameter_specifier opt_procedure_type opt_procedure_attribute_sequence SEMI
{
push_scope();
}
;
procedure_type:
basic_type
;
relation_operator:
EQ
| GE
| GT
| LE
| LT
| NE
;
return_statement:
typed_return
| untyped_return
;
secondary:
primary
| unary_sign primary
;
simple_do_block:
simple_do_statement ending
| simple_do_statement unit_sequence ending
| simple_do_statement declaration_sequence ending
| simple_do_statement declaration_sequence unit_sequence ending
;
simple_do_statement:
DO SEMI {
push_scope();
}
;
simple_variable:
IDENTIFIER
| IDENTIFIER DOT IDENTIFIER
;
start_expression:
expression
;
step_expression:
expression
;
structure_type:
STRUCTURE LPAREN member_element_list RPAREN
;
subexpression:
LPAREN expression RPAREN
;
subscript:
LPAREN expression RPAREN
;
subscript_or_actual_parameters:
LPAREN expression_list RPAREN
;
term:
secondary
| term multiplying_operator secondary
;
to_part:
TO bound_expression
;
true_element:
true_statement
| label_definition_sequence true_statement
;
true_statement:
do_block
| basic_statement
;
true_unit:
unit
;
typed_return:
RETURN expression SEMI
;
unary_minus:
MINUS_SIGN
;
unary_plus:
PLUS_SIGN
;
unary_sign:
unary_minus
| unary_plus
;
unfactored_element:
label_element
| literal_element
| variable_element
;
unfactored_member:
member_name opt_explicit_dimension variable_type
;
unit:
unit_element
| label_definition_sequence unit_element
;
unit_element:
basic_statement
| conditional_clause
| do_block
;
unit_sequence:
unit
| unit_sequence unit
;
untyped_return:
RETURN SEMI
;
variable_attributes:
EXTERNAL constant_attribute
| EXTERNAL
| PUBLIC locator_initialization
| PUBLIC
| locator_initialization
;
variable_element:
variable_name_specifier opt_array_specifier variable_type opt_variable_attributes
;
variable_name_specifier:
IDENTIFIER
| IDENTIFIER BASED base_specifier
;
variable_name_specifier_list:
variable_name_specifier
| variable_name_specifier_list COMMA variable_name_specifier
;
/*
* Variable references may be either data references or function
* references. Syntactically, they appear to be the same, each
* is followed by a parenthesized comma separated list of expressions.
*
* A function reference, of course, cannot have the trailing list of
* member specifiers - semantic checking will catch this.
*/
variable_reference:
IDENTIFIER
| IDENTIFIER member_specifier_sequence
| cast_type subscript
| IDENTIFIER subscript_or_actual_parameters
| IDENTIFIER subscript_or_actual_parameters member_specifier_sequence
;
variable_reference_list:
variable_reference
| variable_reference_list COMMA variable_reference
;
variable_type:
basic_type
| structure_type
;
%%
void
yyerror(char * s)
{
fprintf (stderr, "error at line %d: %s\n", lineno, s);
}
main()
{
init_scope();
return yyparse();
}

View File

@@ -0,0 +1,151 @@
/* literal symbol table for PL/M.
$Id: scope.c,v 1.1 1994/02/28 20:55:56 hays Exp $
Copyright 1994 by Kirk Hays (hays@ichips.intel.com)
USE AT YOUR OWN RISK. NO WARRANTY EXPRESSED OR IMPLIED.
This code is distributed in the hope that it will be useful,
but without any warranty. Further, there is no implied warranty of
merchantability or fitness for a particular purpose.
This code implements a scoped symbol table. It depends on Paul
Vixie's PD AVL Tree code, distributed in comp.sources.unix, Volume 27,
Issue 34.
*/
#include <stdlib.h>
#include <stdio.h>
#include "tree.h"
#include "scope.h"
typedef struct lit_table_stack_t_elem {
struct lit_table_stack_t_elem *next;
tree * literal_table;
} lit_table_stack_t;
/* innermost scope for scope list */
static lit_table_stack_t *lit_table_stack;
typedef struct {
char * identifier;
char * string;
} literal_t;
/* static forward references */
static void new_scope (lit_table_stack_t *);
static int literal_compar (literal_t *, literal_t *);
static void literal_error (literal_t *);
static void literal_t_delete (literal_t *);
/* lookup an identifier in the scoped symbol table */
char *
lookup_literal (char * identifier)
{
literal_t * datum;
literal_t * node;
lit_table_stack_t * scope;
node = alloca (sizeof (literal_t));
node->identifier = identifier;
for (scope = lit_table_stack; scope; scope=scope->next)
{
datum = tree_srch(&(scope->literal_table), literal_compar, node);
if (datum)
{
return datum->string;
}
}
return 0;
}
/* enter an identifier in the current scoping level */
void
enter_literal (char * identifier, char * string)
{
literal_t * datum;
datum = malloc (sizeof (literal_t));
datum->identifier = identifier;
datum->string = string;
tree_add (&(lit_table_stack->literal_table),
literal_compar,
datum,
literal_error);
}
/* increase scope depth by one level - creates a new symbol table
for the current scope */
void
push_scope (void)
{
new_scope (lit_table_stack);
}
/* remove the innermost scope of the symbol table - releases all
allocated storage for that scope */
void
pop_scope (void)
{
lit_table_stack_t * p;
p = lit_table_stack;
lit_table_stack = lit_table_stack->next;
tree_mung (&(p->literal_table), literal_t_delete);
if (p->literal_table)
{
free(p->literal_table);
}
free(p);
}
/* initialize this module, creating the outermost scope */
void
init_scope (void)
{
new_scope (0);
}
/* work procedure to create a new scope */
static void
new_scope (lit_table_stack_t * next)
{
lit_table_stack = malloc (sizeof (lit_table_stack_t));
lit_table_stack->next = next;
tree_init (&(lit_table_stack->literal_table));
}
/* internal procedure to free storage when a symbol table entry is
deleted */
static
void literal_t_delete (literal_t * datum)
{
free (datum->string);
free (datum->identifier);
}
/* internal procedure to determine the match order for two symbol
table entries */
static int
literal_compar (literal_t * left, literal_t * right)
{
return strcmp (left->identifier, right->identifier);
}
/* assertion procedure to assure that duplicate literals are never
added at a single scoping level */
static void
literal_error (literal_t * in_error)
{
fprintf (stderr,
"literal table error - attempt to enter same identifier twice\n");
exit (255);
}

View File

@@ -0,0 +1,22 @@
/* public interfaces for literal symbol table for PL/M.
$Id: scope.h,v 1.1 1994/02/28 20:56:13 hays Exp $
Copyright 1994 by Kirk Hays (hays@ichips.intel.com)
USE AT YOUR OWN RISK. NO WARRANTY EXPRESSED OR IMPLIED.
This code is distributed in the hope that it will be useful,
but without any warranty. Further, there is no implied warranty of
merchantability or fitness for a particular purpose.
This code implements a scoped symbol table. It depends on Paul
Vixie's PD AVL Tree code, distributed in comp.sources.unix, Volume 27,
Issue 34.
*/
char * lookup_literal (char *);
void enter_literal (char *, char *);
void push_scope (void);
void pop_scope (void);
void init_scope (void);

View File

@@ -0,0 +1,108 @@
Some notes about the PL/M to C converter:
With case conversion enabled by the "ifdef" in main.c, all upper case
characters in an identifier are converted to lower case, and all lower case
characters are converted to upper case except for identifiers declared
LITERALLY, in which case the identifier is not case converted.
Dollar signs used in identifiers are discarded.
The use of the AND, OR and NOT operators are converted to &&, ||, and !
operators respectively. This should work, but conversion to &, |, and ~
may be desirable in many cases. There is no clear way to distinguish which
conversion to use, thus the previous conversions were chosen. A #define
in tokens.h allows either convention to be chosen. A more intelligent
expression parser could do a better job of determining use of these operators.
Labels are limited in scope to that defined in C. That is, use of labels is
limited to the current function. PL/M allows external labels.
The dot operator is treated the same as the @ operator (converted to a &
reference).
Constant lists of the form:
@('string', 0)
are converted to:
"string"
Constant lists of the form:
@('string')
are converted to:
's', 't', 'r', 'i', 'n', 'g'
BYTE strings of the form:
'string'
are converted to:
's', 't', 'r', 'i', 'n', 'g'
ADDRESSes and SELECTORs are not supported.
Variables declared AT in one module and EXTERNAL in another will produce
incorrect results, as the EXTERNAL declared variable will not be treated
as a pointer. For example, in module A:
PL/M code: C code:
--------------------------------- ----------------------------------
DECLARE MEMVAR BYTE AT(8000H); BYTE *memvar = (BYTE *) 0x8000;
MEMVAR = 14H; (*memvar) = 0x14;
And in module B:
PL/M code: C code:
--------------------------------- ----------------------------------
DECLARE MEMVAR BYTE EXTERNAL; BYTE memvar;
MEMVAR = 14H; memvar = 0x14;
To avoid this problem, list each AT variable used on a single line in a file
called "at_decl.cvt".
Variable declarations within a procedure with the PUBLIC attribute *probably*
should be placed prior to the procedure definition. Currently, the PUBLIC
attribute is ignored.
Variable declarations of type POINTER are treated as type void.
BASED variables are treated as a pointer to the based variable.
For example, for the following declarations, the associated C code is
generated:
PL/M code: C code:
--------------------------------- ----------------------------------
DECLARE I BYTE; BYTE i;
DECLARE ITEM_PTR POINTER; void *item_ptr;
DECLARE ITEM BASED ITEM_PTR BYTE; BYTE **item = (BYTE **) &item_ptr;
ITEM_PTR = @I; item_ptr = &i;
ITEM = 77H; (**item) = 0x77;
Care should be taken in the use of LITERALLY declared variables. Such
declarations are converted to a #define directive. With the cvt.h flag
PARSE_LITERALS defined, the converter attempts to parse the contents of
all LITERALLY declared variables as the definition for the #define
directive. With PARSE_LITERALS undefined, no parsing takes place. Thus,
for the declaration:
DECLARE MAX_COUNT LITERALLY '55H';
the code generated with PARSE_LITERALS defined is:
#define MAX_COUNT 0x55
and the code generated with PARSE_LITERALS undefined is:
#define MAX_COUNT 55H
Control directives within comments are ignored.
The procedure attribute REENTRANT is ignored. Technically, all PL/M variables
are static and could be declared as such in all but REENTRANT procedures.
This was not done, as it was deemed improbable that any problems would result.
The user should keep this fact in mind though. Especially in cases where the
C compiler warns about using a variable before it has been defined.
In most cases, white space (spaces, tabs, returns, line-feeds and comments)
are retained in their appropriate place. In obscure instances, white space
may be discarded for the sake of simpler code. For example, white space in
some portions of a DECLARE statement is discarded, since the structure of
a DECLARE statement is drastically converted.
Array subscripts and function calls appear to be ambiguous. The converter
keeps a symbol table of DECLARATIONS to try to correctly distinguish one from
the other.

View File

@@ -0,0 +1,31 @@
README
CAVEATS.DOC
FILES
at_decl.cvt
const.c
context.c
control.c
convert.c
cvt.h
cvt_id.h
decl_out.c
declare.c
defs.h
error.c
io.c
lit.c
main.c
makefile
makefile.ibm
mem.c
misc.h
parse.c
struct.h
test.c.out
test.plm
tkn_defs.h
tkn_ext.h
token.c
tokens.h
typedefs.c
version.c

View File

@@ -0,0 +1,37 @@
This is a PL/M to C converter. It will take most PL/M code and do a nice
job of converting it to C. It tries to be intelligent about leaving formatting
and comments intact. This version supports PL/M-286. It is something I wrote
about a year ago to convert several meg of source code, and it did a 99.5%
conversion. I was later handed some source code that it crashed on, and I
extended it to support that code too.
Please keep in mind that this may well not work for your code. It has
been tested only on a few sets of code, each following its own set of coding
standards. Also, don't expect a lot of support from me, as my interest in
PL/M is next to none. I no longer work for the employer for whom I wrote
this converter, but they have given me permission to own and post the sources.
I will, time permitting, collect bug fixes and post patches to the software.
Please mail fixes directly to me, as I may miss any posting of them. If
anyone is interested in taking over maintenance of this code, please let me
know!
The source code compiles under Unix. I've compiled it on a Sun-4, a VAX
running Ultrix, and a VAX running Mt. Xinu. At one time I had a version that
ran under MSDOS, but I can't guarantee it will now. I've included a makefile
for use with Turbo-C. You need to define IBMPC to compile it. What it could
really use is tuning for a large memory model, as in it's present state, it
can only handle small source files. It could also benefit from a good man
page.
The converter expects source code to be in "proper" format (i.e. proper
use of EXTERNAL declarations, and following of the Intel PL/M grammar as the
converter knows it.) It has some moderate error-recovery, but may well dump
core if it expects one thing and gets another.
I've included a garbage file test.plm; typeing "plm2c test.plm" should
result in a test.c file that is identical to the provided test.c.out.
See the file CAVEATS.DOC for compatibility issues.
Hope you find it useful!
Robert Ankeney
April 9, 1991
...!tektronix!bob@reed.bitnet

View File

@@ -0,0 +1,27 @@
foop(i, j)
short i, j;
{
}
float foo()
{
}
WORD bletch;
void *ptr;
farp("Hi\014\037\253\036");
farp(&foo, &bar, &bletch);
bletch = foo + foop(1, 2);
bletch = foo + foop;
ptr = (void *) &foo;
ptr = (void *) &bar;
ptr = (void *) &bletch;
foo();
bar();
(*ptr)();
(*bletch)();
(*ptr)(1, 2);

View File

@@ -0,0 +1,154 @@
#include "misc.h"
#include "defs.h"
#include "cvt.h"
#include "struct.h"
/*
* Pointer to the current context
*/
CONTEXT *context_head;
/*
* Pointer to all popped contexts
*/
CONTEXT *old_context;
/*
* Search DECL_MEMBER list for symbol and if found, return TRUE
* and pointer to DECL_ID for that symbol.
*/
find_member_symbol(symbol, decl_ptr, decl_id)
TOKEN *symbol;
DECL_MEMBER *decl_ptr;
DECL_ID **decl_id;
{
DECL_ID *var_ptr;
for (var_ptr = decl_ptr->name_list; var_ptr;
var_ptr = var_ptr->next_var) {
if (!strcmp(var_ptr->name->token_name, symbol->token_name)) {
*decl_id = var_ptr;
return TRUE;
}
}
*decl_id = NULL;
return FALSE;
}
/*
* Search DECL_MEMBER list for symbol.
* If found, return pointer to DECL_MEMBER containing that symbol
* in decl_found, and return TRUE.
* If not found, return null pointer in decl_found, and return FALSE.
*/
find_list_symbol(symbol, decl_ptr, decl_found, decl_id)
TOKEN *symbol;
DECL_MEMBER *decl_ptr, **decl_found;
DECL_ID **decl_id;
{
for (*decl_found = decl_ptr; *decl_found;
*decl_found = (*decl_found)->next_member) {
if (find_member_symbol(symbol, *decl_found, decl_id))
return TRUE;
}
return FALSE;
}
/*
* Search context for symbol.
* If found, return pointer to DECL_MEMBER containing that symbol
* in decl_found, return DECL_ID for that symbol in decl_id, and
* return TRUE.
* If not found, return null pointers in decl_found and decl_id,
* and return FALSE.
*/
find_symbol(symbol, decl_found, decl_id)
TOKEN *symbol;
DECL_MEMBER **decl_found;
DECL_ID **decl_id;
{
CONTEXT *context_ptr;
for (context_ptr = context_head; context_ptr;
context_ptr = context_ptr->next_context) {
if (find_list_symbol(symbol, context_ptr->decl_head,
decl_found, decl_id))
return TRUE;
}
return FALSE;
}
/*
* Add a declaration to current context
*/
add_to_context(decl)
DECL_MEMBER *decl;
{
DECL_MEMBER *decl_ptr;
/* Find end of declaration list */
for (decl_ptr = decl; decl_ptr->next_member; )
decl_ptr = decl_ptr->next_member;
/* Add current declarations to tail of new list */
decl_ptr->next_member = context_head->decl_head;
context_head->decl_head = decl;
}
/*
* Add a DECL list to context and NULL the list pointer
*/
add_decl_to_context(decl)
DECL *decl;
{
DECL *decl_ptr;
/* Find end of declaration list */
for (decl_ptr = decl; decl_ptr; decl_ptr = decl_ptr->next_decl) {
if (decl_ptr->decl_list)
add_to_context(decl_ptr->decl_list);
decl_ptr->decl_list = NULL;
}
}
/*
* Push a new context of specified type and name
*/
new_context(type, name)
int type;
TOKEN *name;
{
CONTEXT *new_context;
get_context_ptr(&new_context);
new_context->context_type = type;
if (name) {
get_token_ptr(&new_context->context_name);
token_copy(name, new_context->context_name);
} else
new_context->context_name = NULL;
new_context->next_context = context_head;
context_head = new_context;
}
/*
* Pop current context and place on old context
*/
pop_context()
{
CONTEXT *popped_context;
popped_context = context_head;
context_head = popped_context->next_context;
popped_context->next_context = old_context;
old_context = popped_context;
}
/*
* Initializes context pointers
*/
init_context()
{
context_head = NULL;
old_context = NULL;
}

View File

@@ -0,0 +1,89 @@
#include "misc.h"
#include "defs.h"
#include "cvt.h"
#include "struct.h"
#include "tokens.h"
#include "tkn_ext.h"
extern char *text_buffer;
extern char *text_ptr;
/*
* Parse a control directive.
* Handles: Abbreviation:
* $INCLUDE $IC
* $SET
* $RESET
* $IF
* $ELSE
* $ELSEIF
* $ENDIF
*/
parse_control()
{
TOKEN ctl_token, token;
int token_class;
RESERVED_WORD *word_ptr;
char include_file[128], *include_ptr;
token_class = get_token(&ctl_token);
if (token_class != IDENTIFIER) {
control_error("Invalid directive");
return;
}
for (word_ptr = &control_directives[0]; word_ptr->token != END_OF_FILE;
word_ptr++) {
if ((strlen(word_ptr->name) == ctl_token.token_length) &&
!strncmp(word_ptr->name, ctl_token.token_start,
ctl_token.token_length)) {
switch (word_ptr->token) {
case C_INCLUDE :
token_class = get_token(&token);
if (token_class != LEFT_PAREN) {
control_error("'(' expected");
return;
}
/* Copy and send file name (up to ')') */
include_ptr = include_file;
while (*text_ptr != ')') {
if ((*text_ptr >= 'A') && (*text_ptr <= 'Z'))
/* Convert to lower case */
*include_ptr++ = *text_ptr++ + ' ';
else
*include_ptr++ = *text_ptr++;
}
*include_ptr++ = '\0';
/* Skip ')' */
text_ptr++;
/* Parse include file */
cvt_file(include_file);
/* Convert .plm to .c */
if (strcmp(include_ptr - 5, "plm")) {
(void) strcpy(include_ptr - 5, ".c");
include_ptr -= 2;
}
out_to_start();
out_str("#include");
out_must_white(&token);
out_char('"');
out_str(include_file);
out_char('"');
return;
default :
control_error("Non-supported directive");
return;
}
}
}
control_error("Invalid directive");
}

View File

@@ -0,0 +1,145 @@
#include <stdio.h>
#ifdef IBMPC
#include <stdlib.h>
#endif
#include "misc.h"
#include "defs.h"
#include "cvt.h"
#include "struct.h"
#include "tokens.h"
BOOLEAN syntax_error;
extern char *text_buffer, *text_ptr;
extern int line_count;
/*
* Determine statement type and call appropriate parse routine.
* Return statement class or, if a reserved word, reserved word token.
*/
parse_statement(first_token)
TOKEN *first_token;
{
int token_type;
/* Flush standard output and standard error */
(void) fflush(stdout);
(void) fflush(stderr);
/* Flag no error yet */
syntax_error = FALSE;
switch (first_token->token_class) {
case RESERVED:
token_type = first_token->token_type;
switch (token_type) {
case DECLARE :
parse_declare(first_token);
break;
case DO :
parse_do(first_token);
break;
case IF :
parse_if(first_token);
break;
case THEN :
parse_then();
break;
case ELSE :
parse_else(first_token);
break;
case GOTO :
parse_goto(first_token);
break;
case GO :
parse_go(first_token);
break;
case CALL :
parse_call(first_token);
break;
case RETURN :
parse_return(first_token);
break;
case END :
parse_end(first_token);
break;
case DISABLE :
parse_int_ctl(first_token);
break;
case ENABLE :
parse_int_ctl(first_token);
break;
case OUTPUT :
parse_output(first_token);
break;
case OUTWORD :
parse_outword(first_token);
break;
case OUTHWORD :
parse_outhword(first_token);
break;
default :
parse_error("Illegal reserved word");
return ERROR;
}
return token_type;
case IDENTIFIER:
parse_identifier(first_token);
break;
case LABEL:
parse_label();
break;
case END_OF_LINE:
parse_eol(first_token);
break;
case END_OF_FILE:
out_white_space(first_token);
return END_OF_FILE;
default:
parse_error("Illegal statement");
return ERROR;
}
return first_token->token_class;
}
parse_new_statement()
{
TOKEN first_token;
/* Get first token on line */
(void) get_token(&first_token);
return parse_statement(&first_token);
}
parse_file()
{
while (parse_new_statement() != END_OF_FILE) ;
}

View File

@@ -0,0 +1,82 @@
/*
* Parse LITERALLY declared strings
*/
#define PARSE_LITERALS
/*
* Ignore Invalid control errors
*/
#define IGNORE_CONTROL_ERRORS
/*
* Convert lower case to upper and upper to lower in identifiers
*/
#define CONVERT_CASE
/*
* If CONVERT_TYPES defined, use the following type conversions.
*/
#define CONVERT_TYPES
/*
* Type conversions
*/
#define TYPE_BYTE "BYTE"
#define TYPE_WORD "WORD"
#define TYPE_DWORD "DWORD"
#define TYPE_INTEGER "short"
#define TYPE_REAL "float"
/*
* For initialized DATA, use this prefix.
* Probably should be "const" or "static".
*/
#define TYPE_DATA "const"
/*
* Default POINTER type.
*/
#define TYPE_POINTER "void"
/*
* Sizes of data types
*/
#define SIZE_BYTE 1
#define SIZE_WORD 2
#define SIZE_DWORD 4
/*
* Conversion operators
*/
#define AND_OP "&&"
#define OR_OP "||"
#define NOT_OP "!"
/*
#define AND_OP "&"
#define OR_OP "|"
#define NOT_OP "~"
*/
/*
#define AND_OP "AND"
#define OR_OP "OR"
#define NOT_OP "NOT"
*/
/*
* Function call equivalent to OUTPUT(port) = expr
* Becomes: FUNC_OUTPUT(port, expr)
*/
#define FUNC_OUTPUT "outportb"
/*
* Function call equivalent to OUTWORD(port) = expr
* Becomes: FUNC_OUTWORD(port, expr)
*/
#define FUNC_OUTWORD "outport"
/*
* Function call equivalent to OUTHWORD(port) = expr
* Becomes: FUNC_OUTHWORD(port, expr)
*/
#define FUNC_OUTHWORD "outporth"

View File

@@ -0,0 +1,40 @@
/*
* PL/M Cast function equivalents
*/
CVT_ID cast_functions[] = {
"float", TYPE_REAL,
"real", TYPE_REAL,
"fix", TYPE_INTEGER,
"int", TYPE_INTEGER,
"signed", TYPE_INTEGER,
"integer", TYPE_INTEGER,
"unsign", TYPE_WORD,
"word", TYPE_WORD,
"byte", TYPE_BYTE,
"dword", TYPE_DWORD,
"pointer", TYPE_POINTER,
"", ""
};
/*
* PL/M function equivalents
*/
CVT_ID cvt_functions[] = {
"size", "sizeof",
"abs", "fabs",
"iabs", "abs",
"input", "inportb",
"inword", "inport",
"setinterrupt", "signal",
"initrealmathunit", "_fpreset",
"", ""
};
/*
* PL/M identifier equivalents
*/
CVT_ID cvt_identifiers[] = {
"getrealerror", "_status87()",
"", ""
};

View File

@@ -0,0 +1,408 @@
#include "misc.h"
#include "defs.h"
#include "cvt.h"
#include "struct.h"
#include "tokens.h"
extern char *text_ptr;
extern int at_decl_count;
extern char at_decl_list[MAX_AT_DECLS][MAX_TOKEN_LENGTH];
/*
* Output *<name> if use_parens == NULL, else (*<name>).
*/
out_pointer(name, use_parens)
TOKEN *name;
BOOLEAN use_parens;
{
/* Use parentheses? */
if (use_parens) {
/* Yes - make it (*name) */
out_str("(*");
out_token_name(name);
out_char(')');
} else {
/* No - make it *name */
out_char('*');
out_token_name(name);
}
}
/*
* Output array bound (if any)
*/
out_bound(bound)
TOKEN *bound;
{
if (bound) {
out_char('[');
out_token(bound);
out_char(']');
}
}
/*
* Output a declaration type.
*/
out_decl_type(decl_ptr)
DECL_MEMBER *decl_ptr;
{
if (decl_ptr->type->token_type != STRUCTURE) {
out_type(decl_ptr->type->token_type);
} else {
out_struct(decl_ptr->struct_list);
}
}
/*
* Output structure contents.
*/
out_struct(el_ptr)
DECL_MEMBER *el_ptr;
{
DECL_ID *var_ptr;
out_str("struct {");
while (el_ptr) {
/* Use initial white space before type */
var_ptr = el_ptr->name_list;
if (var_ptr)
out_must_white(var_ptr->name);
out_decl_type(el_ptr);
out_char(' ');
while (var_ptr) {
out_token_name(var_ptr->name);
out_bound(el_ptr->array_bound);
var_ptr = var_ptr->next_var;
if (var_ptr) {
out_char(',');
out_must_white(var_ptr->name);
}
}
if ((el_ptr = el_ptr->next_member) != NULL)
out_char(';');
}
out_char('}');
}
/*
* Output C declaration list member.
*/
out_decl_member(decl_list, decl_token)
DECL_MEMBER *decl_list;
TOKEN *decl_token;
{
int i;
TOKEN token, tmp_token;
int token_class;
int name_count;
char count_str[8];
DECL_ID *var_ptr;
char *tmp_white_start, *tmp_white_end;
char *tmp_text_ptr;
BOOLEAN typedefed, is_at;
int string_len, string_size;
char *string_ptr;
/* Output characters up to CR */
out_pre_white(decl_token);
if (decl_list->type->token_type == LABEL)
/* Ignore label declarations */
return;
var_ptr = decl_list->name_list;
if (decl_list->type->token_type == LITERALLY) {
/* Make sure we're at start of new line */
out_pre_white(var_ptr->name);
out_to_start();
/* Convert to a #define */
out_str("#define ");
out_cvt_name(var_ptr->name);
out_char(' ');
out_str(decl_list->literal);
/*
out_str("\n");
*/
return;
}
var_ptr->name->white_space_start = decl_token->white_space_start;
var_ptr->name->white_space_end = decl_token->white_space_end;
/* Swap white space between type and first identifier */
/* and eat any new_lines prior to first identifier */
tmp_white_start = decl_list->type->white_space_start;
tmp_white_end = decl_list->type->white_space_end;
while ((tmp_white_start < tmp_white_end) && (*tmp_white_start < ' '))
tmp_white_start++;
decl_list->type->white_space_start = var_ptr->name->white_space_start;
var_ptr->name->white_space_start = tmp_white_start;
decl_list->type->white_space_end = var_ptr->name->white_space_end;
var_ptr->name->white_space_end = tmp_white_end;
out_white_space(decl_list->type);
if (decl_list->attributes == EXTERNAL) {
out_str("extern ");
/* Check if declared AT in another module */
for (i = 0; i < at_decl_count; i++)
if (!strcmp(var_ptr->name->token_name, at_decl_list[i]))
/* Yes - flag as so */
var_ptr->is_ext_at = TRUE;
} else
if (decl_list->initialization == DATA) {
out_str(TYPE_DATA);
out_char(' ');
}
is_at = (decl_list->at_ptr != NULL) || var_ptr->is_ext_at;
/* Determine if a structure with an AT attribute */
typedefed = (decl_list->type->token_type == STRUCTURE) && is_at;
/* Output type */
/* Is this a structure with an AT attribute? */
if (typedefed) {
/* Yes - output typedefed structure */
out_str("typedef ");
out_struct(decl_list->struct_list);
out_must_white(var_ptr->name);
#ifdef USE_DEFINES
out_char('_');
#endif
out_cvt_name(var_ptr->name);
if (decl_list->array_bound)
out_bound(decl_list->array_bound);
out_str(";\n");
out_white_space(decl_token);
#ifdef USE_DEFINES
out_char('_');
#endif
out_cvt_name(var_ptr->name);
} else
out_decl_type(decl_list);
/* Walk through name list */
name_count = 0;
while (var_ptr) {
if (is_at) {
/* AT (<expression>) -
OK... don't panic...
we can handle this
*/
/*
* Output:
* <type> *<ident> = (<type> *) <AT expr> + name_count
*
* NOTE: BASED variables are not dealt with.
*/
out_must_white(var_ptr->name);
/* Is this an array? */
if ((decl_list->array_bound) && !typedefed)
/* Yes - output ( *<ident> ) */
out_char('(');
out_char('*');
#ifdef USE_DEFINES
/* Output case converted name */
out_cvt_name(var_ptr->name);
#else
out_token_name(var_ptr->name);
#endif
if ((decl_list->array_bound) && !typedefed) {
out_char(')');
/* Output array bound (if any) */
out_bound(decl_list->array_bound);
}
if (decl_list->attributes != EXTERNAL) {
out_str(" = (");
/* Is this a structure? */
if (decl_list->type->token_type == STRUCTURE) {
/* Yes - output structure name prefix */
#ifdef USE_DEFINES
out_char('_');
#endif
out_cvt_name(decl_list->name_list->name);
} else
out_decl_type(decl_list);
out_str(" *) ");
out_str(decl_list->at_ptr);
if (name_count) {
(void) sprintf(count_str, " + %d", name_count);
out_str(count_str);
}
}
} else {
/* Not an AT expression (whew!) */
out_must_white(var_ptr->name);
/* Is variable based? */
if (var_ptr->based_name) {
/* Yes - Output **name = */
/* (type **) &based_name */
if (decl_list->array_bound) {
/* Use (**name)[] */
out_str("(**");
out_token_name(var_ptr->name);
out_str(")[]");
} else {
out_str("**");
out_token_name(var_ptr->name);
}
out_str(" = (");
out_decl_type(decl_list);
out_str(" **) &");
out_token_name(var_ptr->based_name);
} else
if (decl_list->type->token_type == POINTER) {
/* Yes - if based on an array */
/* output (*name) else output *name */
out_pointer(var_ptr->name,
(BOOLEAN) decl_list->array_bound);
} else {
/* Output variable name */
out_token_name(var_ptr->name);
/* Output array bound (if any) */
out_bound(decl_list->array_bound);
}
}
/* Get next name */
if ((var_ptr = var_ptr->next_var) != NULL) {
out_char(',');
name_count++;
}
}
/* Check for INITIAL or DATA initializers */
if (decl_list->initialization != NONE) {
out_str(" = ");
/* Point back to initializer string */
tmp_text_ptr = text_ptr;
text_ptr = decl_list->init_ptr;
if (decl_list->array_bound) {
out_char('{');
/* Array - determine if just a single string */
switch (decl_list->type->token_type) {
case BYTE :
string_size = SIZE_BYTE;
break;
case WORD :
string_size = SIZE_WORD;
break;
case DWORD :
string_size = SIZE_DWORD;
break;
case STRUCTURE :
/*
* Oh, SH-T!! fake it!
*/
string_size = SIZE_BYTE;
break;
default :
string_size = 0;
}
if (string_size && (get_token(&token) == STRING) &&
(get_token(&tmp_token) == RIGHT_PAREN)) {
/* Single string - break up into */
/* Pieces of sizeof(<type>) size */
string_ptr = token.token_name;
string_len = token.token_length;
while (string_len) {
out_str_const(string_ptr, string_size);
if (string_size > string_len)
string_size = string_len;
string_ptr += string_size;
if (string_len -= string_size)
out_char(',');
}
} else {
/* Point back to init string */
text_ptr = decl_list->init_ptr;
do {
token_class = parse_expression(&token);
if (token_class == COMMA)
out_token(&token);
} while (token_class == COMMA);
}
out_char('}');
/* Point past init string */
text_ptr = token.token_start + token.token_length + 2;
token_class = get_token(&token);
} else {
token_class = parse_expression(&token);
}
if (token_class != RIGHT_PAREN)
parse_error("')' expected");
text_ptr = tmp_text_ptr;
}
out_char(';');
#ifdef USE_DEFINES
/* Walk through name list and check for BASED variables */
var_ptr = decl_list->name_list;
while (var_ptr) {
/* See if variable is BASED */
if (var_ptr->based_name) {
/* Make sure we're at start of new line */
out_to_start();
out_str("#define");
out_must_token(var_ptr->based_name);
out_white_space(var_ptr->name);
out_str("(*");
out_token_name(var_ptr->name);
out_str(")\n");
}
/* See if variable is AT */
if (is_at) {
/* Make sure we're at start of new line */
out_to_start();
out_str("#define");
out_must_token(var_ptr->name);
out_white_space(var_ptr->name);
out_str("(*");
out_cvt_name(var_ptr->name);
out_str(")\n");
}
var_ptr = var_ptr->next_var;
}
#endif
}
out_decl(decl)
DECL *decl;
{
DECL_MEMBER *decl_list;
while (decl) {
for (decl_list = decl->decl_list; decl_list;
decl_list = decl_list->next_member)
out_decl_member(decl_list, decl->decl_token);
decl = decl->next_decl;
}
}

View File

@@ -0,0 +1,506 @@
#include "misc.h"
#include "defs.h"
#include "cvt.h"
#include "struct.h"
#include "tokens.h"
extern char *text_ptr;
extern char *out_string;
/*
* Routines to process DECLARE statements.
*/
/*
* Skip to closing right parenthesis
*/
find_right_paren()
{
TOKEN token;
int token_class;
int paren_count;
paren_count = 1;
do {
token_class = get_token(&token);
if (token_class == LEFT_PAREN)
paren_count++;
else
if (token_class == RIGHT_PAREN)
paren_count--;
} while (paren_count);
}
/*
* Copy an element from source to destination
*/
element_copy(src, dest)
DECL_MEMBER *src, *dest;
{
/* Don't copy name list */
dest->name_list = NULL;
/* Don't copy link */
dest->next_member = NULL;
dest->literal = src->literal;
dest->array_bound = src->array_bound;
dest->type = src->type;
dest->attributes = src->attributes;
dest->initialization = src->initialization;
dest->at_ptr = src->at_ptr;
dest->init_ptr = src->init_ptr;
if (src->struct_list)
element_copy(src->struct_list, dest->struct_list);
}
/*
* Generate a linked list of variables of the form:
* <id> [BASED <id>[.<id>]] or
* ( <id> [BASED <id>[.<id>]] [ ,<id> [BASED <id>[.<id>]] ] ... )
* Return token following variable list.
*/
get_var_list(list_ptr, sep_token)
DECL_ID **list_ptr;
TOKEN *sep_token;
{
DECL_ID *var_ptr, *last_var;
TOKEN *token;
int token_class;
BOOLEAN multi_list;
char *par_white_start, *par_white_end;
*list_ptr = NULL;
/* Get first token */
get_token_ptr(&token);
token_class = get_token(token);
/* Determine if <var> or list of ( <var> [,<var>] ... ) */
if (token_class == LEFT_PAREN) {
/* List of ( <var> [,<var>] ... ) */
multi_list = TRUE;
/* Use white space before '(' for first identifier */
par_white_start = token->white_space_start;
par_white_end = token->white_space_end;
/* Get first identifier */
token_class = get_token(token);
token->white_space_start = par_white_start;
token->white_space_end = par_white_end;
} else
/* <var> */
multi_list = FALSE;
/* Process identifier list */
last_var = NULL;
while (1) {
if (token_class != IDENTIFIER) {
parse_error("Identifier expected");
free_var_list(*list_ptr);
free((char *) token);
*list_ptr = NULL;
return ERROR;
}
/* Get a variable structure */
get_var_ptr(&var_ptr);
if (*list_ptr == NULL)
/* Point to first variable */
*list_ptr = var_ptr;
if (last_var)
last_var->next_var = var_ptr;
last_var = var_ptr;
/* Save variable name */
var_ptr->name = token;
/* Check for BASED */
token_class = get_token(sep_token);
if ((token_class == RESERVED) &&
(sep_token->token_type == BASED)) {
/* BASED <id>[ .<id> ] */
/* Get based name */
get_token_ptr(&token);
token_class = get_token(token);
if (token_class != IDENTIFIER) {
parse_error("Identifier expected");
free_var_list(*list_ptr);
free((char *) token);
*list_ptr = NULL;
return ERROR;
}
token_class = parse_simple_variable(token, sep_token);
#ifdef USE_DEFINES
/* Swap variable name with based name */
var_ptr->based_name = var_ptr->name;
var_ptr->name = token;
#else
var_ptr->based_name = token;
#endif
}
if (!multi_list)
return token_class;
if (token_class != COMMA)
break;
/* Get next variable */
get_token_ptr(&token);
token_class = get_token(token);
}
if (token_class == RIGHT_PAREN) {
/* Get next token */
token_class = get_token(sep_token);
return token_class;
} else {
parse_error("')' expected");
free_var_list(*list_ptr);
*list_ptr = NULL;
return ERROR;
}
}
/*
* Parse a structure declaration of the form:
* STRUCTURE ( <member> [ ,<member> ] ... )
* where:
* <member> ::= { <id> | ( <id> [ ,<id> ] ... ) } [ ( <numeric> ) ] <type>
*/
parse_structure(list_ptr)
DECL_MEMBER **list_ptr;
{
DECL_MEMBER *struct_ptr, *last_struct;
TOKEN token;
int token_class;
*list_ptr = NULL;
/* Get left paren */
token_class = get_token(&token);
if (token_class != LEFT_PAREN) {
parse_error("'(' expected");
return;
}
last_struct = NULL;
do {
/* Get a DECL_MEMBER structure */
get_element_ptr(&struct_ptr);
if (*list_ptr == NULL)
/* Point to first structure */
*list_ptr = struct_ptr;
if (last_struct)
last_struct->next_member = struct_ptr;
last_struct = struct_ptr;
/* Get variable list */
token_class = get_var_list(&struct_ptr->name_list, &token);
/* Get type and optional array designator */
get_token_ptr(&struct_ptr->type);
token_class = parse_type(struct_ptr, &token);
/* Get seperator */
token_class = get_token(&token);
} while (token_class == COMMA);
if (token_class != RIGHT_PAREN) {
parse_error("'(' expected");
free_decl_list(*list_ptr);
*list_ptr = NULL;
return;
}
}
/*
* Parse type and optional array designator.
* Passed initial token.
* Returns RESERVED if appropriate type found, else returns END_OF_LINE.
*/
parse_type(el_ptr, token)
DECL_MEMBER *el_ptr;
TOKEN *token;
{
TOKEN *temp_token;
int token_class;
token_class = token->token_class;
if (token_class == LEFT_PAREN) {
/* Array specifier */
/* Get numeric or '*' */
get_token_ptr(&temp_token);
token_class = get_token(temp_token);
if ((token_class == NUMERIC) ||
((token_class == OPERATOR) &&
(temp_token->token_type == TIMES))) {
if (token_class != NUMERIC)
/* array(*) specified - ignore '*' */
temp_token->token_name[0] = '\0';
/* Save array bound token */
el_ptr->array_bound = temp_token;
} else {
parse_error("Illegal array bound");
free((char *) temp_token);
return ERROR;
}
/* Get right paren */
token_class = get_token(token);
if (token_class != RIGHT_PAREN) {
parse_error("')' expected");
free((char *) temp_token);
return ERROR;
}
/* Get type */
token_class = get_token(token);
}
if ((token_class == RESERVED) && (token->token_type >= BYTE) &&
(token->token_type <= STRUCTURE)) {
/* Save type token */
token_copy(token, el_ptr->type);
if (token->token_type == STRUCTURE) {
/* Get structure list */
parse_structure(&el_ptr->struct_list);
}
return token_class;
} else {
parse_error("Illegal type");
return ERROR;
}
}
/*
* Parse a DECLARE element.
* Return token terminating DECLARE element.
*/
get_element(element, token)
DECL_MEMBER **element;
TOKEN *token;
{
DECL_MEMBER *el_ptr;
TOKEN temp_token, eof_token;
int token_class;
char *tmp_text_ptr;
char *tmp_out_string;
char *get_mem();
get_element_ptr(element);
/* Point to element */
el_ptr = *element;
/* Get name list */
token_class = get_var_list(&el_ptr->name_list, token);
/* Malloc space for type */
get_token_ptr(&el_ptr->type);
if (token_class == RESERVED)
switch (token->token_type) {
case LABEL :
/* LABEL declaration */
token_copy(token, el_ptr->type);
/* Check for PUBLIC or EXTERNAL */
token_class = get_token(token);
if ((token_class == RESERVED) &&
((token->token_type == PUBLIC) ||
(token->token_type == EXTERNAL)))
/* Indeed, who cares? */
token_class = get_token(token);
return token_class;
case LITERALLY :
token_copy(token, el_ptr->type);
/* Check for 'string' */
if (get_token(token) != STRING) {
parse_error("String expected");
free_decl_list(el_ptr);
return ERROR;
}
el_ptr->literal = get_mem(MAX_LITERAL_SIZE);
#ifdef PARSE_LITERALS
/* Parse literal string if only one token in string */
tmp_text_ptr = text_ptr;
text_ptr = token->token_name;
/* Parse token in string */
if (get_token(&temp_token) == END_OF_FILE)
el_ptr->literal[0] = '\0';
else
if (get_token(&eof_token) == END_OF_FILE) {
/* Single token literal */
(void) strcpy(el_ptr->literal, temp_token.token_name);
/* Save parsed token */
get_token_ptr(&el_ptr->literal_token);
token_copy(&temp_token, el_ptr->literal_token);
} else
(void) strcpy(el_ptr->literal, token->token_name);
text_ptr = tmp_text_ptr;
#else
/* Put string in literal */
(void) strcpy(el_ptr->literal, token->token_name);
#endif
/* Return following token */
token_class = get_token(token);
return token_class;
}
if (parse_type(el_ptr, token) != RESERVED) {
/* Error occurred */
free_decl_list(el_ptr);
return END_OF_LINE;
}
/* Process attribute information (if any) */
/* Check for EXTERNAL [ DATA ] */
token_class = get_token(token);
if (token_class != RESERVED)
return token_class;
if (token->token_type == EXTERNAL) {
el_ptr->attributes = EXTERNAL;
/* Check for DATA attribute */
token_class = get_token(token);
if (token_class == RESERVED) {
if (token->token_type == DATA) {
/*
* Ignore attribute
* el_ptr->initialization = DATA;
*/
token_class = get_token(token);
} else {
parse_error("Illegal attribute");
free_decl_list(el_ptr);
return ERROR;
}
}
return token_class;
} else
/* Check for PUBLIC */
if (token->token_type == PUBLIC) {
el_ptr->attributes = PUBLIC;
token_class = get_token(token);
}
if (token_class != RESERVED)
return token_class;
/* Check for AT ( <expr> ) */
if (token->token_type == AT) {
/* Check for '(' */
token_class = get_token(token);
if (token_class != LEFT_PAREN) {
parse_error("'(' expected");
free_decl_list(el_ptr);
return ERROR;
}
/* Generate a string for the AT expression */
el_ptr->at_ptr = get_mem(MAX_AT_EXPR_SIZE);
el_ptr->at_ptr[0] = '\0';
tmp_out_string = out_string;
out_string = el_ptr->at_ptr;
/* Parse the expression into at_ptr */
token_class = parse_expression(token);
if (token_class != RIGHT_PAREN) {
parse_error("')' expected");
free_decl_list(el_ptr);
return ERROR;
}
out_string = tmp_out_string;
token_class = get_token(token);
}
if (token_class != RESERVED)
return token_class;
/* Check for INITIAL or DATA ( <expr> ) */
if ((token->token_type == INITIAL) ||
(token->token_type == DATA)) {
el_ptr->initialization = token->token_type;
/* Check for '(' */
token_class = get_token(token);
if (token_class != LEFT_PAREN) {
parse_error("'(' expected");
free_decl_list(el_ptr);
return ERROR;
}
el_ptr->init_ptr = text_ptr;
/* Skip to ')' */
find_right_paren();
token_class = get_token(token);
}
return token_class;
}
/*
* Parse a DECLARE list.
* Passed a pointer to a DECL, returns with DECL filled.
*/
get_decl_list(decl)
DECL *decl;
{
DECL_MEMBER *el_ptr, *decl_ptr;
TOKEN token;
int token_class;
decl->decl_list = NULL;
decl->next_decl = NULL;
decl_ptr = NULL;
do {
/* Get a declaration element */
token_class = get_element(&el_ptr, &token);
if (decl->decl_list == NULL)
decl->decl_list = el_ptr;
/* Link previous element */
if (decl_ptr)
decl_ptr->next_member = el_ptr;
decl_ptr = el_ptr;
} while (token_class == COMMA);
}
/*
* Parse a DECLARE statement.
*/
parse_declare(first_token)
TOKEN *first_token;
{
DECL decl;
decl.decl_token = first_token;
get_decl_list(&decl);
out_decl(&decl);
add_to_context(decl.decl_list);
}

View File

@@ -0,0 +1,24 @@
/*
* Maximum number of characters in a token
*/
#define MAX_TOKEN_LENGTH 512
/*
* Maximum number of characters in an individual DO CASE statement
*/
#define MAX_CASE_STATEMENT_SIZE 10240
/*
* Maximum number of characters in an AT expression
*/
#define MAX_AT_EXPR_SIZE 128
/*
* Maximum number of characters in a literal string
*/
#define MAX_LITERAL_SIZE 512
/*
* Maximum number of identifier names in at_decl.cvt
*/
#define MAX_AT_DECLS 64

View File

@@ -0,0 +1,116 @@
#include <stdio.h>
#include <string.h>
#include "misc.h"
#include "defs.h"
#include "cvt.h"
#include "struct.h"
#include "tokens.h"
#include "tkn_ext.h"
extern BOOLEAN syntax_error;
extern char *text_ptr;
extern int line_count;
extern char *line_ptr;
extern char current_file_name[];
/*
* parse_mesg() - Print given message, message type, and current
* line number. Skip to error_eol.
*/
parse_mesg(error_string, error_type, error_eol)
char *error_string, *error_type;
char error_eol;
{
char *err_ptr;
int i, offset;
TOKEN token;
syntax_error = TRUE;
offset = text_ptr - line_ptr - 1;
/* Find end of line */
for (err_ptr = line_ptr; (*err_ptr != '\0') &&
(*err_ptr != LF); err_ptr++) ;
if (*error_string) {
(void) fprintf(stderr, "\n%s - Parse %s: %s.\nOccurred at line %d near:\n",
current_file_name, error_type, error_string, line_count);
/* Print offending line */
(void) fwrite(line_ptr, err_ptr - line_ptr + 1, 1, stderr);
for (i = 0; i < offset; i++)
if (line_ptr[i] < ' ')
(void) fputc(line_ptr[i], stderr);
else
(void) fputc(' ', stderr);
(void) fputc('^', stderr);
if (*err_ptr == '\0')
(void) fputc(LF, stderr);
}
if (*err_ptr != '\0')
err_ptr++;
/* Skip to end-of-line */
if (error_eol == '\0')
return;
else
if (error_eol == LF) {
text_ptr = err_ptr;
line_ptr = err_ptr;
line_count++;
} else {
if (*(text_ptr - 1) != ';') {
do {
i = get_token(&token);
} while ((i != END_OF_FILE) && (i != END_OF_LINE));
}
/* Point at end of line */
text_ptr--;
}
}
/*
* parse_error() - Print given error message and current line number.
* Called when an unrecognised or unprocessable token
* appears.
*/
parse_error(error_string)
char *error_string;
{
if (syntax_error)
/* Already had an error on this line */
return;
parse_mesg(error_string, "error", END_OF_LINE);
}
/*
* Do a parse_error(), but move to END_OF_LINE, not ';'
*/
control_error(error_string)
char *error_string;
{
#ifdef IGNORE_CONTROL_ERRORS
parse_mesg("", "", LF);
#else
parse_mesg(error_string, "error", LF);
#endif
}
/*
* parse_warning - Generate a warning message
*/
parse_warning(warning_string)
char *warning_string;
{
parse_mesg(warning_string, "warning", '\0');
}

View File

@@ -0,0 +1,354 @@
#include <stdio.h>
#ifdef IBMPC
#include <stdlib.h>
#endif
#include "misc.h"
#include "defs.h"
#include "cvt.h"
#include "struct.h"
#include "tokens.h"
char *out_string;
char last_out_ch;
char *str_shifts[] = { "0", "8", "16", "24" };
extern char *text_buffer, *text_ptr;
extern int line_count;
extern int file_depth;
extern FILE *ofd;
extern BOOLEAN parsing_literal;
extern TOKEN literal_token;
/*
* Output data of specified length.
* If out_string is not NULL, append string to out_string.
* Otherwise write string to stdout.
*/
out_data(string, length)
char *string;
int length;
{
if (length) {
if (out_string)
(void) strncat(out_string, string, length);
else
if (file_depth == 1)
#ifdef DEBUG
(void) fwrite(string, length, 1, stdout);
#else
(void) fwrite(string, length, 1, ofd);
#endif
else
return;
/* Save last character output */
last_out_ch = *(string + length - 1);
}
}
/*
* Print white space
*/
out_white_space(token)
TOKEN *token;
{
int length;
/* Compute length of white space */
length = token->white_space_end - token->white_space_start;
if (length)
out_data(token->white_space_start, length);
}
/*
* Print white space, if any. If start of white space string is not
* white, prefix with a space.
*/
out_must_white(token)
TOKEN *token;
{
if (!is_white(*(token->white_space_start)))
out_char(' ');
out_white_space(token);
}
/*
* Print all white space up first new-line (if any).
* Move white_space_start to point past first new-line.
*/
out_pre_line(token)
TOKEN *token;
{
while ((token->white_space_start < token->white_space_end) &&
(*token->white_space_start != '\n')) {
out_char(*token->white_space_start);
token->white_space_start++;
}
}
/*
* Print all white space up to but not including last new-line.
* Move white_space_start to point to last new-line.
*/
out_pre_white(token)
TOKEN *token;
{
char *ptr;
int length;
for (ptr = token->white_space_end;
(ptr > token->white_space_start) && (*(ptr - 1) != '\n') ; )
ptr--;
if (ptr == token->white_space_start)
return;
/* Compute length of white space */
length = ptr - token->white_space_start - 1;
if (length)
out_data(token->white_space_start, length);
token->white_space_start = ptr - 1;
}
/*
* Output token name
*/
out_token_name(token)
TOKEN *token;
{
if (is_a_type(token))
out_type(token->token_type);
else
out_data(token->token_name, strlen(token->token_name));
}
/*
* Output white space and token name
*/
out_token(token)
TOKEN *token;
{
out_white_space(token);
out_token_name(token);
}
/*
* Output guaranteed white space and token name
*/
out_must_token(token)
TOKEN *token;
{
out_must_white(token);
out_token_name(token);
}
/*
* Output case converted token name
*/
out_cvt_name(token)
TOKEN *token;
{
char *ptr;
for (ptr = token->token_name; *ptr; ptr++) {
if (is_a_lc_char(*ptr))
out_char(*ptr - 32);
else
if (is_a_uc_char(*ptr))
out_char(*ptr + 32);
else
out_char(*ptr);
}
}
/*
* Output string
*/
out_str(string)
char *string;
{
out_data(string, strlen(string));
}
/*
* Output character
*/
out_char(ch)
char ch;
{
out_data(&ch, 1);
}
/*
* Output new-line if not at start of line
*/
out_to_start()
{
if (last_out_ch != LF)
out_char(LF);
}
/*
* Output type
*/
out_type(type)
int type;
{
switch (type) {
case BYTE :
#ifdef CONVERT_TYPES
out_str(TYPE_BYTE);
#else
out_str("BYTE");
#endif
break;
case WORD :
#ifdef CONVERT_TYPES
out_str(TYPE_WORD);
#else
out_str("WORD");
#endif
break;
case DWORD :
#ifdef CONVERT_TYPES
out_str(TYPE_DWORD);
#else
out_str("DWORD");
#endif
break;
case INTEGER :
#ifdef CONVERT_TYPES
out_str(TYPE_INTEGER);
#else
out_str("INTEGER");
#endif
break;
case REAL :
#ifdef CONVERT_TYPES
out_str(TYPE_REAL);
#else
out_str("REAL");
#endif
break;
case POINTER :
out_str(TYPE_POINTER);
break;
default :
parse_error("Unknown type");
}
}
/*
* Initialize variables for I/O.
*/
out_init()
{
out_string = NULL;
last_out_ch = '\0';
parsing_literal = FALSE;
}
/*
* Output string constant of form 'WXYZ' in form:
* 'W' << 24 | 'X' << 16 | 'Y' << 8 | Z
* where len specifies the number of bytes in the string to output.
*/
out_str_const(str_ptr, len)
char *str_ptr;
int len;
{
while (len-- && *str_ptr) {
out_char('\'');
if (*str_ptr == '\'')
out_char('\\');
out_char(*str_ptr++);
out_char('\'');
if (len) {
out_str(" << ");
out_str(str_shifts[len]);
if (*str_ptr)
out_str(" | ");
}
}
}
/*
* Convert NUMERIC constant to octal constant
*/
cvt_octal(token, octal_string)
TOKEN *token;
char octal_string[];
{
int octal;
char ch, *ptr;
octal = 0;
octal_string[0] = '\\';
octal_string[4] = '\0';
ch = *(token->token_start + token->token_length - 1);
/* Determine base of numeric */
if (ch == 'H') {
/* Hex */
for (ptr = token->token_name + 2; *ptr; ptr++) {
octal *= 16;
if ((*ptr >= '0') && (*ptr <= '9'))
octal += *ptr - '0';
else
if ((*ptr >= 'A') && (*ptr <= 'Z'))
octal += *ptr - 'A' + 10;
else
if ((*ptr >= 'a') && (*ptr <= 'z'))
octal += *ptr - 'a' + 10;
else {
parse_error("Illegal hex character");
return;
}
}
} else
if ((ch == 'O') || (ch == 'Q')) {
/* Octal constant */
for (ptr = token->token_name + 1; *ptr; ptr++) {
octal *= 8;
if ((*ptr >= '0') && (*ptr <= '7'))
octal += *ptr - '0';
else {
parse_error("Illegal decimal character");
return;
}
}
} else {
/* Decimal constant */
for (ptr = token->token_name + 1; *ptr; ptr++) {
octal *= 10;
if ((*ptr >= '0') && (*ptr <= '9'))
octal += *ptr - '0';
else {
parse_error("Illegal decimal character");
return;
}
}
}
/* Generate octal constant */
octal_string[1] = ((octal >> 6) & 3) + '0';
octal_string[2] = ((octal >> 3) & 7) + '0';
octal_string[3] = (octal & 7) + '0';
}

View File

@@ -0,0 +1,168 @@
/*********************************************************************
*********************************************************************
** **
** **
** LITERALS **
** **
** **
** Revision History: SCO #23 (12/11/84) **
** SCO #31 (02/12/86) {SCO31.DOC} **
** SCO #33 (06/03/86) {SCO33.DOC} **
** SCO #34 (10/28/86) {SCO34.DOC} **
** SCO #36 (07/16/86) {SCO36.DOC} **
** SCO #48 (03/21/87) {SCO48.DOC} **
** **
*********************************************************************
*********************************************************************/
#define POWER_FAIL_SENSE_LATCH 0x0080
#define INTERRUPT_CONTROLLER_PORT_1 0x00C0
#define INTERRUPT_CONTROLLER_PORT_2 0x00C2
#define INSTRUCTION_WORD_1 0x13
#define INSTRUCTION_WORD_2 0x20
#define INSTRUCTION_WORD_3 0x01
#define END_OF_PARITY_INTERRUPT 0x60
#define END_OF_EXCEPTION_INTERRUPT 0x61
#define END_OF_REFRESH_INTERRUPT 0x62
#define END_OF_CYCLE_INTERRUPT 0x63
#define END_OF_SHORT_INTERRUPT 0x67
#define INTERRUPT_CONTROLLER_MASK_0 0x0F0
#define INTERRUPT_CONTROLLER_MASK_1 0x0FC
#define INTERRUPT_CONTROLLER_MASK_2 0x0F8
#define INTERRUPT_CONTROLLER_MASK_3 0x0F4
#define INTERVAL_TIMER_PORT_1 0x0D2
#define INTERVAL_TIMER_PORT_2 0x0D6
#define CONTROL_WORD 0x74
#define DATA_WORD_1 0x12
#define DATA_WORD_2 0x7A
#define CONTROL_WORD_87 0x033C
#define DPM_CONTROL_WORD_87 0x0F3C
#define BIT_CONTROL_WORD_87 0x0F3C
#define INTERFACE_1_START_CODE 0x01
#define INTERFACE_2_START_CODE 0x01
#define HCP_NORMAL 0x00
#define HCP_TEST_MODE 0x01
#define HCP_ADVANCE 0x02
#define HCP_RESET 0x03
#define HCP_ALTITUDE_HOLD_RESET 0x04
#define HCP_FAIL 0x07
#define IS =
#define VALID 0x55
#define NO_COMPUTED_DATA 0x66
#define FUNCTIONAL_TEST 0x99
#define TEST_MODE 0x0AA /*{SCO36.DOC}*/
#define FLIGHT_MODE 0x55 /*{SCO36.DOC}*/
#define POSITIVE_BIAS 0 /*{SCO31.DOC}*/
#define NEGATIVE_BIAS 1 /*{SCO31.DOC}*/
#define RESET 0x0AA
#define PASS 0x55
#define ON 0x55
#define TO_VOR 0x55
#define FROM_VOR 0x99
#define ILS 0x55 /*{SCO48.DOC}*/
#define VOR 0x0AA /*{SCO48.DOC}*/
#define INVALID 0x0AA
#define OFF 0x0AA
#define PUSHED 0x55
#define SET 0x55
#define FAIL 0x0AA
#define FAILED 0x0FF
#define VMC 4
#define IMC 5
#define CRZ 6
#define TOGA 7
#define BLANK 10
#define NEGATIVE_SIGN 11
#define ERROR_DISPLAY 0x5554
#define PFM_KEY_COUNTER 0x5555
#define PFM_TIMER 0x5556
#define COMPUTER_FAULT 0x5557
#define KEY1 5
#define KEY2 4
#define KEY3 3
#define KEY4 2
#define KEY5 1
#define KEY6 0
#define DISPLAY_GENERATOR_PORT 0x0C000
#define DISPLAY_GENERATOR_HALT_CODE 3
#define DISPLAY_GENERATOR_START_CODE 4
#define DISPLAY_HALT_ENABLE_CODE 0
#define DG_HALT 0x0005
#define LOAD_ROTATION_ANGLE 0x0007
#define LOAD_PRESENT_POSITION 0x0008
#define DRAW_VECTOR 0x0009
#define LOAD_BORDERS 0x000D
#define ZERO_DEGREE_ANGLE 0
#define NINETY_DEGREE_ANGLE 0x4000
#define NEG_NINETY_DEGREE_ANGLE 0x0C000
#define ONE_EIGHTY_DEGREE_ANGLE 0x8000
#define FIRST_HALF_OF_BUFFER 0
#define SECOND_HALF_OF_BUFFER 750
#define WINDOW_COMPARATOR_FAIL 0
#define WINDOW_COMPARATOR_PASS 7
#define TWENTY_CYCLES 20
#define FORTY_CYCLES 40
#define IOS1_CODE_CHECKSUM_ERROR 0x11 /*{SCO31.DOC}*/
#define IOS1_RAM_ERROR 0x12 /*{SCO31.DOC}*/
#define IOS1_80186_ERROR 0x13 /*{SCO31.DOC}*/
#define IOS1_8087_ERROR 0x14 /*{SCO31.DOC}*/
#define IOS1_CONVERTOR_ERROR 0x15 /*{SCO31.DOC}*/
#define IOS1_HUD_POWER_SUPPLY_ERROR 0x16 /*{SCO31.DOC}*/
#define IOS2_CODE_CHECKSUM_ERROR 0x21 /*{SCO31.DOC}*/
#define IOS2_RAM_ERROR 0x22 /*{SCO31.DOC}*/
#define IOS2_80186_ERROR 0x23 /*{SCO31.DOC}*/
#define IOS2_8087_ERROR 0x24 /*{SCO31.DOC}*/
#define IOS2_CONVERTOR_ERROR 0x25 /*{SCO31.DOC}*/
#define CLP_CODE_CHECKSUM_ERROR 0x31 /*{SCO31.DOC}*/
#define CLP_RAM_ERROR 0x32 /*{SCO31.DOC}*/
#define CLP_8086_ERROR 0x33 /*{SCO31.DOC}*/
#define CLP_8087_ERROR 0x34 /*{SCO31.DOC}*/
#define SM_CODE_CHECKSUM_ERROR 0x41 /*{SCO31.DOC}*/
#define SM_RAM_ERROR 0x42 /*{SCO31.DOC}*/
#define SM_8086_ERROR 0x43 /*{SCO31.DOC}*/
#define SM_8087_ERROR 0x44 /*{SCO31.DOC}*/
#define SYSTEM_MONITOR_INACTIVE 0x45 /*{SCO31.DOC}*/
#define DISPLAY_GENERATOR_ERROR 0x51 /*{SCO31.DOC}*/
#define SYMBOL_MISPOSITIONED_1 0x52 /*{SCO31.DOC}*/
#define OHU_VIDEO_FAIL 0x63 /*{SCO31.DOC}*/
#define OHU_HVPS_FAIL 0x64 /*{SCO31.DOC}*/
#define OHU_95_OR_30_VOLT_SUPPLY_FAIL 0x65 /*{SCO31.DOC}*/
#define SYMBOL_MISPOSITIONED_2 0x71 /*{SCO31.DOC}*/
#define WINDOW_COMPARATOR_ERROR 0x77 /*{SCO31.DOC}*/
#define DEU_VERTICAL_DEFLECTION_FAIL 0x7A /*{SCO31.DOC}*/
#define DEU_HORIZONTAL_DEFLECTION_FAIL 0x7B /*{SCO31.DOC}*/
#define DEU_DC_SUPPLY_FAIL 0x7C /*{SCO31.DOC}*/
#define DEU_BOOST_SUPPLY_FAIL 0x7D /*{SCO31.DOC}*/
#define DEU_DEFLECTION_SUPPLY_FAIL 0x7E /*{SCO31.DOC}*/
#define TEST_ERROR_DISPLAY 0x88
#define DISPLAY_GENERATOR_TEST 0x89
#define HCP_FAILURE 0x91 /*{SCO31.DOC}*/
#define RSU_FAILURE 0x0A1 /*{SCO34.DOC}*/
#define COMBINER_NOT_LOCKED 0x0B1 /*{SCO33.DOC}*/
#define EIGHTH_SECOND 3
#define ONE_SIXTH_SECOND 3
#define QUARTER_SECOND 5
#define ONE_THIRD_SECOND 6
#define HALF_SECOND 10
#define ONE_SECOND 20
#define ONE_POINT_FIVE_SECONDS 30
#define TWO_SECONDS 40
#define FIVE_SECONDS 100
#define HALF_PI 1.57079633F
#define PI 3.14159265F
#define TWO_PI 6.28318531F
#define TEN_KNOTS 16.9F
#define TEN_DEGREES 0.1745F
#define FIFTEEN_DEGREES 0.2618F
#define MAXIMUM_NUMBER 99999.9F
#define FOREVER while (1)

View File

@@ -0,0 +1,248 @@
#include <stdio.h>
#ifdef IBMPC
#include <stdlib.h>
#include <sys\stat.h>
#else
#include <sys/types.h>
#include <sys/stat.h>
#endif
#include <fcntl.h>
#include "misc.h"
#include "defs.h"
#include "cvt.h"
#include "struct.h"
#include "tokens.h"
#include "tkn_defs.h"
char *text_buffer, *text_ptr;
int line_count;
char *line_ptr;
char current_file_name[128];
char out_file_name[128];
int at_decl_count;
char at_decl_list[MAX_AT_DECLS][MAX_TOKEN_LENGTH];
FILE *ofd;
int file_depth;
FILE *fopen();
/*
* Get list of AT declaration variables for EXTERNAL declaration checks
*/
get_at_decl()
{
int i, fd;
char ch;
at_decl_count = 0;
if ((fd = open("at_decl.cvt", O_RDONLY)) == -1)
/* Not found */
return;
while (read(fd, &ch, 1) == 1) {
i = 0;
if (!is_a_char(ch)) {
fprintf(stderr, "Illegal identifier in line %d at_decl.cvt\n",
at_decl_count + 1);
exit(1);
}
do {
#ifdef CONVERT_CASE
if (is_a_uc_char(ch))
/* Convert to lower case */
ch += 32;
else
if (is_a_lc_char(ch))
/* Convert to upper case */
ch -= 32;
#endif
at_decl_list[at_decl_count][i++] = ch;
if (read(fd, &ch, 1) != 1) {
fprintf(stderr, "Unexpected EOF in at_decl.cvt\n");
exit(1);
}
} while ((ch != '\n') && (ch != ' '));
at_decl_list[at_decl_count++][i] = '\0';
}
}
/*
* Open specified file, init options, and parse.
*/
cvt_file(file_name)
char *file_name;
{
int fd, nr;
struct stat file_stat;
TOKEN token, fname_token, token_module, token_do;
int token_class;
char *tmp_text_buffer, *tmp_text_ptr, *tmp_line_ptr;
char *tmp_ptr;
int tmp_line_count;
char tmp_file_name[128];
char *get_mem();
/* Is this the first file? */
if (file_depth) {
/* No - save old text pointers */
tmp_text_buffer = text_buffer;
tmp_text_ptr = text_ptr;
tmp_line_ptr = line_ptr;
tmp_line_count = line_count;
(void) strcpy(tmp_file_name, current_file_name);
}
/* Save file name */
(void) strcpy(current_file_name, file_name);
/* Open file */
if ((fd = open(file_name, O_RDONLY)) == -1) {
(void) fprintf(stderr, "Cannot open input file %s", file_name);
perror("");
exit(1);
}
/* Get length */
if (fstat(fd, &file_stat)) {
perror("Cannot stat input file");
exit(1);
}
/* Allocate that much RAM */
text_buffer = get_mem((unsigned int) file_stat.st_size + 1);
/* Read file */
if ((nr = read(fd, text_buffer, (int) file_stat.st_size)) == -1) {
perror("Cannot read input file");
exit(1);
}
/* Insert End-of-file Mark */
text_buffer[nr] = '\0';
(void) close(fd);
/* Init pointers */
text_ptr = text_buffer;
line_ptr = text_ptr;
line_count = 1;
/* Init I/O */
out_init();
/* Start with initial context using file name */
(void) strcpy(fname_token.token_name, file_name);
fname_token.token_class = IDENTIFIER;
new_context(MODULE, &fname_token);
/* Is this the first file? */
if (file_depth++ == 0) {
/* Yes - open output file */
if ((ofd = fopen(out_file_name, "w")) == NULL) {
(void) fprintf(stderr, "Cannot create output file %s",
out_file_name);
exit(1);
}
/* Check for module name */
token_class = get_token(&token_module);
out_pre_white(&token_module);
tmp_ptr = token_module.token_start;
if ((token_class == IDENTIFIER) &&
/* Maybe got module name - Check for : */
(get_token(&token) == LABEL) &&
/* Check for DO; */
((get_token(&token_do) == RESERVED) &&
(token_do.token_type == DO)) &&
(get_token(&token) == END_OF_LINE)) {
/* Got module header */
out_pre_white(&token_do);
/* Parse to END [<module name>] */
parse_till_end(&token);
out_white_space(&token);
token_class = get_token(&token);
if (token_class == IDENTIFIER) {
out_pre_white(&token);
token_class = get_token(&token);
}
/* Should be at end of line */
if (token_class != END_OF_LINE) {
parse_error("';' expected");
}
/* Should be at end of file */
if (get_token(&token) != END_OF_FILE) {
parse_error("End of file expected");
}
out_white_space(&token);
} else {
out_pre_white(&token_do);
parse_warning("Module name expected");
text_ptr = tmp_ptr;
parse_file();
}
} else
parse_file();
free(text_buffer);
/* Was this the first file? */
if (--file_depth) {
/* No - restore old text pointers */
text_buffer = tmp_text_buffer;
text_ptr = tmp_text_ptr;
line_ptr = tmp_line_ptr;
line_count = tmp_line_count;
(void) strcpy(current_file_name, tmp_file_name);
} else
exit(0);
}
/*
* Open file and init options
*/
main(argc, argv)
int argc;
char *argv[];
{
int i;
char ch;
if (argc != 2) {
(void) fprintf(stderr, "usage: %s filename\n", argv[0]);
exit(1);
}
/* Search for a '.' in filename */
for (i = strlen(argv[1]) - 1; i; i--) {
ch = argv[1][i];
if ((ch == '.') || (ch == '/') || (ch == '\\'))
break;
}
if (ch != '.')
i = strlen(argv[1]);
/* Append a '.c' */
(void) strncpy(out_file_name, argv[1], i);
out_file_name[i] = '\0';
(void) strcat(out_file_name, ".c");
(void) printf("Output to: %s\n", out_file_name);
/* Get AT declaration list */
get_at_decl();
/* Init context */
init_context();
file_depth = 0;
/* Parse main file */
cvt_file(argv[1]);
}

View File

@@ -0,0 +1,83 @@
# Makefile for Unix
SRCS = convert.c \
parse.c \
declare.c \
decl_out.c \
control.c \
io.c \
token.c \
context.c \
mem.c \
error.c \
version.c \
main.c
OBJS = convert.o \
parse.o \
declare.o \
decl_out.o \
control.o \
io.o \
token.o \
context.o \
mem.o \
error.o \
version.o \
main.o
LNKS = convert parse declare decl_out control io token context mem error version main
TOKEN_HDRS = misc.h defs.h struct.h cvt.h cvt_id.h tokens.h
HDRS = $(TOKEN_HDRS) tkn_defs.h tkn_ext.h
OPTS = -c -O
plm2c: $(OBJS)
$(CC) -o plm2c $(OBJS)
convert.o: convert.c $(TOKEN_HDRS)
$(CC) $(OPTS) convert.c
parse.o: parse.c $(TOKEN_HDRS) cvt_id.h
$(CC) $(OPTS) parse.c
declare.o: declare.c $(TOKEN_HDRS)
$(CC) $(OPTS) declare.c
control.o: control.c $(TOKEN_HDRS) tkn_ext.h
$(CC) $(OPTS) control.c
decl_out.o: decl_out.c $(TOKEN_HDRS)
$(CC) $(OPTS) decl_out.c
io.o: io.c $(TOKEN_HDRS) tkn_ext.h
$(CC) $(OPTS) io.c
token.o: token.c $(TOKEN_HDRS) tkn_ext.h
$(CC) $(OPTS) token.c
context.o: context.c $(TOKEN_HDRS)
$(CC) $(OPTS) context.c
mem.o: mem.c $(TOKEN_HDRS)
$(CC) $(OPTS) mem.c
error.o: error.c $(TOKEN_HDRS)
$(CC) $(OPTS) error.c
version.o: version.c
$(CC) $(OPTS) version.c
main.o: main.c $(TOKEN_HDRS) tkn_defs.h
$(CC) $(OPTS) main.c
backup:
cp $(HDRS) Makefile bak
cp $(SRCS) bak
lint:
lint $(SRCS)
clean:
rm -f $(OBJS)

View File

@@ -0,0 +1,86 @@
# Makefile for IBM-PC MSDOS
SRCS = convert.c \
parse.c \
declare.c \
decl_out.c \
control.c \
io.c \
token.c \
context.c \
mem.c \
error.c \
version.c \
main.c
OBJS = convert.obj \
parse.obj \
declare.obj \
decl_out.obj \
control.obj \
io.obj \
token.obj \
context.obj \
mem.obj \
error.obj \
version.obj \
main.obj
LNKS = convert parse declare decl_out control io token context mem error version main
TOKEN_HDRS = misc.h defs.h struct.h cvt.h cvt_id.h tokens.h
HDRS = $(TOKEN_HDRS) tkn_defs.h tkn_ext.h
MDL = m
OPTS = -c -N -v -DIBMPC -m$(MDL)
plm2c: $(OBJS)
tlink /c /v c:\tc\lib\c0$(MDL) $(LNKS), plm2c, plm2c, c:\tc\lib\c$(MDL)
convert.obj: convert.c $(TOKEN_HDRS)
tcc $(OPTS) convert
parse.obj: parse.c $(TOKEN_HDRS) cvt_id.h
tcc $(OPTS) parse
declare.obj: declare.c $(TOKEN_HDRS)
tcc $(OPTS) declare
control.obj: control.c $(TOKEN_HDRS) tkn_ext.h
tcc $(OPTS) control
decl_out.obj: decl_out.c $(TOKEN_HDRS)
tcc $(OPTS) decl_out
io.obj: io.c $(TOKEN_HDRS) tkn_ext.h
tcc $(OPTS) io
token.obj: token.c $(TOKEN_HDRS) tkn_ext.h
tcc $(OPTS) token
context.obj: context.c $(TOKEN_HDRS)
tcc $(OPTS) context
mem.obj: mem.c $(TOKEN_HDRS)
tcc $(OPTS) mem
error.obj: error.c $(TOKEN_HDRS)
tcc $(OPTS) error
version.obj: version.c
tcc $(OPTS) version
main.obj: main.c $(TOKEN_HDRS) tkn_defs.h
tcc $(OPTS) main
backup:
cp $(HDRS) Makefile bak
cp $(SRCS) bak
floppy:
cp $(HDRS) makefile a:
cp $(SRCS) a:
lint:
lint $(SRCS)

View File

@@ -0,0 +1,196 @@
#ifdef IBMPC
#include <alloc.h>
#endif
#include "misc.h"
#include "defs.h"
#include "cvt.h"
#include "struct.h"
/*
* Memory allocation and deallocation routines.
*/
/*
* Allocate memory
*/
char *get_mem(size)
unsigned int size;
{
char *malloc_ptr;
void *malloc();
if ((malloc_ptr = (char *)malloc(size)) == NULL) {
parse_error("Out of memory");
exit(1);
}
return malloc_ptr;
}
/*
* Generate a new context.
*/
get_context_ptr(context)
CONTEXT **context;
{
*context = (CONTEXT *) get_mem(sizeof(CONTEXT));
(*context)->decl_head = NULL;
(*context)->next_context = NULL;
}
/*
* Malloc memory for a TOKEN.
*/
get_token_ptr(token)
TOKEN **token;
{
*token = (TOKEN *) get_mem(sizeof(TOKEN));
}
/*
* Malloc memory for a DECL_ID.
*/
get_var_ptr(var)
DECL_ID **var;
{
*var = (DECL_ID *) get_mem(sizeof(DECL_ID));
(*var)->name = NULL;
(*var)->based_name = NULL;
(*var)->next_var = NULL;
(*var)->is_ext_at = FALSE;
}
/*
* Free a linked list of variables.
*/
free_var_list(list_ptr)
DECL_ID *list_ptr;
{
DECL_ID *next_ptr;
while (list_ptr) {
if (list_ptr->name)
free( (char *) list_ptr->name);
if (list_ptr->based_name)
free( (char *) list_ptr->based_name);
next_ptr = list_ptr->next_var;
free((char *) list_ptr);
list_ptr = next_ptr;
}
}
/*
* Malloc space for a DECL_MEMBER structure and return pointer.
*/
get_element_ptr(element)
DECL_MEMBER **element;
{
DECL_MEMBER *el_ptr;
/* Malloc space for element */
el_ptr = (DECL_MEMBER *) get_mem(sizeof(DECL_MEMBER));
/* Init pointers */
el_ptr->name_list = NULL;
el_ptr->literal = NULL;
#ifdef PARSE_LITERALS
el_ptr->literal_token = NULL;
#endif
el_ptr->array_bound = NULL;
el_ptr->type = NULL;
el_ptr->struct_list = NULL;
el_ptr->at_ptr = NULL;
el_ptr->init_ptr = NULL;
el_ptr->next_member = NULL;
el_ptr->attributes = NONE;
el_ptr->initialization = NONE;
*element = el_ptr;
}
/*
* Free a DECL_MEMBER list.
*/
free_decl_list(element)
DECL_MEMBER *element;
{
DECL_MEMBER *el_ptr;
while (element) {
if (element->name_list)
free_var_list(element->name_list);
if (element->literal)
free((char *) element->literal);
if (element->array_bound)
free((char *) element->array_bound);
if (element->type)
free((char *) element->type);
if (element->struct_list)
free_decl_list(element->struct_list);
if (element->at_ptr)
free(element->at_ptr);
el_ptr = element->next_member;
free((char *) element);
element = el_ptr;
}
}
/*
* Malloc space for a procedure parameter
*/
get_param_ptr(param)
PARAM_LIST **param;
{
*param = (PARAM_LIST *) get_mem(sizeof(PARAM_LIST));
(*param)->next_param = NULL;
}
/*
* Free parameter list
*/
free_param_list(param_list)
PARAM_LIST *param_list;
{
PARAM_LIST *param_ptr;
while (param_list) {
param_ptr = param_list->next_param;
free((char *) param_list);
param_list = param_ptr;
}
}
/*
* Malloc space for a DECLARE statement
*/
get_decl_ptr(decl)
DECL **decl;
{
*decl = (DECL *) get_mem(sizeof(DECL));
(*decl)->decl_list = NULL;
(*decl)->next_decl = NULL;
}
/*
* Free DECL list
*/
free_decl(decl_list)
DECL *decl_list;
{
DECL *decl_ptr;
while (decl_list) {
decl_ptr = decl_list->next_decl;
#ifdef FREE_DECL_TOKEN
if (decl_list->decl_token)
free((char *) decl_list->decl_token);
#endif
if (decl_list->decl_list)
free_decl_list(decl_list->decl_list);
free((char *) decl_list);
decl_list = decl_ptr;
}
}

View File

@@ -0,0 +1,46 @@
/*
* Miscellaneous defines
*/
typedef unsigned char BYTE;
typedef unsigned char BOOLEAN;
#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif
#ifndef NULL
#define NULL 0
#endif
/*
* White space characters
*/
#define SPACE ' '
#define TAB 9
#define CR 13
#define LF 10
/*
* Useful defines
*/
#define is_a_uc_char(char) ((char >= 'A') && (char <= 'Z'))
#define is_a_lc_char(char) ((char >= 'a') && (char <= 'z'))
#define is_a_char(char) (((char & 0x5F) >= 'A') && ((char & 0x5F) <= 'Z'))
#define is_a_digit(char) ((char >= '0') && (char <= '9'))
#define is_a_type(token) ((token->token_class == RESERVED) && \
(token->token_type >= BYTE) && (token->token_type <= REAL))
#define is_white(ch) ((ch == ' ') || (ch == TAB))
#define NONE 0
char *strcat(), *strncat(), *strcpy(), *strncpy();
#ifdef IBMPC
int sprintf();
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,131 @@
/*
* Format of a token returned by get_token().
*/
typedef struct TOKEN {
/* Class of token (see below) */
int token_class;
/* Type of token (see below) */
int token_type;
/* Converted token name (when applicable) */
char token_name[MAX_TOKEN_LENGTH];
/* Pointer to start of token in text_buffer */
char *token_start;
/* Number of characters token_start points to */
int token_length;
/* Pointer to start of white space in text_buffer */
char *white_space_start;
/* Pointer to char after end of white space in text_buffer */
char *white_space_end;
#ifdef LINKED_TOKENS
/* Pointer for use in linked list */
struct TOKEN *next_token;
#endif
} TOKEN;
/*
* Format of a procedure parameter list
*/
typedef struct PARAM_LIST {
/* Parameter name */
TOKEN param;
/* Pointer for use in linked list */
struct PARAM_LIST *next_param;
} PARAM_LIST;
/*
* Format of a variable in a DECLARE statement.
*/
typedef struct DECL_ID {
/* Variable name */
TOKEN *name;
/* BASED identifier token */
TOKEN *based_name;
/* If declared AT in another module */
BOOLEAN is_ext_at;
/* Pointer for use in linked list */
struct DECL_ID *next_var;
} DECL_ID;
/*
* Format of an element in a DECLARE statement.
*/
typedef struct DECL_MEMBER {
/* Linked list of identifiers of designated type */
DECL_ID *name_list;
/* LITERALLY string */
char *literal;
#ifdef PARSE_LITERALS
/* Parsed LITERAL token */
TOKEN *literal_token;
#endif
/* Array bound token */
TOKEN *array_bound;
/* Type of variable (INTEGER, WORD, LABEL, LITERALLY, etc.) */
TOKEN *type;
/* Attributes (NONE, EXTERNAL or PUBLIC) */
int attributes;
/* Initialization attribute (NONE, INITIAL or DATA) */
/* If PROCEDURE, DATA if has parameters */
int initialization;
/* Pointer to linked list of structure elements */
struct DECL_MEMBER *struct_list;
/* Pointer to parsed AT expression */
char *at_ptr;
/* Pointer in text_buffer to start of INITIAL/DATA values */
char *init_ptr;
/* Pointer for use in linked list */
struct DECL_MEMBER *next_member;
} DECL_MEMBER;
/*
* Format of a DECLARE statement.
*/
typedef struct DECL {
/* DECLARE token */
TOKEN *decl_token;
/* Linked list of DECL_MEMBERs */
DECL_MEMBER *decl_list;
/* Pointer for use in linked list */
struct DECL *next_decl;
} DECL;
/*
* Format of a context element
*/
typedef struct CONTEXT {
/* Type of context (MODULE, PROCEDURE or DO) */
int context_type;
/* Name of module or procedure */
TOKEN *context_name;
/* Pointer to linked list of declaration members */
DECL_MEMBER *decl_head;
/* Pointer for use in linked list */
struct CONTEXT *next_context;
} CONTEXT;
/*
* Format of a PL/M identifier equivalent
*/
typedef struct {
char *id_name, *new_id;
} CVT_ID;
/*
* Format of a PL/M reserved word
*/
typedef struct {
char *name;
int token;
} RESERVED_WORD;
/*
* Format of a PL/M reserved operator
*/
typedef struct {
char *operator;
char *cvt_operator;
int name;
} RESERVED_OPERATOR;

View File

@@ -0,0 +1,26 @@
extern farp();
slug()
{
void *ptr;
short i;
short **iptr = (short **) &ptr;
float j;
float k;
float l;
WORD mqaFOO;
DWORD fooBAR;
ptr = (void *) &i;
(**iptr) = 72;
iptfil();
setinterrput(0, farp);
signal(abs(i), (short) (i));
j = (float) ((short) (i));
} /* slug */

View File

@@ -0,0 +1,25 @@
FOO: DO;
FARP: PROCEDURE EXTERNAL;
END;
SLUG :PROCEDURE;
DECLARE PTR POINTER;
DECLARE I INTEGER;
DECLARE IPTR BASED PTR INTEGER;
DECLARE J REAL;
declare k real;
declare l REAL;
declare mqaFOO WORD;
declare FOObar DWORD;
PTR = @I;
IPTR = 72;
CALL IPTFIL;
CALL SET$INTERRPUT(0, FARP);
CALL SET$INTERRUPT(IABS(I), FIX(I));
J = FLOAT(FIX(I));
END SLUG;
END FOO;

View File

@@ -0,0 +1,191 @@
/*
* Reserved word list
*/
RESERVED_WORD reserved_words[] = {
/* Statements */
"DECLARE", DECLARE,
"DO", DO,
"END", END,
"IF", IF,
"THEN", THEN,
"ELSE", ELSE,
"GOTO", GOTO,
"GO", GO,
"CALL", CALL,
"RETURN", RETURN,
"DISABLE", DISABLE,
"ENABLE", ENABLE,
"OUTPUT", OUTPUT,
"OUTWORD", OUTWORD,
"OUTHWORD", OUTHWORD,
/* Operators */
"AND", AND,
"OR", OR,
"XOR", XOR,
"NOT", NOT,
"MOD", MOD,
"PLUS", PLUS,
"MINUS", MINUS,
/* DO options */
"CASE", CASE,
"WHILE", WHILE,
"TO", TO,
"BY", BY,
/* DECLARE types */
"BYTE", BYTE,
"WORD", WORD,
"DWORD", DWORD,
"INTEGER", INTEGER,
"REAL", REAL,
"SELECTOR", SELECTOR,
"ADDRESS", ADDRESS,
"STRUCTURE", STRUCTURE,
"LABEL", LABEL,
"POINTER", POINTER,
"BASED", BASED,
"LITERALLY", LITERALLY,
/* DECLARE options */
"DATA", DATA,
"EXTERNAL", EXTERNAL,
"INITIAL", INITIAL,
"PUBLIC", PUBLIC,
"AT", AT,
/* Misc reserved words */
"PROCEDURE", PROCEDURE,
"REENTRANT", REENTRANT,
"INTERRUPT", INTERRUPT,
/* End of list */
"", END_OF_FILE
};
/*
* Operator list
*/
RESERVED_OPERATOR reserved_operators[] = {
"+", "+", PLUS,
"-", "-", MINUS,
"*", "*", TIMES,
"/", "/", DIVIDE,
"<>", "!=", NOT_EQUAL,
"<=", "<=", LESS_EQUAL,
">=", ">=", GREATER_EQUAL,
"<", "<", LESS,
">", ">", GREATER,
"=", "=", EQUAL,
":=", "=", EQUATE,
"@", "&", AT_OP,
"", "", END_OF_FILE
};
/*
* Control directives list
*/
RESERVED_WORD control_directives[] = {
#ifdef USE_ALL_CONTROLS
"CODE", C_CODE,
"CO", C_CODE,
"NOCODE", C_NOCODE,
"NOCO", C_NOCODE,
"COND", C_COND,
"NOCOND", C_NOCOND,
"DEBUG", C_DEBUG,
"DB", C_DEBUG,
"NODEBUG", C_NODEBUG,
"NODB", C_NODEBUG,
"EJECT", C_EJECT,
"EJ", C_EJECT,
#endif
"IF", C_IF,
"ELSEIF", C_ELSEIF,
"ELSE", C_ELSE,
"ENDIF", C_ENDIF,
"INCLUDE", C_INCLUDE,
"IC", C_INCLUDE,
#ifdef USE_ALL_CONTROLS
"INTERFACE", C_INTERFACE,
"ITF", C_INTERFACE,
"LEFTMARGIN", C_LEFTMARGIN,
"LM", C_LEFTMARGIN,
"LIST", C_LIST,
"LI", C_LIST,
"NOLIST", C_NOLIST,
"NOLI", C_NOLIST,
"OBJECT", C_OBJECT,
"OJ", C_OBJECT,
"NOOBJECT", C_NOOBJECT,
"NOOJ", C_NOOBJECT,
"OPTIMIZE", C_OPTIMIZE,
"OT", C_OPTIMIZE,
"OVERFLOW", C_OVERFLOW,
"OV", C_OVERFLOW,
"NOOVERFLOW", C_NOOVERFLOW,
"NOOV", C_NOOVERFLOW,
"PAGELENGTH", C_PAGELENGTH,
"PL", C_PAGELENGTH,
"PAGEWIDTH", C_PAGEWIDTH,
"PW", C_PAGEWIDTH,
"PAGING", C_PAGING,
"PI", C_PAGING,
"NOPAGING", C_NOPAGING,
"NOPI", C_NOPAGING,
"PRINT", C_PRINT,
"PR", C_PRINT,
"NOPRINT", C_NOPRINT,
"NOPR", C_NOPRINT,
"RAM", C_RAM,
"ROM", C_ROM,
"SAVE", C_SAVE,
"SA", C_SAVE,
"RESTORE", C_RESTORE,
"RS", C_RESTORE,
#endif
"SET", C_SET,
"RESET", C_RESET,
#ifdef USE_ALL_CONTROLS
"SMALL", C_SMALL,
"SM", C_SMALL,
"COMPACT", C_COMPACT,
"CP", C_COMPACT,
"MEDIUM", C_MEDIUM,
"MD", C_MEDIUM,
"LARGE", C_LARGE,
"LA", C_LARGE,
"SUBTITLE", C_SUBTITLE,
"ST", C_SUBTITLE,
"SYMBOLS", C_SYMBOLS,
"SB", C_SYMBOLS,
"NOSYMBOLS", C_NOSYMBOLS,
"NOSB", C_NOSYMBOLS,
"TITLE", C_TITLE,
"TT", C_TITLE,
"TYPE", C_TYPE,
"TY", C_TYPE,
"NOTYPE", C_NOTYPE,
"NOTY", C_NOTYPE,
"XREF", C_XREF,
"XR", C_XREF,
"NOXREF", C_NOXREF,
"NOXR", C_NOXREF,
"INTVECTOR", C_INTVECTOR,
"IV", C_INTVECTOR,
"NOINTVECTOR", C_NOINTVECTOR,
"NOIV", C_NOINTVECTOR,
"MOD86", C_MOD86,
"MOD186", C_MOD186,
"WORD16", C_WORD16,
"W16", C_WORD16,
"WORD32", C_WORD32,
"W32", C_WORD32,
#endif
/* End of list */
"", END_OF_FILE
};

View File

@@ -0,0 +1,15 @@
/*
* Reserved word list
*/
extern RESERVED_WORD reserved_words[];
/*
* Operator list
*/
extern RESERVED_OPERATOR reserved_operators[];
/*
* Control directives list
*/
extern RESERVED_WORD control_directives[];

View File

@@ -0,0 +1,478 @@
#include <stdio.h>
#include <string.h>
#include "misc.h"
#include "defs.h"
#include "cvt.h"
#include "struct.h"
#include "tokens.h"
#include "tkn_ext.h"
BOOLEAN parsing_literal;
TOKEN literal_token, eof_token;
char *lit_text_ptr;
extern char *text_buffer, *text_ptr;
extern int line_count;
extern char *line_ptr;
extern char current_file_name[];
/*
* get_token() - Fetch a token from the buffer and return type,
* pointer and associated white space.
*/
get_token(token)
TOKEN *token;
{
RESERVED_WORD *word_ptr;
RESERVED_OPERATOR *op_ptr;
char token_ch, last_token;
char *token_name_ptr;
char *op_name;
BOOLEAN got_fraction;
BOOLEAN cvt_case;
char id[MAX_TOKEN_LENGTH], *id_ptr;
DECL_MEMBER *decl_ptr;
DECL_ID *decl_id;
int token_class;
char *cvt_ptr;
TOKEN *token_ptr;
/* Point to start of white space (if any) */
token->white_space_start = text_ptr;
token->white_space_end = text_ptr;
/* Get first character */
token_ch = *text_ptr++;
/* Check for white space */
while ((token_ch == SPACE) || (token_ch == TAB) || (token_ch == CR) ||
(token_ch == LF) || (token_ch == '$') ||
((token_ch == '/') && (*text_ptr == '*'))) {
if (token_ch == '$') {
/* Check for a control directive */
if ((text_ptr - 1 == text_buffer) ||
(*(text_ptr - 2) == '\n')) {
out_pre_white(token);
parse_control();
/* Reset start of white space */
token->white_space_start = text_ptr;
token->white_space_end = text_ptr;
} else {
parse_error("Illegal character");
return ERROR;
}
} else {
*(token->white_space_end++) = token_ch;
if (token_ch == LF) {
/* Increment input line count */
line_count++;
/* Point to start of line */
line_ptr = text_ptr;
} else
if (token_ch == '/') {
/* Comment - search to end */
/* Add '*' of comment */
token_ch = *(token->white_space_end++) = *text_ptr++;
do {
last_token = token_ch;
token_ch = *(token->white_space_end++) = *text_ptr++;
if (token_ch == LF) {
/* Increment input line count */
line_count++;
/* Point to start of line */
line_ptr = text_ptr;
}
} while ((token_ch != '/') || (last_token != '*'));
}
}
token_ch = *text_ptr++;
}
/* Point to start of current token */
token->token_start = text_ptr - 1;
/* Point to start of converted token */
token_name_ptr = token->token_name;
if (is_a_char(token_ch)) {
/* Process identifier */
#ifdef CONVERT_CASE
/* Convert identifiers starting with an */
/* upper-case character to opposite case. */
cvt_case = is_a_uc_char(token_ch);
#else
cvt_case = FALSE;
#endif
while (TRUE) {
if (is_a_char(token_ch)) {
if (cvt_case) {
if (is_a_uc_char(token_ch))
/* Convert to lower-case character */
*token_name_ptr++ = token_ch + ' ';
else
/* Convert to upper-case character */
*token_name_ptr++ = token_ch - ' ';
} else
*token_name_ptr++ = token_ch;
} else
if (is_a_digit(token_ch))
*token_name_ptr++ = token_ch;
else
if (token_ch == '_')
*token_name_ptr++ = token_ch;
else
if (token_ch == '$')
#ifdef CONVERT_DOLLAR
*token_name_ptr++ = CONVERT_DOLLAR;
#else
;
#endif
else
break;
token_ch = *text_ptr++;
}
/* Mark end of token */
text_ptr--;
token->token_length = text_ptr - token->token_start;
*token_name_ptr = '\0';
/* Get a copy of identifier */
(void) strcpy(id, token->token_name);
/* If lower-case, convert to upper case for comparison */
if (is_a_lc_char(*id)) {
for (id_ptr = id; *id_ptr; id_ptr++)
if (is_a_lc_char(*id_ptr))
*id_ptr -= ' ';
}
/* Check for reserved word */
for (word_ptr = &reserved_words[0]; word_ptr->token != END_OF_FILE;
word_ptr++)
{
if (!strcmp(word_ptr->name, id)) {
token->token_type = word_ptr->token;
/* Check for reserved operator */
switch (token->token_type) {
case AND :
op_name = AND_OP;
break;
case OR :
op_name = OR_OP;
break;
case NOT :
op_name = NOT_OP;
break;
case XOR :
op_name = "^";
break;
case MOD :
op_name = "%";
break;
case PLUS :
parse_error("Cannot convert PLUS operator");
token->token_class = token->token_type = ERROR;
return ERROR;
case MINUS :
parse_error("Cannot convert MINUS operator");
token->token_class = token->token_type = ERROR;
return ERROR;
default :
/* Must not be an operator! */
token->token_class = RESERVED;
return RESERVED;
}
/* Switch to appropriate operator */
(void) strcpy(token->token_name, op_name);
token->token_class = OPERATOR;
return OPERATOR;
}
}
/* Not a reserved word - must be an identifier */
token->token_class = token->token_type = IDENTIFIER;
/* Check for a literal */
if (!parsing_literal && find_symbol(token, &decl_ptr, &decl_id) &&
(decl_ptr->type->token_type == LITERALLY)) {
#ifdef CONVERT_CASE
/* Convert case of literal */
for (cvt_ptr = token->token_name; *cvt_ptr;
cvt_ptr++) {
if (is_a_uc_char(*cvt_ptr))
*cvt_ptr += 32;
else
if (is_a_lc_char(*cvt_ptr))
*cvt_ptr -= 32;
}
#endif
#ifdef PARSE_LITERALS
/* Yes - Has literal been parsed? */
if (decl_ptr->literal_token) {
/* Yes - return parsed literal token */
/* with token_name set to literal name */
token_ptr = decl_ptr->literal_token;
token->token_class = token_ptr->token_class;
token->token_type = token_ptr->token_type;
return token->token_class;
}
#endif
/* Is literal a single token? */
lit_text_ptr = text_ptr;
text_ptr = decl_ptr->literal;
token_class = get_token(&literal_token);
if (get_token(&eof_token) == END_OF_FILE) {
/* Yes - return single token with */
/* token_name set to literal name */
token->token_class = token_class;
token->token_type = literal_token.token_type;
text_ptr = lit_text_ptr;
parsing_literal = FALSE;
return token->token_class;
}
/* No - parse complex literal and replace */
/* Use of literal declaration */
parsing_literal = TRUE;
text_ptr = lit_text_ptr;
parse_warning("Literal expanded");
text_ptr = decl_ptr->literal;
return get_token(token);
}
return IDENTIFIER;
} else
if (is_a_digit(token_ch)) {
/* Process number */
/* Flag not a floating point number */
got_fraction = FALSE;
while (TRUE) {
if (is_a_digit(token_ch))
*token_name_ptr++ = token_ch;
else
if (token_ch == '.') {
got_fraction = TRUE;
*token_name_ptr++ = token_ch;
} else
if ((token_ch == 'E') && got_fraction) {
/* Process exponent */
*token_name_ptr++ = token_ch;
/* Signed exponent? */
if ((*text_ptr != '+') && (*text_ptr != '-')) {
/* No - default to + exponent */
*token_name_ptr++ = '+';
} else {
/* Yes - add sign */
token_ch = *text_ptr++;
*token_name_ptr++ = token_ch;
}
} else
/* Assume it's a hex char or constant designator */
if (is_a_char(token_ch))
*token_name_ptr++ = token_ch;
else
if (token_ch != '$')
break;
token_ch = *text_ptr++;
}
/* Point to last character in constant */
token_name_ptr--;
token_ch = *token_name_ptr;
if (got_fraction) {
/* Floating point - add suffix */
*++token_name_ptr = 'F';
/* Mark end of token */
*++token_name_ptr = '\0';
} else
if (token_ch == 'B') {
parse_error("Binary constant");
token->token_class = token->token_type = ERROR;
return ERROR;
} else
if ((token_ch == 'O') || (token_ch == 'Q')) {
/* Octal constant */
/* Mark end of token */
*token_name_ptr++ = '\0';
/* Move constant up 1 character */
while (token_name_ptr != token->token_name) {
*token_name_ptr = *(token_name_ptr - 1);
token_name_ptr--;
}
/* Make a C octal constant */
*token_name_ptr = '0';
} else
if (token_ch == 'H') {
/* Hex constant */
/* Mark end of token */
*token_name_ptr++ = '\0';
token_name_ptr++;
/* Move constant up 2 characters */
while (token_name_ptr != (token->token_name + 1)) {
*token_name_ptr = *(token_name_ptr - 2);
token_name_ptr--;
}
/* Make a C hex constant */
*token_name_ptr-- = 'x';
*token_name_ptr = '0';
} else
if (token_ch == 'D')
/* Decimal constant - ignore 'D' */
*token_name_ptr = '\0';
else
/* Regular constant */
*++token_name_ptr = '\0';
/* Mark end of token */
text_ptr--;
token->token_length = text_ptr - token->token_start;
token->token_class = token->token_type = NUMERIC;
return NUMERIC;
} else {
/* Check for operator */
for (op_ptr = &reserved_operators[0]; op_ptr->name != END_OF_FILE;
op_ptr++) {
token->token_length = strlen(op_ptr->operator);
if (!strncmp(text_ptr - 1, op_ptr->operator,
token->token_length)) {
/* Found operator */
/* Save converted type */
(void) strcpy(token->token_name, op_ptr->cvt_operator);
token->token_type = op_ptr->name;
/* Point past operator */
text_ptr += token->token_length - 1;
token->token_class = OPERATOR;
return OPERATOR;
}
}
/* Assume single character token */
*token_name_ptr++ = token_ch;
*token_name_ptr = '\0';
/* Mark end of token so far */
token->token_length = 1;
switch (token_ch) {
case ';' :
token->token_class = token->token_type = END_OF_LINE;
return END_OF_LINE;
case ':' :
token->token_class = token->token_type = LABEL;
return LABEL;
case ',' :
token->token_class = token->token_type = COMMA;
return COMMA;
case '.' :
token->token_class = token->token_type = PERIOD;
return PERIOD;
case '(' :
token->token_class = token->token_type = LEFT_PAREN;
return LEFT_PAREN;
case ')' :
token->token_class = token->token_type = RIGHT_PAREN;
return RIGHT_PAREN;
case '\'' :
/* String constant */
token_name_ptr--;
while (1) {
if (*text_ptr == '\'') {
if ((*(text_ptr + 1) == '\''))
text_ptr++;
else
break;
}
*token_name_ptr++ = *text_ptr++;
}
text_ptr++;
*token_name_ptr++ = '\0';
token->token_length = strlen(token->token_name);
token->token_class = token->token_type = STRING;
return STRING;
case 0:
if (parsing_literal) {
/* Done parsing literal - */
/* Switch back to text_ptr */
parsing_literal = FALSE;
text_ptr = lit_text_ptr;
return get_token(token);
}
token->token_class = token->token_type = END_OF_FILE;
return END_OF_FILE;
default:
parse_error("Illegal character");
/* Eat the evidence */
token->token_name[0] = '\0';
token->token_class = token->token_type = ERROR;
return ERROR;
}
}
}
/*
* Copy source token to destination token
*/
token_copy(src, dest)
TOKEN *src, *dest;
{
dest->token_class = src->token_class;
dest->token_type = src->token_type;
(void) strcpy(dest->token_name, src->token_name);
dest->token_start = src->token_start;
dest->token_length = src->token_length;
dest->white_space_start = src->white_space_start;
dest->white_space_end = src->white_space_end;
}

View File

@@ -0,0 +1,151 @@
/**************************
* Token classes
*************************/
#define END_OF_FILE 0
#define RESERVED 1
#define IDENTIFIER 2
#define NUMERIC 3
#define OPERATOR 4
#define STRING 5
#define LABEL 6
#define END_OF_LINE 7
#define COMMA 8
#define PERIOD 9
#define LEFT_PAREN 10
#define RIGHT_PAREN 11
#define SUBSCRIPT 12
#define MODULE 13
#define ERROR 19
/**************************
* Token types
*************************/
/*
* Operators
*/
#define PLUS 20 /* + */
#define MINUS 21 /* - */
#define TIMES 22 /* * */
#define DIVIDE 23 /* / */
#define NOT_EQUAL 24 /* <> */
#define LESS_EQUAL 25 /* <= */
#define GREATER_EQUAL 26 /* >= */
#define LESS 27 /* < */
#define GREATER 28 /* > */
#define EQUAL 29 /* = */
#define EQUATE 30 /* := */
#define COLON 31 /* : */
#define AT_OP 32 /* @ */
/*
* Reserved word values
*/
/* Statements */
#define DECLARE 40
#define DO 41
#define END 42
#define IF 43
#define THEN 44
#define ELSE 45
#define GOTO 46
#define GO 47
#define CALL 48
#define RETURN 49
#define DISABLE 50
#define ENABLE 51
#define OUTPUT 52
#define OUTWORD 53
#define OUTHWORD 54
/* Operators */
#define AND 60
#define OR 61
#define XOR 62
#define NOT 63
#define MOD 64
/* DO options */
#define CASE 70
#define WHILE 71
#define TO 72
#define BY 73
/* DECLARE types */
#define BYTE 80
#define WORD 81
#define DWORD 82
#define INTEGER 83
#define REAL 84
#define ADDRESS 85
#define SELECTOR 86
#define POINTER 87
#define STRUCTURE 88
/* DECLARE options */
#define BASED 90
#define LITERALLY 91
#define DATA 92
#define EXTERNAL 93
#define INITIAL 94
#define PUBLIC 95
#define AT 96
/* Misc reserved words */
#define PROCEDURE 101
#define REENTRANT 102
#define INTERRUPT 103
/* Control Directives */
#define C_CODE 200
#define C_NOCODE 201
#define C_COND 202
#define C_NOCOND 203
#define C_DEBUG 204
#define C_NODEBUG 205
#define C_EJECT 206
#define C_IF 207
#define C_ELSEIF 208
#define C_ELSE 209
#define C_ENDIF 210
#define C_INCLUDE 211
#define C_INTERFACE 212
#define C_LEFTMARGIN 213
#define C_LIST 214
#define C_NOLIST 215
#define C_OBJECT 216
#define C_NOOBJECT 217
#define C_OPTIMIZE 218
#define C_OVERFLOW 219
#define C_NOOVERFLOW 220
#define C_PAGELENGTH 221
#define C_PAGEWIDTH 222
#define C_PAGING 223
#define C_NOPAGING 224
#define C_PRINT 225
#define C_NOPRINT 226
#define C_RAM 227
#define C_ROM 228
#define C_SAVE 229
#define C_RESTORE 230
#define C_SET 231
#define C_RESET 232
#define C_SMALL 233
#define C_COMPACT 234
#define C_MEDIUM 235
#define C_LARGE 236
#define C_SUBTITLE 237
#define C_SYMBOLS 238
#define C_NOSYMBOLS 239
#define C_TITLE 240
#define C_TYPE 241
#define C_NOTYPE 242
#define C_XREF 243
#define C_NOXREF 244
#define C_INTVECTOR 245
#define C_NOINTVECTOR 246
#define C_MOD86 247
#define C_MOD186 248
#define C_WORD16 249
#define C_WORD32 250

View File

@@ -0,0 +1,6 @@
typedef unsigned char BYTE;
typedef unsigned short WORD;
typedef unsigned int DWORD;
typedef short INTEGER;
typedef float REAL;

View File

@@ -0,0 +1 @@
char version[] = "Version 1.02 (Alpha)";