home *** CD-ROM | disk | FTP | other *** search
- /* Programm zum Eliminieren von defined(...)-Ausdrⁿcken in #if -
- PrΣprozessor-Anweisungen in C-Programmen, fⁿr VAX C.
- Bruno Haible 26.2.1993
- */
-
- /* Methode:
- Erkenne die PrΣprozessor-Anweisung #if.
- Der folgende Ausdruck wird in seine Bestandteile zerlegt. Liefert einen
- Syntaxbaum. Fⁿr jeden Teilbaum, der einen defined(...)-Ausdruck enthΣlt,
- wird eine temporΣre PrΣprozessor-Variable eingefⁿhrt.
- Die Ausgabe besteht aus "#undef tmp_var_xx" zu Beginn, dann kurzen
- #if's bzw. #ifdef's fⁿr jeden nΣchstumfangreicheren Teilbaum.
-
- Dieser PrΣprozessor setzt deelif.d voraus.
- */
-
- /* Noch zu tun: #line-Anweisungen erkennen und selber emittieren. */
-
- #define local static
- #define global
- #define var
- #define loop while (1)
- #define until(exp) while (!(exp))
- typedef unsigned char uintB;
- typedef unsigned short uintW;
- typedef unsigned long uintL;
- typedef int boolean;
- #define FALSE 0
- #define TRUE 1
-
- #if defined(__TURBOC__) || defined(__GO32__) || defined(__WATCOMC__)
- #define STDC_HEADERS 1
- #else
- #if defined(unix) || defined(__unix)
- #include "unixconf.h"
- #endif
- #endif
- #ifdef STDC_HEADERS
- #include <stdlib.h> /* fⁿr malloc(), realloc(), exit() */
- #endif
-
- #include <stdio.h>
- #include <setjmp.h> /* fⁿr setjmp(), longjmp() */
-
- /* Einfache Ein-/Ausgaben: */
-
- local var FILE* infile;
- local var FILE* outfile;
-
- #define get() getc(infile)
- #define put(x) putc(x,outfile)
- #define puts(x) fputs(x,outfile)
-
- #define NL 10
-
- /* Es wird gebuffert: */
-
- local char* buffer;
- local uintL bufsize;
- local char* bufend;
-
- local void putbuffer(c)
- var char c;
- { if (bufend == buffer+bufsize)
- { buffer = realloc(buffer,2*bufsize);
- bufend = buffer+bufsize;
- bufsize = 2*bufsize;
- }
- *bufend++ = c;
- }
-
- /* Syntax-Analyse im Buffer zwischen buffer und bufend: */
-
- local boolean whitespacep(c)
- var char c;
- { return (c==' ') || (c=='\v') || (c=='\t'); }
-
- /* Beenden der Analyse */
- local jmp_buf abort_line_jmpbuf;
- local void abort_line()
- { longjmp(abort_line_jmpbuf,1); }
-
- /* Syntax konstanter C-Expressions:
- 16 name
- 16 defined(...)
- 16 f(...)
- 14 ~ ...
- 14 ! ...
- 14 - ...
- 13L * / %
- 12L + -
- 11L << >>
- 10L < > <= >=
- 9L == !=
- 8L &
- 7L ^
- 6L |
- 5L &&
- 4L ||
- 3R ? :
- 1L ,
- */
-
- /* Lexikalische Analyse: */
- typedef enum { TT_ident, /* identifier */
- TT_number, /* number */
- TT_lparen, /* ( */
- TT_rparen, /* ) */
- TT_plus, /* + */
- TT_minus, /* - */
- TT_mul, /* * */
- TT_div, /* / */
- TT_mod, /* % */
- TT_lshift, /* << */
- TT_rshift, /* >> */
- TT_less, /* < */
- TT_greater, /* > */
- TT_less_equal, /* <= */
- TT_greater_equal, /* >= */
- TT_equal, /* == */
- TT_not_equal, /* != */
- TT_not, /* ~ */
- TT_and, /* & */
- TT_or, /* | */
- TT_xor, /* ^ */
- TT_lognot, /* ! */
- TT_logand, /* && */
- TT_logor, /* || */
- TT_if, /* ? */
- TT_else, /* : */
- TT_comma, /* , */
- TT_eof
- }
- tokentype;
- typedef struct { tokentype type; /* Typ */
- char* startptr; char* endptr; /* Pointer in den Buffer */
- }
- token_;
- typedef token_* Token;
- local token_ token_eof = {TT_eof,NULL,NULL};
- #define Token_EOF &token_eof
-
- local Token make_token(type,startptr,endptr)
- var tokentype type;
- var char* startptr;
- var char* endptr;
- { var Token token = malloc(sizeof(token_));
- token->type = type;
- token->startptr = startptr;
- token->endptr = endptr;
- return token;
- }
-
- local void free_token(token)
- var Token token;
- { free(token); }
-
- /* Pointer in den Buffer, so weit die lexikalische Analyse gelangt ist. */
- local char* bufptr;
-
- local int peek_char()
- { if (bufptr==bufend) return EOF; else return *bufptr; }
-
- local int next_char()
- { if (bufptr==bufend) return EOF; else return *bufptr++; }
-
- /* Holt das nΣchste Token, rⁿckt bufptr weiter: */
- local Token nexttoken()
- { var int c;
- restart:
- {var char* startptr = bufptr;
- c = next_char();
- switch (c)
- { case ' ': case '\v': case '\t':
- goto restart; /* Whitespace ⁿberlesen */
- case '/':
- if (peek_char() == '*')
- /* Kommentar */
- { next_char();
- loop
- { c = next_char();
- if (c==EOF) { fprintf(stderr,"Unbeendeter Kommentar\n"); abort_line(); }
- if ((c=='*') && (peek_char()=='/')) { next_char(); break; }
- }
- goto restart;
- }
- else
- return make_token(TT_div,startptr,bufptr);
- case '*':
- if (peek_char() == '/')
- /* illegales Kommentar-Ende */
- { fprintf(stderr,"Kommentar-Ende au▀erhalb Kommentar\n"); abort_line(); }
- return make_token(TT_mul,startptr,bufptr);
- case '(': return make_token(TT_lparen,startptr,bufptr);
- case ')': return make_token(TT_rparen,startptr,bufptr);
- case '+': return make_token(TT_plus,startptr,bufptr);
- case '-': return make_token(TT_minus,startptr,bufptr);
- case '%': return make_token(TT_mod,startptr,bufptr);
- case '<':
- c = peek_char();
- if (c=='<') { next_char(); return make_token(TT_lshift,startptr,bufptr); }
- if (c=='=') { next_char(); return make_token(TT_less_equal,startptr,bufptr); }
- return make_token(TT_less,startptr,bufptr);
- case '>':
- c = peek_char();
- if (c=='>') { next_char(); return make_token(TT_rshift,startptr,bufptr); }
- if (c=='=') { next_char(); return make_token(TT_greater_equal,startptr,bufptr); }
- return make_token(TT_greater,startptr,bufptr);
- case '=':
- c = peek_char();
- if (c=='=') { next_char(); return make_token(TT_equal,startptr,bufptr); }
- abort_line();
- case '~': return make_token(TT_not,startptr,bufptr);
- case '!':
- c = peek_char();
- if (c=='=') { next_char(); return make_token(TT_not_equal,startptr,bufptr); }
- return make_token(TT_lognot,startptr,bufptr);
- case '&':
- c = peek_char();
- if (c=='&') { next_char(); return make_token(TT_logand,startptr,bufptr); }
- return make_token(TT_and,startptr,bufptr);
- case '|':
- c = peek_char();
- if (c=='|') { next_char(); return make_token(TT_logor,startptr,bufptr); }
- return make_token(TT_or,startptr,bufptr);
- case '^': return make_token(TT_xor,startptr,bufptr);
- case '?': return make_token(TT_if,startptr,bufptr);
- case ':': return make_token(TT_else,startptr,bufptr);
- case ',': return make_token(TT_comma,startptr,bufptr);
- case '.':
- c = peek_char();
- if (!(((c>='0') && (c<='9')) || (c=='.'))) { abort_line(); }
- case '0': case '1': case '2': case '3': case '4':
- case '5': case '6': case '7': case '8': case '9':
- /* Zahl. Weiterlesen, solange alphanumerisches Zeichen oder '.': */
- loop
- { c = peek_char();
- if (((c>='0') && (c<='9'))
- || ((c>='A') && (c<='Z')) || ((c>='a') && (c<='z'))
- || (c=='.')
- )
- { next_char(); }
- else
- break;
- }
- return make_token(TT_number,startptr,bufptr);
- case '\'':
- /* Character-Konstante */
- loop
- { c = next_char();
- if (c==EOF) { fprintf(stderr,"Unbeendete Character-Konstante"); abort_line(); }
- if (c=='\'') break;
- if (c=='\\') { c = next_char(); }
- }
- return make_token(TT_number,startptr,bufptr);
- case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
- case 'G': case 'H': case 'I': case 'J': case 'K': case 'L':
- case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
- case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
- case 'Y': case 'Z':
- case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
- case 'g': case 'h': case 'i': case 'j': case 'k': case 'l':
- case 'm': case 'n': case 'o': case 'p': case 'q': case 'r':
- case 's': case 't': case 'u': case 'v': case 'w': case 'x':
- case 'y': case 'z':
- case '_': case '$':
- /* Identifier. alles alphanumerische ⁿberlesen. */
- loop
- { c = peek_char();
- if ( ((c>='0') && (c<='9'))
- || ((c>='A') && (c<='Z')) || ((c>='a') && (c<='z'))
- || (c=='_') || (c=='$')
- )
- { next_char(); }
- else
- break;
- }
- return make_token(TT_ident,startptr,bufptr);
- case EOF:
- return Token_EOF;
- default:
- abort_line();
- }
- }}
-
- local void print_token(token)
- var Token token;
- { var char* ptr = token->startptr;
- var char* endptr = token->endptr;
- until (ptr==endptr) { char c = *ptr++; put(c); }
- }
-
- /* Ausdrucks-Analyse: */
- typedef enum { ET_literal, /* identifier, number, literal */
- ET_paren, /* (expr) */
- ET_call, /* expr1(expr2) */
- ET_unary, /* ~ expr, ! expr, - expr */
- ET_mulop, /* expr1 * expr2, expr1 / expr2, expr1 % expr2 */
- ET_addop, /* expr1 + expr2, expr1 - expr2 */
- ET_shiftop, /* expr1 << expr2, expr1 >> expr2 */
- ET_cmpop, /* expr1 < expr2, expr1 > expr2 etc. */
- ET_relop, /* expr1 == expr2, expr1 != expr2 */
- ET_andop, /* expr1 & expr2 */
- ET_xorop, /* expr1 ^ expr2 */
- ET_orop, /* expr1 | expr2 */
- ET_logandop, /* expr1 && expr2 */
- ET_logorop, /* expr1 || expr2 */
- ET_condop, /* expr1 ? expr2 : expr3 */
- ET_seqop, /* expr1 , expr2 */
- ET_defined /* DEFINED_xxx */
- }
- exprtype;
- typedef struct expr_ * Expr;
- typedef struct expr_ { exprtype type; /* Typ */
- Token token1, token2;
- Expr expr1, expr2, expr3;
- uintL counter;
- }
- expr_;
-
- local Expr make_expr(type,token1,token2,expr1,expr2,expr3)
- var exprtype type;
- var Token token1;
- var Token token2;
- var Expr expr1;
- var Expr expr2;
- var Expr expr3;
- { var Expr expr = malloc(sizeof(expr_));
- expr->type = type;
- expr->token1 = token1;
- expr->token2 = token2;
- expr->expr1 = expr1;
- expr->expr2 = expr2;
- expr->expr3 = expr3;
- return expr;
- }
-
- local void free_expr(expr)
- var Expr expr;
- { if (expr->token1) free_token(expr->token1);
- if (expr->token2) free_token(expr->token2);
- if (expr->expr1) free_expr(expr->expr1);
- if (expr->expr2) free_expr(expr->expr2);
- if (expr->expr3) free_expr(expr->expr3);
- free(expr);
- }
-
- local Token last_token;
-
- local Token peek_token()
- { if (last_token) return last_token;
- return last_token = nexttoken(); /* Token_EOF bedeutet EOF */
- }
-
- local Token next_token()
- { if (last_token)
- { var Token result = last_token; last_token = NULL; return result; }
- return nexttoken(); /* Token_EOF bedeutet EOF */
- }
-
- local Expr parse_expr();
-
- local Expr parse_expr_16()
- { var Token token = next_token();
- switch (token->type)
- { case TT_ident:
- { var Expr expr = make_expr(ET_literal, token,NULL, NULL,NULL,NULL);
- var Token token2 = peek_token();
- if (token2->type==TT_lparen)
- { next_token();
- {var Expr expr2 = parse_expr();
- var Token token3 = next_token();
- if (!(token3->type==TT_rparen)) abort_line();
- return make_expr(ET_call, token2,token3, expr,expr2,NULL);
- }}
- else
- return expr;
- }
- case TT_number:
- return make_expr(ET_literal, token,NULL, NULL,NULL,NULL);
- case TT_lparen:
- { var Expr expr = parse_expr();
- var Token token2 = next_token();
- if (!(token2->type==TT_rparen)) abort_line();
- return make_expr(ET_paren, token,token2, expr,NULL,NULL);
- }
- default:
- abort_line();
- } }
-
- local Expr parse_expr_14()
- { var Token token = peek_token();
- switch (token->type)
- { case TT_not:
- case TT_lognot:
- case TT_minus:
- next_token();
- { var Expr expr = parse_expr_14();
- return make_expr(ET_unary, token,NULL, expr,NULL,NULL);
- }
- default:
- return parse_expr_16();
- } }
-
- local Expr parse_expr_13()
- { var Expr expr = parse_expr_14();
- loop
- { var Token token = peek_token();
- switch (token->type)
- { default:
- return expr;
- case TT_mul:
- case TT_div:
- case TT_mod:
- next_token();
- expr = make_expr(ET_mulop, token,NULL, expr,parse_expr_14(),NULL);
- } }
- }
-
- local Expr parse_expr_12()
- { var Expr expr = parse_expr_13();
- loop
- { var Token token = peek_token();
- switch (token->type)
- { default:
- return expr;
- case TT_plus:
- case TT_minus:
- next_token();
- expr = make_expr(ET_addop, token,NULL, expr,parse_expr_13(),NULL);
- } }
- }
-
- local Expr parse_expr_11()
- { var Expr expr = parse_expr_12();
- loop
- { var Token token = peek_token();
- switch (token->type)
- { default:
- return expr;
- case TT_lshift:
- case TT_rshift:
- next_token();
- expr = make_expr(ET_shiftop, token,NULL, expr,parse_expr_12(),NULL);
- } }
- }
-
- local Expr parse_expr_10()
- { var Expr expr = parse_expr_11();
- loop
- { var Token token = peek_token();
- switch (token->type)
- { default:
- return expr;
- case TT_less:
- case TT_greater:
- case TT_less_equal:
- case TT_greater_equal:
- next_token();
- expr = make_expr(ET_cmpop, token,NULL, expr,parse_expr_11(),NULL);
- } }
- }
-
- local Expr parse_expr_9()
- { var Expr expr = parse_expr_10();
- loop
- { var Token token = peek_token();
- switch (token->type)
- { default:
- return expr;
- case TT_equal:
- case TT_not_equal:
- next_token();
- expr = make_expr(ET_relop, token,NULL, expr,parse_expr_10(),NULL);
- } }
- }
-
- local Expr parse_expr_8()
- { var Expr expr = parse_expr_9();
- loop
- { var Token token = peek_token();
- switch (token->type)
- { default:
- return expr;
- case TT_and:
- next_token();
- expr = make_expr(ET_andop, token,NULL, expr,parse_expr_9(),NULL);
- } }
- }
-
- local Expr parse_expr_7()
- { var Expr expr = parse_expr_8();
- loop
- { var Token token = peek_token();
- switch (token->type)
- { default:
- return expr;
- case TT_xor:
- next_token();
- expr = make_expr(ET_xorop, token,NULL, expr,parse_expr_8(),NULL);
- } }
- }
-
- local Expr parse_expr_6()
- { var Expr expr = parse_expr_7();
- loop
- { var Token token = peek_token();
- switch (token->type)
- { default:
- return expr;
- case TT_or:
- next_token();
- expr = make_expr(ET_orop, token,NULL, expr,parse_expr_7(),NULL);
- } }
- }
-
- local Expr parse_expr_5()
- { var Expr expr = parse_expr_6();
- loop
- { var Token token = peek_token();
- switch (token->type)
- { default:
- return expr;
- case TT_logand:
- next_token();
- expr = make_expr(ET_logandop, token,NULL, expr,parse_expr_6(),NULL);
- } }
- }
-
- local Expr parse_expr_4()
- { var Expr expr = parse_expr_5();
- loop
- { var Token token = peek_token();
- switch (token->type)
- { default:
- return expr;
- case TT_logor:
- next_token();
- expr = make_expr(ET_logorop, token,NULL, expr,parse_expr_5(),NULL);
- } }
- }
-
- local Expr parse_expr_3()
- { var Expr expr = parse_expr_4();
- var Token token = peek_token();
- if (token->type==TT_if)
- { next_token();
- {var Expr expr2 = parse_expr_3();
- var Token token2 = next_token();
- if (!(token2->type==TT_else)) abort_line();
- return make_expr(ET_condop, token,token2, expr,expr2,parse_expr_3());
- }}
- else
- return expr;
- }
-
- local Expr parse_expr_1()
- { var Expr expr = parse_expr_3();
- loop
- { var Token token = peek_token();
- switch (token->type)
- { default:
- return expr;
- case TT_comma:
- next_token();
- expr = make_expr(ET_seqop, token,NULL, expr,parse_expr_3(),NULL);
- } }
- }
-
- local Expr parse_expr()
- { return parse_expr_1(); }
-
- /* Ausdruck ausgeben: */
- local void print_expr(expr)
- var Expr expr;
- { switch (expr->type)
- { case ET_literal:
- print_token(expr->token1); break;
- case ET_paren:
- print_token(expr->token1); print_expr(expr->expr1); print_token(expr->token2); break;
- case ET_call:
- print_expr(expr->expr1); print_token(expr->token1); print_expr(expr->expr2); print_token(expr->token2); break;
- case ET_unary:
- print_token(expr->token1); print_expr(expr->expr1); break;
- case ET_mulop:
- case ET_addop:
- case ET_shiftop:
- case ET_cmpop:
- case ET_relop:
- case ET_andop:
- case ET_xorop:
- case ET_orop:
- case ET_logandop:
- case ET_logorop:
- case ET_seqop:
- print_expr(expr->expr1); print_token(expr->token1); print_expr(expr->expr2); break;
- case ET_condop:
- print_expr(expr->expr1); print_token(expr->token1); print_expr(expr->expr2); print_token(expr->token2); print_expr(expr->expr3); break;
- case ET_defined:
- fprintf(outfile,"DEFINED_%lu",expr->counter); break;
- } }
-
- /* Ausdruck rekursiv durchgehen und defined(...)-Ausdrⁿcke ersetzen: */
- local uintL defined_counter;
- local boolean definedp(expr)
- var Expr expr;
- { if (!(expr->type==ET_literal)) return FALSE;
- {var Token token = expr->token1;
- if (!(token->type==TT_ident)) return FALSE;
- {var char* ptr = token->startptr;
- if (!(token->endptr == ptr+7)) return FALSE;
- if ( (ptr[0]=='d') && (ptr[1]=='e') && (ptr[2]=='f') && (ptr[3]=='i')
- && (ptr[4]=='n') && (ptr[5]=='e') && (ptr[6]=='d')
- )
- return TRUE;
- else
- return FALSE;
- }}}
- local void defined_replace(expr)
- var Expr expr;
- { if (expr->type==ET_call)
- if (definedp(expr->expr1))
- if (expr->expr2->type==ET_literal)
- if (expr->expr2->token1->type==TT_ident)
- { var Token ident = expr->expr2->token1;
- /* expr vom Typ ET_call in Typ ET_defined umwandeln: */
- expr->expr2->token1 = NULL;
- free_expr(expr->expr1); free_expr(expr->expr2);
- free_token(expr->token1); free_token(expr->token2);
- expr->type = ET_defined; expr->counter = ++defined_counter;
- puts("#undef "); print_expr(expr); puts("\n");
- puts("#ifdef "); print_token(ident); puts("\n");
- puts("#define "); print_expr(expr); puts(" 1\n");
- puts("#else\n");
- puts("#define "); print_expr(expr); puts(" 0\n");
- puts("#endif\n");
- free_token(ident);
- return;
- }
- if (expr->expr1) defined_replace(expr->expr1);
- if (expr->expr2) defined_replace(expr->expr2);
- if (expr->expr3) defined_replace(expr->expr3);
- }
-
- /* Zeile im Buffer behandeln: Falls sie eine #if-Anweisung ist, werden alle
- defined(...) durch Tokens ersetzt, die vorher entsprechend definiert werden.
- */
- local void process_line()
- { if (setjmp(abort_line_jmpbuf)==0)
- { bufptr = buffer;
- if ((next_char()=='#') && (next_char()=='i') && (next_char()=='f')
- && whitespacep(next_char())
- )
- { /* Rest der Zeile lesen: */
- last_token = NULL;
- {var Expr expr = parse_expr();
- if (!(peek_token()==Token_EOF)) abort_line();
- /* defined(...) ersetzen: */
- defined_counter = 0; defined_replace(expr);
- /* Zeile ausgeben: */
- puts("#if "); print_expr(expr); puts("\n");
- return;
- } }}
- /* Keine passende PrΣprozessor-Zeile oder Abbruch wegen Syntaxfehler -> */
- /* Zeile unverΣndert ausgeben: */
- {var char* ptr = buffer;
- until (ptr==bufend) { var char c = *ptr++; put(c); }
- put('\n');
- }}
-
- global int main(argc,argv)
- var int argc;
- var char** argv;
- { /* Argumente behandeln: */
- if (argc > 3)
- { fprintf(stderr,"Usage: dedefined [infile [outfile]]\n"); return 1; }
- if (argc >= 2)
- { if ((infile = fopen(argv[1],"r")) == NULL)
- { fprintf(stderr,"dedefined: unable to open input file `%s'",argv[1]);
- return 1;
- } }
- else
- { infile = stdin; }
- if (argc >= 3)
- { if ((outfile = fopen(argv[2],"w")) == NULL)
- { fprintf(stderr,"dedefined: unable to open output file `%s'",argv[2]);
- return 1;
- } }
- else
- { outfile = stdout; }
- /* Buffer initialisieren: */
- buffer = malloc(bufsize = 1024);
- /* Zeilen lesen: */
- loop
- { var int c = get();
- if (c==EOF) break;
- if (c=='#')
- /* m÷gliche PrΣprozessor-Anweisung */
- { bufend = buffer;
- loop
- { putbuffer(c);
- c = get();
- if ((c==EOF) || (c==NL)) break;
- }
- process_line();
- }
- else
- /* normale Zeile, unverΣndert durchlassen */
- { loop
- { put(c);
- c = get();
- if ((c==EOF) || (c==NL)) break;
- }
- put(NL);
- if (c==EOF) break;
- } }
- /* Files schlie▀en: */
- if (ferror(infile) || ferror(outfile))
- { fclose(infile); fclose(outfile); exit(1); }
- fclose(infile);
- fclose(outfile);
- exit(0);
- }
-
-