📄 proc.c
字号:
/*--- proc.c -------------------------------------------------------------Procedure, type, variable, and label parsing routines for the Pascal to Ctranslator.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 1024typedef 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 */};booleanisSectionKeyword(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.------------------------------------------------------------------------*/voidskipSpace(){ 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.------------------------------------------------------------------------*/voidparseSpace(){ 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); }}voidexpected(s)char *s;{ printf("/***# Expected %s ***/", s); fflush(stdout);}/*---- expectThing -------------------------------------------------------Makes sure current token is of desired type, else prints error message.------------------------------------------------------------------------*/voidexpectThing(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.------------------------------------------------------------------------*/voidgetThing(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 */voidparseVarDec(){ 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.----------------------------------------------------------------------------*/voidparseProcedure(){ 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 specificationto the buffer tindex.Lower bounds are ignored, 'cause it's safe to do so, and impossibly difficultto handle.----------------------------------------------------------------------------*/voidconvertArrayBound(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-----------------------------------------------------------------------*/voidparseTypeDecl(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;----------------------------------------------------------------------------*/voidparseVar(){ 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;---------------------------------------------------------------------------*/voidparseType(){ 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 likeLABEL foo, goo;into/ * LABEL foo, goo; * /----------------------------------------------------------------------------*/voidparseLabel(){ 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);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -