DataMuseum.dk

Presents historical artifacts from the history of:

DKUUG/EUUG Conference tapes

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about DKUUG/EUUG Conference tapes

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - download
Index: ┃ T p

⟦7add275ff⟧ TextFile

    Length: 14091 (0x370b)
    Types: TextFile
    Names: »proc.c«

Derivation

└─⟦a0efdde77⟧ Bits:30001252 EUUGD11 Tape, 1987 Spring Conference Helsinki
    └─ ⟦this⟧ »EUUGD11/euug-87hel/sec1/p2c/proc.c« 

TextFile

/*--- proc.c -------------------------------------------------------------
Procedure, type, variable, and label parsing routines for the Pascal to C
translator.
3/25/87 Daniel Kegel (seismo!rochester!srs!dan)
--------------------------------------------------------------------------*/
#include <stdio.h>
#include <string.h>
#include "p2c.h"
#include "ktypes.h"	/* keyword type definitions */

#define SLEN 80	
typedef char sstr[SLEN+1];	/* short string */
#define PLEN 1024
typedef char pstr[PLEN+1];	/* long string */

/* pgroup is used in parseProcedure to store the procedure's parameters */
struct pgroup {
    sstr pclass;	/* VAR or empty */
    sstr ptype;		/* what type all these guys are */
    pstr params;	/* identifiers separated by commas and space */
};

boolean
isSectionKeyword(k)
register int k;
{
    return(k==T_CONST||k==T_TYPE||k==T_VAR||k==T_PROC||k==T_FUNC||k==T_BEGIN);
}

/*--- skipSpace ---------------------------------------------------------
Accepts and throws away space and comment tokens.
------------------------------------------------------------------------*/
void
skipSpace()
{
    do
	getTok();
    while (cTok.kind == T_SPACE || cTok.kind == T_COMMENT);
    if (cTok.kind == T_EOF) {
	printf("\n/***# EOF ***/\n");
	fflush(stdout);
	exit(1);
    }
}

/*--- parseSpace ---------------------------------------------------------
Accepts and prints space and comment tokens.
------------------------------------------------------------------------*/
void
parseSpace()
{
    do {
	getTok();
	if (cTok.kind == T_SPACE || cTok.kind == T_COMMENT)
	    fputs(cTok.str, stdout);
    } while (cTok.kind == T_SPACE || cTok.kind == T_COMMENT);
    if (cTok.kind == T_EOF) {
	printf("\n/***# EOF ***/\n");
	fflush(stdout);
	exit(1);
    }
}

void
expected(s)
char *s;
{
    printf("/***# Expected %s ***/", s);
    fflush(stdout);
}

/*---- expectThing -------------------------------------------------------
Makes sure current token is of desired type, else prints error message.
------------------------------------------------------------------------*/

void
expectThing(s, k)
char *s;
{
    if (cTok.kind != k)
	expected(s);
}

/*---- getThing -------------------------------------------------------
Gets next nonblank token, makes sure it is desired type, else prints error 
message.
------------------------------------------------------------------------*/
void
getThing(s, k)
char *s;
int k;
{
    skipSpace();
    expectThing(s, k);
}

/*---- parseVarDec ----------------------------------------------------
Translates one (possibly multi-)variable declaration.
Works for complex types, but can't be used to parse procedure parameters.
On entry, cTok is first token in identifier list.
On exit, cTok is the token after the type- probably T_SEMI.
Semicolon is translated, too.
----------------------------------------------------------------------*/

struct ident {			/* Used to save variable declaration body */
    char *str;			/* until type is known */
    int  kind;
};
#define MAXIDENTS 132		/* allows about 32 variables */

void
parseVarDec()
{
    void parseTypeDecl();		/* forward declaration */
    sstr indir, index;
    struct ident idents[MAXIDENTS];
    int i, n;

    /* Get identifiers, up to the colon that marks end of list */
    n=0;
    while (cTok.kind != T_COLON) {
	if (n == MAXIDENTS-1)
	    printf("/***# Variable declaration too long ***/");
	if (n == MAXIDENTS) n--;
	idents[n].str = MALLOC(char, strlen(cTok.str));
	strcpy(idents[n].str, cTok.str);
	idents[n++].kind = cTok.kind;
	if (cTok.kind != T_ZIP && cTok.kind != T_COMMA 
	&& cTok.kind != T_SPACE && cTok.kind != T_COMMENT)
	    expected(" (variable declaration) comma or identifier");
	getTok();		/* don't nuke spaces or comments */
    }

    /* Output any whitespace given before the type declaration */
    for (i=0; i<n&&(idents[i].kind==T_SPACE||idents[i].kind==T_COMMENT); i++){
	fputs(idents[i].str, stdout);
	free(idents[i].str);
    }

    /* Translate type specification */
    indir[0]=index[0]='\0';
    parseTypeDecl(indir, index);

    /* Output the identifiers, with appropriate modification for 
       ptr & array types */
    putchar(' ');		/* separate RECORD from first element...? */
    for (; i<n; i++) {
	if (idents[i].kind == T_ZIP && indir[0]!='\0')
	    fputs(indir, stdout);
	fputs(idents[i].str, stdout);
	if (idents[i].kind == T_ZIP && index[0]!='\0')
	    fputs(index, stdout);
	free(idents[i].str);
    }
    if (cTok.kind == T_SEMI)
	putchar(';');
}

/*---- parseProcedure -------------------------------------------------------
On entry, cTok is "PROCEDURE" or "FUNCTION".
On exit, cTok is the token after the semicolon after the function header.

Turns declarations like
    foo(a:int; b:int)
into
    foo(a,b)
    int a;
    int b;

Breaks up function declarations into 
    1. name
    2. parameter declarations
    3. type (or 'void', if procedure)
Breaks up parameter declarations into an array of pgroups.
----------------------------------------------------------------------------*/
void
parseProcedure()
{
    boolean isProcedure;
    boolean isForward;
    sstr fnName;
    sstr fnType;
    struct pgroup *pgps=NULL;
    int i, npgp=0;
    register struct pgroup *p;

    /* Remember whether is returns a value or not */
    isProcedure = (cTok.kind == T_PROC);
    /* Get function or procedure name, skipping space & comments */
    getThing("function name", T_ZIP);
    strcpy(fnName, cTok.str);
    skipSpace();			/* eat the function name */
    /* Get open paren (or semicolon of a parameterless procedure or fn) */
    if (cTok.kind == T_LPAREN) {
	do {
	    register char *cp;
	    /* Allocate and initialize another parameter group */
	    if (npgp++ == 0) pgps=MALLOC(struct pgroup, 1);
	    else pgps = REALLOC(pgps, struct pgroup, npgp);
	    p = pgps + npgp-1;
	    p->pclass[0] = p->ptype[0] = '\0';

	    /* Get optional class keyword */
	    skipSpace();		/* eat the paren or semicolon */
	    if (cTok.kind == T_VAR) {
		strcpy(p->pclass, cTok.str);
		skipSpace();		/* eat the class keyword */
	    }
	    /* Get identifier list & type */
	    cp = p->params;
	    /* Get identifiers, up to the colon that marks end of list */
	    while (cTok.kind != T_COLON) {
		register char *cq=cTok.str;
		if (cTok.kind != T_ZIP && cTok.kind != T_COMMA)
		    expected(" (variable declaration) comma or identifier");
		while (*cp++ = *cq++)
		    ;
		cp--;
		skipSpace();
	    }
	    *cp = 0;

	    /* Get type specifier, which may be many tokens.  Primitive. */
	    skipSpace();
	    p->ptype[0]=0;
	    do {
		strcat(p->ptype, cTok.str);
		skipSpace();
	    } while (cTok.kind != T_SEMI && cTok.kind != T_RPAREN);
	} while (cTok.kind == T_SEMI);
	expectThing(") at end of param list", T_RPAREN);
	skipSpace();
    }
    /* Get return type */
    if (isProcedure) {
	strcpy(fnType, "void");
    } else {
	expectThing(":", T_COLON);
	getThing("function type", T_ZIP);
	strcpy(fnType, cTok.str);
	skipSpace();
    }
    expectThing("semicolon", T_SEMI);
    /* Get optional FORWARD keyword */
    skipSpace();
    if (isForward = (cTok.kind == T_FORWARD)) {
	getThing(";", T_SEMI);
	skipSpace();
    }

    /* Output the first part of the translated function declaration */
    printf("%s %s(", fnType, fnName);
    for (i=0, p=pgps; i++ < npgp; p++) {
	fputs(p->params, stdout);
	if (i<npgp) putchar(',');
    }
    putchar(')');
    if (isForward)
	puts(";");
    else {
	/* Output second part */
	putchar('\n');
	for (i=0, p=pgps; i++ < npgp; p++) {
	    if (p->pclass[0])
		fputs(p->pclass, stdout);	/* already xlated */
	    printf("%s %s;\n", p->ptype, p->params);
	}
    }
}

/*--- convertArrayBound -----------------------------------------------------
Given the upper bound of a Pascal array, append the C array size specification
to the buffer tindex.
Lower bounds are ignored, 'cause it's safe to do so, and impossibly difficult
to handle.
----------------------------------------------------------------------------*/
void
convertArrayBound(s, tindex)
char *s, *tindex;
{
    sstr buf;
    int ubound;

    ubound = atoi(s);
    if (ubound == 0) {
	/* Probably symbolic */
	sprintf(buf, "[%s+1]", s);
    } else {
	if (ubound < 0)
	    expected("positive upper bound");
	sprintf(buf, "[%d]", ubound+1);
    }
    strcat(tindex, buf);
}

/*---- parseTypeDecl -------------------------------------------------------
Translates a type definition in place.  Appends indirection & array subscrips,
if any, to the buffers tindir and tindex.
Never translates the semicolon- that is done in parseType.

On entry, cTok is the token that made us expect to find a type
(e.g. the colon in a variable declaration, or the equals in a type declaration,
On exit, cTok is the token after the type, usually T_SEMI (but may be T_END 
in the last declaration in a RECORD).

Pascal (or at least, Turbo Pascal) doesn't allow constructions like
    a = ^array [0..10] of integer;
rather, it forces you to define the base type, too:
    b = array [0..10] of integer;
    a = ^b;
Thus any type definition can be unambiguously broken up into 2 parts:
    - the base type (which may be complex)
    - if pointer, how many levels of indirection
      else if array, how many indices the type has, with limits
-----------------------------------------------------------------------*/
void
parseTypeDecl(tindir, tindex)
char *tindir, *tindex;		/* buffer to put * or [n] in */
{
    skipSpace();		/* get initial token of type */

    switch (cTok.kind) {
    case T_DEREF:		/* pointer type */
	strcat(tindir, "*");
	parseTypeDecl(tindir, tindex);
	break;
    case T_LPAREN:		/* enumerated type */
	fputs("enum {", stdout);
	do {
	    parseSpace();
	    if (cTok.kind != T_RPAREN)
		fputs(cTok.str, stdout);
	} while (cTok.kind != T_RPAREN);
	getThing(";", T_SEMI);
	putchar('}');
	break;
    case T_ARRAY:		/* array type */
	getThing("[", T_LBRACKET);
	do {					/* Get all the dimensions */
	    getThing("lower bound", T_ZIP);	/* Ignore lower bound except */
	    if (cTok.str[0] == '-')		/* to make sure >= 0 */
		expected("non-negative lower bound");
	    getThing("..", T_RANGE);
	    getThing("upper bound", T_ZIP);
	    convertArrayBound(cTok.str, tindex);
	    skipSpace();
	} while (cTok.kind == T_COMMA);
	expectThing("]", T_RBRACKET);
	getThing("OF", T_OF);
	parseTypeDecl(tindir, tindex);
	break;
    case T_STRINGTYPE:		/* Turbo (& UCSD?) string type */
	printf("char");
	skipSpace();
	if (cTok.kind != T_LPAREN && cTok.kind != T_LBRACKET) 
	    expected("[ or ( after STRING");
	getThing("string length", T_ZIP);
	convertArrayBound(cTok.str, tindex);
	skipSpace();
	if (cTok.kind != T_RPAREN && cTok.kind != T_RBRACKET) 
	    expected("] or ) after STRING[");
	getThing(";", T_SEMI);
	break;
    case T_FILE:		/* file type - not supported in C */
	strcat(tindir, "*");
	printf("FILE /* OF ");	/* show what it's a file of in the comment */
	do {
	    skipSpace();
	    if (cTok.kind != T_COMMENT);	/* avoid nesting comments */
		fputs(cTok.str, stdout);
	} while (cTok.kind != T_SEMI);
	printf(" */ ");
	break;
    case T_RECORD:		/* struct definition */
	printf("struct {");
	parseSpace();		/* eat RECORD */
	do {
	    if (cTok.kind == T_CASE) {
		printf("/***# Sorry- variant records not supported\n\t");
		do {
		    if (cTok.kind != T_COMMENT)
			fputs(cTok.str, stdout);
		    getTok();
		} while (cTok.kind != T_END);
		printf(" ***/");
		break;
	    }
	    parseVarDec();
	    if (cTok.kind == T_SEMI)
		parseSpace();
	    else if (cTok.kind == T_END)
		putchar(';');		/* Pascal doesn't need ; but C does*/
	    else if (cTok.kind != T_CASE)
		expected("Either semicolon or END");
	} while (cTok.kind != T_END);
	parseSpace();		/* eat the END, get the semi */
	printf("}");
	break;
    case T_ZIP:			/* probably a type keyword like 'integer' */
	fputs(cTok.str, stdout);
	skipSpace();		/* eat the type, get the semi */
	break;
    default:			/* unexpected */
	expected("type");
    }
}

/*---- parseVar -------------------------------------------------------
Translates the VAR section of a program or procedure.

On entry, cTok is "VAR".
On exit, cTok is any section-starting keyword.
Turns declarations like
    foo : ^integer;
into
    int *foo;
----------------------------------------------------------------------------*/
void
parseVar()
{
    getTok();		/* eat the VAR */
    do {
	parseVarDec();
	if (cTok.kind == T_SEMI)
	    parseSpace();
    } while (!isSectionKeyword(cTok.kind));
}

/*---- parseType -----------------------------------------------------------
Translates the TYPE section of a program or procedure.
On entry, cTok is TYPE.
On exit, cTok is any section-starting keyword.

Turns declarations like
    foo = array [0..10, LO..HI] of integer;
    boo = record
	    x : foo;
	    y : ^foo
	  end;

into
    typedef integer foo[11][HI+1];
    typedef struct {
	foo x;
	foo *y;
    } boo;
---------------------------------------------------------------------------*/
void
parseType()
{
    parseSpace();
    do {
	sstr typ;
	sstr tindir, tindex;
	expectThing("type identifier", T_ZIP);
	strcpy(typ, cTok.str);
	parseSpace();
	expectThing("=", T_EQUALS);
	printf("typedef ");
	tindir[0]=tindex[0]=0;
	parseTypeDecl(tindir, tindex);
	expectThing(";", T_SEMI);
	printf(" %s%s%s;", tindir, typ, tindex);
	parseSpace();
    } while (!isSectionKeyword(cTok.kind));
}

/*---- parseLabel -------------------------------------------------------
On entry, cTok is "LABEL".
On exit, cTok is whatever follows the semicolon.

Turns declarations like
LABEL foo, goo;
into
/ * LABEL foo, goo; * /
----------------------------------------------------------------------------*/
void
parseLabel()
{
    skipSpace();		/* eat the LABEL */
    printf("/* LABEL ");
    /* Get identifiers, up to the semicolon that marks end of list */
    while (cTok.kind != T_SEMI) {
	if (cTok.kind != T_ZIP && cTok.kind != T_COMMA)
	    expected(" (label declaration) comma or identifier");
	fputs(cTok.str, stdout);
	skipSpace();
    }
    /* Get semicolon without wiping out trailing space */
    getTok();
    fputs("; */", stdout);
}