home *** CD-ROM | disk | FTP | other *** search
- From dan@srs.UUCP Thu Mar 26 09:06:29 1987
- Path: seismo!rochester!ur-tut!ur-cvsvax!srs!dan
- From: dan@srs.UUCP (Dan Kegel)
- Newsgroups: net.sources,comp.sys.ibm.pc
- Subject: new Pascal to C translator
- Message-ID: <141@srs.UUCP>
- Date: 26 Mar 87 14:06:29 GMT
- Organization: S.R.Systems
- Lines: 1133
-
- Here's a Pascal to C translator which correctly handles function,
- procedure, and most type declarations (yay!). It is adapted from p2c.c 1.1 of
- the mod.sources archives; I suppose it should be called "p2c, version 2.0".
- I wrote it in anticipation of a need to convert a VERY large Turbo Pascal
- program, but the need never arose... so the resulting program is untested
- and unpolished. Nevertheless, it should be interesting and useful to those
- willing to play with it a bit.
- Cheers,
- Dan Kegel
- seismo!rochester!srs!dan
-
- p.s. Hi, Rick!
-
- #!/bin/sh
- #
- # shar archiver, delete everything above the #!/bin/sh line
- # and run through sh (not csh)
- #
- echo 'shar: extracting "p2c.doc" (2297 characters)'
- sed 's/^XX //' > p2c.doc << 'XXX_EOF_XXX'
- XX NAME
- XX p2c - Pascal to C translator
- XX
- XX SYNOPSIS
- XX p2c < foo.pas > foo.c
- XX
- XX DESCRIPTION
- XX p2c converts many Pascal structures to their C equivalent.
- XX The Pascal source can be in upper, lower, or mixed case; case is
- XX preserved during translation.
- XX
- XX Structures translated properly include simple assignment
- XX and comparison statments, variable, type, and label declarations,
- XX enumerated types, and procedure and function declarations and instances.
- XX
- XX Structures NOT translated properly include sets, constant declarations,
- XX variant records, files, subrange types, VAR parameters, CASE, FOR,
- XX WITH, READ, and WRITE statements, and nested procedures.
- XX
- XX The translator provides hints about untranslated regions by inserting
- XX UPPERCASE messages enclosed with /* and */ into the translated source.
- XX Error messages are of the form /***# Expected ... ***/.
- XX
- XX Human massaging of the output will certainly be needed.
- XX In fact, you may want to modify the keyword translation table
- XX to better translate your particular variant of Pascal.
- XX
- XX IMPLEMENTATION
- XX Written in C for Sun UNIX workstations; ought to compile on other
- XX systems without change...
- XX Some of the translation is done with a keyword table, but most of
- XX the work is done by a recursive-descent parser.
- XX
- XX BUGS
- XX Not well tested.
- XX Error recovery is very poor- the first error in translation inside
- XX the recursive-descent section will result in a very long stream of
- XX error messages.
- XX Some of the bread-and-butter structures of Pascal- like CASE and FOR-
- XX are not translated properly, although it would be easy to extend
- XX the parser to understand them.
- XX
- XX I welcome bug reports, and invite anyone interested to implement
- XX more PASCAL structures; I probably won't work on it much, because
- XX I don't use Pascal these days.
- XX
- XX VERSION
- XX This version by Daniel Kegel <dan@srs.UUCP> or <seismo!rochester!srs!dan>,
- XX 25 March 87.
- XX Based on a program by James A Mullens <jcm@ornl-msr.arpa> 29-Jan-87
- XX which was in turn based on two nearly identical programs by Robert Heller
- XX (1 Feb 1985) and Rick Walker <walker@hpl-opus.hp.COM> (8 Sep 1986)
- XX which were reportedly derived from a similar program in the Feb 85 Byte
- XX which did a C TO PASCAL conversion.
- XX
- XXX_EOF_XXX
- if test 2297 -ne "`wc -c < p2c.doc`"
- then
- echo 'shar: transmission error on "p2c.doc"'
- fi
- echo 'shar: extracting "p2c.h" (1096 characters)'
- sed 's/^XX //' > p2c.h << 'XXX_EOF_XXX'
- XX /*---- p2c.h ------------------------------------------------------
- XX Defines and Global Variable for the Pascal to C translator
- XX 3/25/87 Daniel Kegel (seismo!rochester!srs!dan)
- XX -------------------------------------------------------------------*/
- XX
- XX #define MAXTOKLEN 2048 /* maximum token length */
- XX /* Note: even comments are jammed into a token; that's why this is big. */
- XX
- XX typedef struct { /* holds keywords, operators, etc. */
- XX char str[MAXTOKLEN];
- XX int kind; /* code from table of wnodes */
- XX } token;
- XX
- XX typedef struct {
- XX int ktype; /* the meaning of the keyword */
- XX char *pname; /* the Pascal name of the keyword */
- XX char *cname; /* the C name of the keyword */
- XX } wnode;
- XX
- XX /* Allocate or Reallocate n 'type' items */
- XX #define MALLOC(type, n) \
- XX ((type *) DoMalloc((unsigned) sizeof(type) * (n)))
- XX #define REALLOC(ptr, type, n) \
- XX ((type *) DoRealloc((char *)ptr, (unsigned) sizeof(type) * (n)))
- XX
- XX #ifndef TRUE
- XX #define TRUE 1
- XX #define FALSE 0
- XX #endif
- XX #ifndef boolean
- XX #define boolean int
- XX #endif
- XX
- XX /*--- The Global Variable ---------*/
- XX token cTok; /* current token from scanner */
- XX
- XXX_EOF_XXX
- if test 1096 -ne "`wc -c < p2c.h`"
- then
- echo 'shar: transmission error on "p2c.h"'
- fi
- echo 'shar: extracting "ktypes.h" (1438 characters)'
- sed 's/^XX //' > ktypes.h << 'XXX_EOF_XXX'
- XX /*--- ktypes.h ------------------------------------------------------
- XX Keyword types for the Pascal to C translator.
- XX 3/25/87 Daniel Kegel (seismo!rochester!srs!dan)
- XX ---------------------------------------------------------------------*/
- XX #define T_ZIP 0 /* Nondescript identifier */
- XX #define T_BEGIN 1 /* BEGIN */
- XX #define T_END 2 /* END */
- XX #define T_PROC 3 /* PROCEDURE */
- XX #define T_FUNC 4 /* FUNCTION */
- XX #define T_FORWARD 5 /* FORWARD */
- XX #define T_CONST 6 /* CONST */
- XX #define T_VAR 7 /* VAR */
- XX #define T_COMPARE 8 /* ==, <>, >, < */
- XX #define T_EQUALS 9 /* = alone; in CONST, TYPE or comparison */
- XX #define T_COLON 10 /* : alone; in VAR, READ, or WRITE */
- XX #define T_SEMI 11 /* ; alone */
- XX #define T_LPAREN 12 /* ( alone */
- XX #define T_RPAREN 13 /* ) alone */
- XX #define T_SPACE 14 /* a string of blanks, tabs, and/or newlines */
- XX #define T_STRUCTMEMBER 15 /* ^. */
- XX #define T_ASSIGN 16 /* := */
- XX #define T_STRING 17 /* quoted string */
- XX #define T_COMMENT 18 /* comment text */
- XX #define T_EOF 19 /* end of source file */
- XX #define T_COMMA 20 /* , */
- XX #define T_LABEL 21 /* LABEL */
- XX #define T_DEREF 22 /* ^ alone */
- XX #define T_LBRACKET 23 /* [ */
- XX #define T_RBRACKET 24 /* ] */
- XX #define T_ARRAY 25 /* ARRAY */
- XX #define T_RANGE 26 /* .. */
- XX #define T_OF 27 /* OF */
- XX #define T_RECORD 28 /* RECORD */
- XX #define T_FILE 29 /* FILE */
- XX #define T_TYPE 30 /* TYPE */
- XX #define T_STRINGTYPE 31 /* STRING(n) or STRING[n] type */
- XX #define T_CASE 32 /* CASE */
- XXX_EOF_XXX
- if test 1438 -ne "`wc -c < ktypes.h`"
- then
- echo 'shar: transmission error on "ktypes.h"'
- fi
- echo 'shar: extracting "p2c.c" (10964 characters)'
- sed 's/^XX //' > p2c.c << 'XXX_EOF_XXX'
- XX /*----------------------------------------------------------------------
- XX PAS2C.C Version 1.1
- XX Translate Pascal keywords and operators to C.
- XX useage: pas2c < pascal_source > c_source
- XX i.e., this is a filter program which filters out the Pascal.
- XX By James A Mullens <jcm@ornl-msr.arpa> 29-Jan-87
- XX
- XX Revisions:
- XX Version 1.1 17-Feb-87 Changed several keyword translations on the
- XX advice of James R. Van Zandt <jrv@mitre-bedford.ARPA>. Added many
- XX more translations. Added a source for function strcmpi for the
- XX unfortunates who don't have this case-insensitive string comparison
- XX in their C library.
- XX
- XX Dan Kegel 15 Mar 87 Made it work on Sun workstation. Ripped out
- XX translations that hurt translation of a large (20,000 line) Turbo program.
- XX ----------------------------------------------------------------------*/
- XX
- XX #include <stdio.h> /* standard I/O */
- XX #include <ctype.h> /* character macros */
- XX #include <string.h> /* string functions */
- XX #include "p2c.h"
- XX #include "ktypes.h" /* keyword type definitions */
- XX
- XX boolean WasSemi; /* kludge to avoid duplicating semicolons */
- XX
- XX /* Change these translations to fit your desires, but the Pascal names must
- XX be written in lower case and must be in alphabetical order. If you include
- XX a C comment in your translation output as a HINT to the programmer, write
- XX it in CAPITALs, else write the comment in lower case, eh?
- XX */
- XX
- XX wnode xlate[] = {
- XX {T_ZIP, "and", "&&" },
- XX {T_ARRAY, "array", "" }, /* see parseTypeDecl */
- XX {T_BEGIN, "begin", "{" },
- XX {T_ZIP, "boolean", "boolean"},
- XX {T_ZIP, "byte", "char" }, /* Turbo */
- XX {T_CASE, "case", "switch"},
- XX {T_CONST, "const", "/* CONST */"},
- XX {T_ZIP, "div", "/" },
- XX {T_ZIP, "do", ")" },
- XX {T_ZIP, "downto", ";/*DOWNTO*/"},
- XX {T_ZIP, "else", "; else"},
- XX {T_END, "end", "}" },
- XX {T_ZIP, "false", "FALSE" },
- XX {T_FILE, "file", "" }, /* see parseTypeDecl() */
- XX {T_ZIP, "for", "for (" },
- XX {T_FORWARD, "forward", "" },
- XX {T_FUNC, "function", "" }, /* see parseProcedure() */
- XX {T_ZIP, "if", "if (" },
- XX {T_ZIP, "implementation", "/* private (static) section */"},
- XX {T_ZIP, "input", "stdin" },
- XX {T_ZIP, "integer", "int" },
- XX {T_ZIP, "interface", "/* exported symbol section */"},
- XX {T_ZIP, "ioresult", "errno" }, /* UCSD, Turbo */
- XX {T_LABEL, "label", "" }, /* see parseLabel() */
- XX {T_ZIP, "mod", "%" },
- XX {T_ZIP, "not", "!" },
- XX {T_OF, "of", "" }, /* see parseTypeDecl() */
- XX {T_ZIP, "or", "||" },
- XX {T_ZIP, "output", "stdout"},
- XX {T_ZIP, "packed", "/* PACKED */"},
- XX {T_PROC, "procedure", "void" }, /* see parseProcedure() */
- XX {T_ZIP, "program", "main" },
- XX {T_ZIP, "read", "scanf" },
- XX {T_ZIP, "readln", "/*LINE*/scanf"},/* hint - read end-of-line */
- XX {T_ZIP, "real", "double"}, /* or "float" */
- XX {T_RECORD, "record", "" }, /* see parseTypeDecl() */
- XX {T_ZIP, "repeat", "do {" },
- XX {T_STRINGTYPE,"string", "" }, /* UCSD, Turbo string type */
- XX {T_ZIP, "text", "FILE *"}, /* UCSD, Turbo file type */
- XX {T_ZIP, "then", ")" },
- XX {T_ZIP, "to", ";" },
- XX {T_ZIP, "true", "TRUE" },
- XX {T_TYPE, "type", "" }, /* see parseType() */
- XX {T_ZIP, "until", "} until ("},
- XX {T_ZIP, "uses", "/* USES */\n#include"},
- XX {T_VAR, "var", "/* VAR */"}, /* see parseProc, parseVar() */
- XX {T_ZIP, "while", "while ("},
- XX {T_ZIP, "with", "/* WITH */"}, /*hint-set pointer to struct*/
- XX {T_ZIP, "write", "printf"},
- XX {T_ZIP, "writeln", "/*LINE*/printf"},/* hint - write newline */
- XX {T_ZIP, "", "" } /* marks end of xlate table */
- XX };
- XX
- XX wnode theend = {T_ZIP, "", ""};
- XX
- XX wnode *hash[26]; /* quick index into the translation array */
- XX
- XX /* Fill in the quick index ("hash") array
- XX */
- XX void init_hash()
- XX {
- XX int ch, cmp;
- XX wnode *nptr = xlate;
- XX
- XX for (ch='a'; ch<='z'; ch++) {
- XX while (nptr->pname[0] && (cmp = ch - *nptr->pname) > 0)
- XX nptr++;
- XX hash[ch-'a'] = (cmp==0) ? nptr : &theend;
- XX }
- XX }
- XX
- XX
- XX /* compare two strings without regard to case,
- XX the equivalent of this function may already be in your C library
- XX Used to fail on Suns because it used tolower on lowercase chars...
- XX Assumes second argument already lowercase.
- XX */
- XX int strcmpi(s1,s2)
- XX register char *s1, *s2;
- XX {
- XX register char c1;
- XX
- XX while ((c1= *s1++) && *s2) { /* get char, advance ptr */
- XX if (isupper(c1)) c1 = tolower(c1);
- XX if (c1 != *s2) break;
- XX s2++;
- XX }
- XX return(c1 - *s2);
- XX }
- XX
- XX
- XX /* Pass an identifier through the translation table; return its
- XX keyword type. Translated keyword left in same buffer.
- XX */
- XX int
- XX translate(word)
- XX register char *word;
- XX {
- XX register wnode *xptr;
- XX int nomatch;
- XX int c;
- XX
- XX c = *word;
- XX if (isalpha(c)) {
- XX if (isupper(c)) c=tolower(c);
- XX xptr = hash[c - 'a'];
- XX while ( xptr->pname[0] && (nomatch = strcmpi(word,xptr->pname)) > 0 )
- XX xptr++;
- XX if (!nomatch) {
- XX word[0]=0;
- XX if (!WasSemi && xptr->ktype == T_END)
- XX strcpy(word, ";");
- XX strcat(word, xptr->cname);
- XX return(xptr->ktype);
- XX }
- XX }
- XX return(T_ZIP);
- XX }
- XX
- XX #define Q_NOQUOTE 1
- XX #define Q_ONEQUOTE 2
- XX #define Q_DONE 3
- XX #define Q_ERR 4
- XX
- XX #define Q_C_ESCAPES FALSE /* Set true if your Pascal knows backslashes */
- XX
- XX /*---- parseQuotedString -------------------------------------------------
- XX Accepts Pascal quoted string from stdin, converts to C quoted string, and
- XX places in buf.
- XX Examples:
- XX 'hi' -> "hi" 'hi''' -> "hi'" 'hi''''' -> "hi''"
- XX '' -> "" '''' -> "'" '''''' -> "''"
- XX ''hi' -> ERROR '''hi' -> "'hi" '''''hi' -> "''hi"
- XX 'I''m' -> "I'm"
- XX Double quotes and backslashes are preceded with backslashes, except that
- XX if Q_C_ESCAPES is TRUE, backslashes are left naked.
- XX --------------------------------------------------------------------------*/
- XX void
- XX parseQuotedString(buf)
- XX char *buf;
- XX {
- XX register char c;
- XX register char *letter=buf;
- XX int qstate;
- XX
- XX *letter++ = '"';
- XX qstate = Q_NOQUOTE;
- XX while (qstate < Q_DONE) {
- XX switch (c=getchar()) {
- XX case '\'':
- XX switch (qstate) {
- XX case Q_NOQUOTE:
- XX qstate = Q_ONEQUOTE; break;
- XX case Q_ONEQUOTE:
- XX *letter++ = c; qstate = Q_NOQUOTE; break;
- XX }
- XX break;
- XX case EOF:
- XX case '\n':
- XX qstate= (qstate==Q_ONEQUOTE) ? Q_DONE : Q_ERR;
- XX ungetc(c,stdin);
- XX break;
- XX default:
- XX switch (qstate) {
- XX case Q_ONEQUOTE:
- XX ungetc(c,stdin); qstate = Q_DONE; break;
- XX case Q_NOQUOTE:
- XX if (c=='\\' && !Q_C_ESCAPES) *letter++ = c;
- XX if (c=='"') *letter++ = '\\';
- XX *letter++ = c;
- XX break;
- XX }
- XX }
- XX }
- XX *letter++ = '"';
- XX *letter++ = '\0';
- XX if (qstate == Q_ERR) {
- XX fprintf(stderr,"Newline in string constant: %s\n",buf);
- XX fprintf(stdout," %c*** \\n IN STRING ***%c ",
- XX '/', buf, '/');
- XX }
- XX }
- XX
- XX void
- XX getTok()
- XX {
- XX register char *letter = cTok.str;
- XX register char *sEnd = letter + MAXTOKLEN-3;
- XX register int c;
- XX
- XX c = getchar();
- XX if (isalnum(c)) {
- XX while (c != EOF && isalnum(c)) {
- XX *letter++ = c;
- XX c = getchar();
- XX }
- XX ungetc(c,stdin);
- XX *letter++ = 0;
- XX cTok.kind = translate(cTok.str);
- XX } else {
- XX switch(c) {
- XX case '\n': /* newline */
- XX case 0x20: /* space */
- XX case 0x9: /* tab */
- XX do /* Gather a string of blank space into one token */
- XX *letter++ = c;
- XX while ((c=getchar()) != EOF && isspace(c));
- XX ungetc(c, stdin);
- XX *letter++ = '\0';
- XX cTok.kind = T_SPACE;
- XX break;
- XX case '\'': /* Quoted String */
- XX parseQuotedString(cTok.str);
- XX cTok.kind = T_STRING;
- XX break;
- XX case '{' : /* Curly Comment */
- XX *letter++='/';
- XX *letter++='*';
- XX while ((c=getchar()) != EOF && c!='}' && letter!=sEnd)
- XX *letter++ = c;
- XX if (letter == sEnd) {
- XX printf("/***ERROR: Comment too long (sorry) ***/");
- XX while ((c=getchar()) != EOF && c!='}')
- XX ;
- XX }
- XX strcpy(letter, "*/");
- XX cTok.kind = T_COMMENT;
- XX break;
- XX case '(' :
- XX if ((c=getchar())!='*') { /* Parenthesis */
- XX ungetc(c,stdin);
- XX strcpy(letter, "(");
- XX cTok.kind = T_LPAREN;
- XX } else {
- XX register int lastc = '\0'; /* (* Comment *) */
- XX *letter++='/';
- XX *letter++='*';
- XX while ((c=getchar())!=EOF && !(c==')' && lastc == '*') &&
- XX letter != sEnd) {
- XX lastc = c;
- XX *letter++ = c;
- XX }
- XX if (letter == sEnd) {
- XX printf("/***ERROR: Comment too long (sorry) ***/");
- XX while ((c=getchar())!=EOF && !(c==')' && lastc == '*'))
- XX lastc = c;
- XX }
- XX strcpy(letter, "/"); /* * already there! */
- XX cTok.kind = T_COMMENT;
- XX }
- XX break;
- XX case ')' :
- XX strcpy(letter, ")");
- XX cTok.kind = T_RPAREN;
- XX break;
- XX case ':' :
- XX if ((c=getchar())=='=') { /* Assignment */
- XX strcpy(letter, "=");
- XX cTok.kind = T_ASSIGN;
- XX } else { /* Colon */
- XX ungetc(c,stdin);
- XX strcpy(letter, ":");
- XX cTok.kind = T_COLON;
- XX }
- XX break;
- XX case '=':
- XX strcpy(letter, "=="); /* Might be equality test...*/
- XX cTok.kind = T_EQUALS; /* depends on parse state */
- XX break;
- XX case '<' :
- XX switch (c=getchar()) {
- XX case '>':
- XX strcpy(letter, "!=");
- XX break;
- XX case '=':
- XX strcpy(letter, "<=");
- XX break;
- XX default :
- XX ungetc(c,stdin);
- XX strcpy(letter,"<");
- XX }
- XX cTok.kind = T_COMPARE;
- XX break;
- XX case '>' :
- XX if ((c=getchar()) == '=')
- XX strcpy(letter, ">=");
- XX else {
- XX ungetc(c,stdin);
- XX strcpy(letter, ">");
- XX }
- XX cTok.kind = T_COMPARE;
- XX break;
- XX case '^' :
- XX if ((c=getchar()) == '.') { /* perhaps we should skip blanks? */
- XX strcpy(letter, "->");
- XX cTok.kind = T_STRUCTMEMBER;
- XX } else {
- XX ungetc(c,stdin);
- XX strcpy(letter, "[0]"); /* '*' would have to go in front */
- XX cTok.kind = T_DEREF;
- XX }
- XX break;
- XX case '$' : /* Turbo Pascal extension */
- XX strcpy(letter, "0x");
- XX cTok.kind = T_ZIP;
- XX break;
- XX case ';' : /* Semicolon- translation depends on */
- XX strcpy(letter, ";"); /* parse state... */
- XX cTok.kind = T_SEMI;
- XX break;
- XX case '.':
- XX if ((c=getchar()) == '.') {
- XX cTok.kind = T_RANGE;
- XX letter[0]=0;
- XX } else {
- XX ungetc(c,stdin);
- XX strcpy(letter, ".");
- XX cTok.kind = T_ZIP;
- XX }
- XX break;
- XX case '[':
- XX *letter++ = c; *letter = '\0';
- XX cTok.kind = T_LBRACKET;
- XX break;
- XX case ']':
- XX *letter++ = c; *letter = '\0';
- XX cTok.kind = T_RBRACKET;
- XX break;
- XX case ',':
- XX *letter++ = c; *letter = '\0';
- XX cTok.kind = T_COMMA;
- XX break;
- XX case EOF: /* end of file */
- XX cTok.kind = T_EOF;
- XX break;
- XX default:
- XX *letter++ = c; /* Pass unknown chars thru as tokens */
- XX *letter = '\0';
- XX cTok.kind = T_ZIP;
- XX }
- XX }
- XX }
- XX
- XX main(argc, argv)
- XX int argc;
- XX char **argv;
- XX {
- XX int debug;
- XX
- XX debug = (argc > 1);
- XX init_hash();
- XX WasSemi = FALSE;
- XX
- XX getTok();
- XX do {
- XX switch(cTok.kind) {
- XX case T_VAR:
- XX parseVar();
- XX break;
- XX case T_PROC:
- XX case T_FUNC:
- XX parseProcedure();
- XX break;
- XX case T_LABEL:
- XX parseLabel();
- XX break;
- XX case T_TYPE:
- XX parseType();
- XX break;
- XX default:
- XX if (debug)
- XX printf("'%s' %d\n", cTok.str, cTok.kind);
- XX else { /* fancy stuff to avoid duplicating semicolons */
- XX if (cTok.kind != T_SEMI || !WasSemi)
- XX fputs(cTok.str, stdout);
- XX if (cTok.kind != T_SPACE && cTok.kind != T_COMMENT)
- XX WasSemi = (cTok.kind == T_SEMI);
- XX }
- XX getTok();
- XX }
- XX } while (cTok.kind != T_EOF);
- XX }
- XX
- XXX_EOF_XXX
- if test 10964 -ne "`wc -c < p2c.c`"
- then
- echo 'shar: transmission error on "p2c.c"'
- fi
- echo 'shar: extracting "proc.c" (14091 characters)'
- sed 's/^XX //' > proc.c << 'XXX_EOF_XXX'
- XX /*--- proc.c -------------------------------------------------------------
- XX Procedure, type, variable, and label parsing routines for the Pascal to C
- XX translator.
- XX 3/25/87 Daniel Kegel (seismo!rochester!srs!dan)
- XX --------------------------------------------------------------------------*/
- XX #include <stdio.h>
- XX #include <string.h>
- XX #include "p2c.h"
- XX #include "ktypes.h" /* keyword type definitions */
- XX
- XX #define SLEN 80
- XX typedef char sstr[SLEN+1]; /* short string */
- XX #define PLEN 1024
- XX typedef char pstr[PLEN+1]; /* long string */
- XX
- XX /* pgroup is used in parseProcedure to store the procedure's parameters */
- XX struct pgroup {
- XX sstr pclass; /* VAR or empty */
- XX sstr ptype; /* what type all these guys are */
- XX pstr params; /* identifiers separated by commas and space */
- XX };
- XX
- XX boolean
- XX isSectionKeyword(k)
- XX register int k;
- XX {
- XX return(k==T_CONST||k==T_TYPE||k==T_VAR||k==T_PROC||k==T_FUNC||k==T_BEGIN);
- XX }
- XX
- XX /*--- skipSpace ---------------------------------------------------------
- XX Accepts and throws away space and comment tokens.
- XX ------------------------------------------------------------------------*/
- XX void
- XX skipSpace()
- XX {
- XX do
- XX getTok();
- XX while (cTok.kind == T_SPACE || cTok.kind == T_COMMENT);
- XX if (cTok.kind == T_EOF) {
- XX printf("\n/***# EOF ***/\n");
- XX fflush(stdout);
- XX exit(1);
- XX }
- XX }
- XX
- XX /*--- parseSpace ---------------------------------------------------------
- XX Accepts and prints space and comment tokens.
- XX ------------------------------------------------------------------------*/
- XX void
- XX parseSpace()
- XX {
- XX do {
- XX getTok();
- XX if (cTok.kind == T_SPACE || cTok.kind == T_COMMENT)
- XX fputs(cTok.str, stdout);
- XX } while (cTok.kind == T_SPACE || cTok.kind == T_COMMENT);
- XX if (cTok.kind == T_EOF) {
- XX printf("\n/***# EOF ***/\n");
- XX fflush(stdout);
- XX exit(1);
- XX }
- XX }
- XX
- XX void
- XX expected(s)
- XX char *s;
- XX {
- XX printf("/***# Expected %s ***/", s);
- XX fflush(stdout);
- XX }
- XX
- XX /*---- expectThing -------------------------------------------------------
- XX Makes sure current token is of desired type, else prints error message.
- XX ------------------------------------------------------------------------*/
- XX
- XX void
- XX expectThing(s, k)
- XX char *s;
- XX {
- XX if (cTok.kind != k)
- XX expected(s);
- XX }
- XX
- XX /*---- getThing -------------------------------------------------------
- XX Gets next nonblank token, makes sure it is desired type, else prints error
- XX message.
- XX ------------------------------------------------------------------------*/
- XX void
- XX getThing(s, k)
- XX char *s;
- XX int k;
- XX {
- XX skipSpace();
- XX expectThing(s, k);
- XX }
- XX
- XX /*---- parseVarDec ----------------------------------------------------
- XX Translates one (possibly multi-)variable declaration.
- XX Works for complex types, but can't be used to parse procedure parameters.
- XX On entry, cTok is first token in identifier list.
- XX On exit, cTok is the token after the type- probably T_SEMI.
- XX Semicolon is translated, too.
- XX ----------------------------------------------------------------------*/
- XX
- XX struct ident { /* Used to save variable declaration body */
- XX char *str; /* until type is known */
- XX int kind;
- XX };
- XX #define MAXIDENTS 132 /* allows about 32 variables */
- XX
- XX void
- XX parseVarDec()
- XX {
- XX void parseTypeDecl(); /* forward declaration */
- XX sstr indir, index;
- XX struct ident idents[MAXIDENTS];
- XX int i, n;
- XX
- XX /* Get identifiers, up to the colon that marks end of list */
- XX n=0;
- XX while (cTok.kind != T_COLON) {
- XX if (n == MAXIDENTS-1)
- XX printf("/***# Variable declaration too long ***/");
- XX if (n == MAXIDENTS) n--;
- XX idents[n].str = MALLOC(char, strlen(cTok.str));
- XX strcpy(idents[n].str, cTok.str);
- XX idents[n++].kind = cTok.kind;
- XX if (cTok.kind != T_ZIP && cTok.kind != T_COMMA
- XX && cTok.kind != T_SPACE && cTok.kind != T_COMMENT)
- XX expected(" (variable declaration) comma or identifier");
- XX getTok(); /* don't nuke spaces or comments */
- XX }
- XX
- XX /* Output any whitespace given before the type declaration */
- XX for (i=0; i<n&&(idents[i].kind==T_SPACE||idents[i].kind==T_COMMENT); i++){
- XX fputs(idents[i].str, stdout);
- XX free(idents[i].str);
- XX }
- XX
- XX /* Translate type specification */
- XX indir[0]=index[0]='\0';
- XX parseTypeDecl(indir, index);
- XX
- XX /* Output the identifiers, with appropriate modification for
- XX ptr & array types */
- XX putchar(' '); /* separate RECORD from first element...? */
- XX for (; i<n; i++) {
- XX if (idents[i].kind == T_ZIP && indir[0]!='\0')
- XX fputs(indir, stdout);
- XX fputs(idents[i].str, stdout);
- XX if (idents[i].kind == T_ZIP && index[0]!='\0')
- XX fputs(index, stdout);
- XX free(idents[i].str);
- XX }
- XX if (cTok.kind == T_SEMI)
- XX putchar(';');
- XX }
- XX
- XX /*---- parseProcedure -------------------------------------------------------
- XX On entry, cTok is "PROCEDURE" or "FUNCTION".
- XX On exit, cTok is the token after the semicolon after the function header.
- XX
- XX Turns declarations like
- XX foo(a:int; b:int)
- XX into
- XX foo(a,b)
- XX int a;
- XX int b;
- XX
- XX Breaks up function declarations into
- XX 1. name
- XX 2. parameter declarations
- XX 3. type (or 'void', if procedure)
- XX Breaks up parameter declarations into an array of pgroups.
- XX ----------------------------------------------------------------------------*/
- XX void
- XX parseProcedure()
- XX {
- XX boolean isProcedure;
- XX boolean isForward;
- XX sstr fnName;
- XX sstr fnType;
- XX struct pgroup *pgps=NULL;
- XX int i, npgp=0;
- XX register struct pgroup *p;
- XX
- XX /* Remember whether is returns a value or not */
- XX isProcedure = (cTok.kind == T_PROC);
- XX /* Get function or procedure name, skipping space & comments */
- XX getThing("function name", T_ZIP);
- XX strcpy(fnName, cTok.str);
- XX skipSpace(); /* eat the function name */
- XX /* Get open paren (or semicolon of a parameterless procedure or fn) */
- XX if (cTok.kind == T_LPAREN) {
- XX do {
- XX register char *cp;
- XX /* Allocate and initialize another parameter group */
- XX if (npgp++ == 0) pgps=MALLOC(struct pgroup, 1);
- XX else pgps = REALLOC(pgps, struct pgroup, npgp);
- XX p = pgps + npgp-1;
- XX p->pclass[0] = p->ptype[0] = '\0';
- XX
- XX /* Get optional class keyword */
- XX skipSpace(); /* eat the paren or semicolon */
- XX if (cTok.kind == T_VAR) {
- XX strcpy(p->pclass, cTok.str);
- XX skipSpace(); /* eat the class keyword */
- XX }
- XX /* Get identifier list & type */
- XX cp = p->params;
- XX /* Get identifiers, up to the colon that marks end of list */
- XX while (cTok.kind != T_COLON) {
- XX register char *cq=cTok.str;
- XX if (cTok.kind != T_ZIP && cTok.kind != T_COMMA)
- XX expected(" (variable declaration) comma or identifier");
- XX while (*cp++ = *cq++)
- XX ;
- XX cp--;
- XX skipSpace();
- XX }
- XX *cp = 0;
- XX
- XX /* Get type specifier, which may be many tokens. Primitive. */
- XX skipSpace();
- XX p->ptype[0]=0;
- XX do {
- XX strcat(p->ptype, cTok.str);
- XX skipSpace();
- XX } while (cTok.kind != T_SEMI && cTok.kind != T_RPAREN);
- XX } while (cTok.kind == T_SEMI);
- XX expectThing(") at end of param list", T_RPAREN);
- XX skipSpace();
- XX }
- XX /* Get return type */
- XX if (isProcedure) {
- XX strcpy(fnType, "void");
- XX } else {
- XX expectThing(":", T_COLON);
- XX getThing("function type", T_ZIP);
- XX strcpy(fnType, cTok.str);
- XX skipSpace();
- XX }
- XX expectThing("semicolon", T_SEMI);
- XX /* Get optional FORWARD keyword */
- XX skipSpace();
- XX if (isForward = (cTok.kind == T_FORWARD)) {
- XX getThing(";", T_SEMI);
- XX skipSpace();
- XX }
- XX
- XX /* Output the first part of the translated function declaration */
- XX printf("%s %s(", fnType, fnName);
- XX for (i=0, p=pgps; i++ < npgp; p++) {
- XX fputs(p->params, stdout);
- XX if (i<npgp) putchar(',');
- XX }
- XX putchar(')');
- XX if (isForward)
- XX puts(";");
- XX else {
- XX /* Output second part */
- XX putchar('\n');
- XX for (i=0, p=pgps; i++ < npgp; p++) {
- XX if (p->pclass[0])
- XX fputs(p->pclass, stdout); /* already xlated */
- XX printf("%s %s;\n", p->ptype, p->params);
- XX }
- XX }
- XX }
- XX
- XX /*--- convertArrayBound -----------------------------------------------------
- XX Given the upper bound of a Pascal array, append the C array size specification
- XX to the buffer tindex.
- XX Lower bounds are ignored, 'cause it's safe to do so, and impossibly difficult
- XX to handle.
- XX ----------------------------------------------------------------------------*/
- XX void
- XX convertArrayBound(s, tindex)
- XX char *s, *tindex;
- XX {
- XX sstr buf;
- XX int ubound;
- XX
- XX ubound = atoi(s);
- XX if (ubound == 0) {
- XX /* Probably symbolic */
- XX sprintf(buf, "[%s+1]", s);
- XX } else {
- XX if (ubound < 0)
- XX expected("positive upper bound");
- XX sprintf(buf, "[%d]", ubound+1);
- XX }
- XX strcat(tindex, buf);
- XX }
- XX
- XX /*---- parseTypeDecl -------------------------------------------------------
- XX Translates a type definition in place. Appends indirection & array subscrips,
- XX if any, to the buffers tindir and tindex.
- XX Never translates the semicolon- that is done in parseType.
- XX
- XX On entry, cTok is the token that made us expect to find a type
- XX (e.g. the colon in a variable declaration, or the equals in a type declaration,
- XX On exit, cTok is the token after the type, usually T_SEMI (but may be T_END
- XX in the last declaration in a RECORD).
- XX
- XX Pascal (or at least, Turbo Pascal) doesn't allow constructions like
- XX a = ^array [0..10] of integer;
- XX rather, it forces you to define the base type, too:
- XX b = array [0..10] of integer;
- XX a = ^b;
- XX Thus any type definition can be unambiguously broken up into 2 parts:
- XX - the base type (which may be complex)
- XX - if pointer, how many levels of indirection
- XX else if array, how many indices the type has, with limits
- XX -----------------------------------------------------------------------*/
- XX void
- XX parseTypeDecl(tindir, tindex)
- XX char *tindir, *tindex; /* buffer to put * or [n] in */
- XX {
- XX skipSpace(); /* get initial token of type */
- XX
- XX switch (cTok.kind) {
- XX case T_DEREF: /* pointer type */
- XX strcat(tindir, "*");
- XX parseTypeDecl(tindir, tindex);
- XX break;
- XX case T_LPAREN: /* enumerated type */
- XX fputs("enum {", stdout);
- XX do {
- XX parseSpace();
- XX if (cTok.kind != T_RPAREN)
- XX fputs(cTok.str, stdout);
- XX } while (cTok.kind != T_RPAREN);
- XX getThing(";", T_SEMI);
- XX putchar('}');
- XX break;
- XX case T_ARRAY: /* array type */
- XX getThing("[", T_LBRACKET);
- XX do { /* Get all the dimensions */
- XX getThing("lower bound", T_ZIP); /* Ignore lower bound except */
- XX if (cTok.str[0] == '-') /* to make sure >= 0 */
- XX expected("non-negative lower bound");
- XX getThing("..", T_RANGE);
- XX getThing("upper bound", T_ZIP);
- XX convertArrayBound(cTok.str, tindex);
- XX skipSpace();
- XX } while (cTok.kind == T_COMMA);
- XX expectThing("]", T_RBRACKET);
- XX getThing("OF", T_OF);
- XX parseTypeDecl(tindir, tindex);
- XX break;
- XX case T_STRINGTYPE: /* Turbo (& UCSD?) string type */
- XX printf("char");
- XX skipSpace();
- XX if (cTok.kind != T_LPAREN && cTok.kind != T_LBRACKET)
- XX expected("[ or ( after STRING");
- XX getThing("string length", T_ZIP);
- XX convertArrayBound(cTok.str, tindex);
- XX skipSpace();
- XX if (cTok.kind != T_RPAREN && cTok.kind != T_RBRACKET)
- XX expected("] or ) after STRING[");
- XX getThing(";", T_SEMI);
- XX break;
- XX case T_FILE: /* file type - not supported in C */
- XX strcat(tindir, "*");
- XX printf("FILE /* OF "); /* show what it's a file of in the comment */
- XX do {
- XX skipSpace();
- XX if (cTok.kind != T_COMMENT); /* avoid nesting comments */
- XX fputs(cTok.str, stdout);
- XX } while (cTok.kind != T_SEMI);
- XX printf(" */ ");
- XX break;
- XX case T_RECORD: /* struct definition */
- XX printf("struct {");
- XX parseSpace(); /* eat RECORD */
- XX do {
- XX if (cTok.kind == T_CASE) {
- XX printf("/***# Sorry- variant records not supported\n\t");
- XX do {
- XX if (cTok.kind != T_COMMENT)
- XX fputs(cTok.str, stdout);
- XX getTok();
- XX } while (cTok.kind != T_END);
- XX printf(" ***/");
- XX break;
- XX }
- XX parseVarDec();
- XX if (cTok.kind == T_SEMI)
- XX parseSpace();
- XX else if (cTok.kind == T_END)
- XX putchar(';'); /* Pascal doesn't need ; but C does*/
- XX else if (cTok.kind != T_CASE)
- XX expected("Either semicolon or END");
- XX } while (cTok.kind != T_END);
- XX parseSpace(); /* eat the END, get the semi */
- XX printf("}");
- XX break;
- XX case T_ZIP: /* probably a type keyword like 'integer' */
- XX fputs(cTok.str, stdout);
- XX skipSpace(); /* eat the type, get the semi */
- XX break;
- XX default: /* unexpected */
- XX expected("type");
- XX }
- XX }
- XX
- XX /*---- parseVar -------------------------------------------------------
- XX Translates the VAR section of a program or procedure.
- XX
- XX On entry, cTok is "VAR".
- XX On exit, cTok is any section-starting keyword.
- XX Turns declarations like
- XX foo : ^integer;
- XX into
- XX int *foo;
- XX ----------------------------------------------------------------------------*/
- XX void
- XX parseVar()
- XX {
- XX getTok(); /* eat the VAR */
- XX do {
- XX parseVarDec();
- XX if (cTok.kind == T_SEMI)
- XX parseSpace();
- XX } while (!isSectionKeyword(cTok.kind));
- XX }
- XX
- XX /*---- parseType -----------------------------------------------------------
- XX Translates the TYPE section of a program or procedure.
- XX On entry, cTok is TYPE.
- XX On exit, cTok is any section-starting keyword.
- XX
- XX Turns declarations like
- XX foo = array [0..10, LO..HI] of integer;
- XX boo = record
- XX x : foo;
- XX y : ^foo
- XX end;
- XX
- XX into
- XX typedef integer foo[11][HI+1];
- XX typedef struct {
- XX foo x;
- XX foo *y;
- XX } boo;
- XX ---------------------------------------------------------------------------*/
- XX void
- XX parseType()
- XX {
- XX parseSpace();
- XX do {
- XX sstr typ;
- XX sstr tindir, tindex;
- XX expectThing("type identifier", T_ZIP);
- XX strcpy(typ, cTok.str);
- XX parseSpace();
- XX expectThing("=", T_EQUALS);
- XX printf("typedef ");
- XX tindir[0]=tindex[0]=0;
- XX parseTypeDecl(tindir, tindex);
- XX expectThing(";", T_SEMI);
- XX printf(" %s%s%s;", tindir, typ, tindex);
- XX parseSpace();
- XX } while (!isSectionKeyword(cTok.kind));
- XX }
- XX
- XX /*---- parseLabel -------------------------------------------------------
- XX On entry, cTok is "LABEL".
- XX On exit, cTok is whatever follows the semicolon.
- XX
- XX Turns declarations like
- XX LABEL foo, goo;
- XX into
- XX / * LABEL foo, goo; * /
- XX ----------------------------------------------------------------------------*/
- XX void
- XX parseLabel()
- XX {
- XX skipSpace(); /* eat the LABEL */
- XX printf("/* LABEL ");
- XX /* Get identifiers, up to the semicolon that marks end of list */
- XX while (cTok.kind != T_SEMI) {
- XX if (cTok.kind != T_ZIP && cTok.kind != T_COMMA)
- XX expected(" (label declaration) comma or identifier");
- XX fputs(cTok.str, stdout);
- XX skipSpace();
- XX }
- XX /* Get semicolon without wiping out trailing space */
- XX getTok();
- XX fputs("; */", stdout);
- XX }
- XXX_EOF_XXX
- if test 14091 -ne "`wc -c < proc.c`"
- then
- echo 'shar: transmission error on "proc.c"'
- fi
- echo 'shar: extracting "doalloc.c" (672 characters)'
- sed 's/^XX //' > doalloc.c << 'XXX_EOF_XXX'
- XX /* doalloc.c: memory allocations which exit upon error */
- XX
- XX #include <stdio.h>
- XX #ifndef NULL
- XX #define NULL ((char *) 0)
- XX #endif
- XX
- XX /* act like calloc, but return only if no error */
- XX char *DoRealloc(ptr,size)
- XX char *ptr;
- XX unsigned size;
- XX {
- XX extern char *realloc();
- XX char *p;
- XX
- XX if ((p=realloc(ptr, size)) == NULL) {
- XX fprintf(stderr, "memory allocation (realloc) error");
- XX exit(1);
- XX }
- XX return (p);
- XX }
- XX
- XX
- XX /* act like malloc, but return only if no error */
- XX char *DoMalloc(size)
- XX unsigned size;
- XX {
- XX extern char *malloc();
- XX char *p;
- XX
- XX if ((p=malloc(size)) == NULL) {
- XX fprintf(stderr, "memory allocation (malloc) error");
- XX exit(1);
- XX }
- XX return (p);
- XX }
- XX
- XXX_EOF_XXX
- if test 672 -ne "`wc -c < doalloc.c`"
- then
- echo 'shar: transmission error on "doalloc.c"'
- fi
-
-
-