home *** CD-ROM | disk | FTP | other *** search
/ Amiga ISO Collection / AmigaUtilCD2.iso / Programming / Misc / CLISP-1.LHA / CLISP960530-sr.lha / utils / ansidecl.c next >
Encoding:
C/C++ Source or Header  |  1996-06-11  |  20.5 KB  |  542 lines

  1. #line 1 "ansidecl.d"
  2. /* Programm zum Umwandeln von Funktionsdeklarationen vom traditionellen Stil */
  3. /* in die ANSI-Syntax bei nicht allzu übel geformten C-Programmen */
  4. /* Bruno Haible 16.2.1993 */
  5.  
  6. /* Ziel: */
  7. /* 1. Token &! streichen. */
  8. /* 2. Deklarationen */
  9. /*           funname(vname1,...,vnamek) */
  10. /*             sspec1 tspec1 vname1 ; */
  11. /*             ...; */
  12. /*             sspeck tspeck vnamek ; */
  13. /*             { */
  14. /*    umwandeln in */
  15. /*           funname ( sspec1 tspec1 vname1 , ..., sspeck tspeck vnamek ) { */
  16. /*    unter Beibehaltung aller Kommentare, Präprozessor-Kommandos usw. */
  17.  
  18. /* Methode: */
  19. /* Mit Kenntnis der Begriffe "Präprozessor-Kommando", "Kommentar", "Token" */
  20. /* wird nach den öffnenden geschweiften Klammern '{' des äußersten */
  21. /* Schachtelungslevels gesucht, denen ein Strichpunkt ';' oder */
  22. /* eine Klammer zu ')' unmittelbar vorangeht. */
  23. /* Von dort aus wird (unter Mitzählen der Strichpunkte im äußersten */
  24. /* Schachtelungslevel) die vorige Klammer zu ')' des äußersten Schachtelungs- */
  25. /* levels gesucht. Die Strichpunkte werden in Kommata bzw. eine Klammer zu */
  26. /* umgewandelt. Bis zur vorigen Klammer auf '(' des äußersten Schachtelungs- */
  27. /* levels wird alles durch Leerstellen ersetzt. */
  28.  
  29.  
  30. #define MAXARGCOUNT  50  /* maximale Anzahl Argumente einer Funktionsdefinition */
  31. #define MAXHEADERLEN  5000  /* maximale Länge eines Funktionsdefinitions-Kopfes */
  32.  
  33. #define local static
  34. #define global
  35. #define var
  36. #define loop  while (1)
  37. #define until(exp)  while (!(exp))
  38. typedef unsigned char  uintB;
  39. typedef unsigned short  uintW;
  40. typedef unsigned long  uintL;
  41. typedef int  boolean;
  42. #define FALSE 0
  43. #define TRUE 1
  44. #define NULL ((void*)0)
  45.  
  46. #if defined(__TURBOC__) || defined(__GO32__) || defined(__WATCOMC__)
  47. #define STDC_HEADERS 1
  48. #else
  49. #if defined(unix) || defined(__unix)
  50. #include "config.h"
  51. #endif
  52. #endif
  53. #ifdef STDC_HEADERS
  54. #include <stdlib.h>
  55. #endif
  56.  
  57. #include <stdio.h>
  58.  
  59. local FILE* infile;
  60. local FILE* outfile;
  61.  
  62. /* Input */
  63. /* ===== */
  64.  
  65. local uintL input_line;
  66.  
  67. local int in_char (void)
  68.   { var int c = getc(infile);
  69.     if (c=='\n') { input_line++; }
  70.     return c;
  71.   }
  72.  
  73. local int peek_char (void)
  74.   { var int c = getc(infile);
  75.     if (!(c==EOF)) { ungetc(c,infile); }
  76.     return c;
  77.   }
  78.  
  79. local uintL last_good_input_line;
  80.  
  81. /* Output */
  82. /* ====== */
  83.  
  84. /* Output kann immer ein wenig gepuffert werden: */
  85. enum out_mode { direct, buffered };
  86. local struct { enum out_mode mode; /* Output-Modus */
  87.                uintB buffer[MAXHEADERLEN]; /* Buffer */
  88.                uintL buffindex; /* Index in den Buffer */
  89.              }
  90.       out;
  91.  
  92. #define char_out(char)  putc(char,outfile)
  93.  
  94. /* Output-Bufferung ausschalten: */
  95. local void outbuffer_off (void)
  96.   { if (out.mode==buffered)
  97.       { var uintL index = 0;
  98.         while (index < out.buffindex)
  99.           { char_out(out.buffer[index]); index++; }
  100.         out.mode = direct;
  101.   }   }
  102.  
  103. /* Output-Bufferung ausschalten und dabei an einer Stelle einen String einfügen: */
  104. local void outbuffer_off_insert (uintL insertpoint, char* insert)
  105.   { if (out.mode==buffered)
  106.       { var uintL index = 0;
  107.         loop
  108.           { if (index==insertpoint)
  109.               { while (!(*insert==0)) { char_out(*insert++); } }
  110.             if (index == out.buffindex) break;
  111.             char_out(out.buffer[index]); index++;
  112.           }
  113.         out.mode = direct;
  114.   }   }
  115.  
  116. /* Output-Bufferung einschalten: */
  117. local void outbuffer_on (void)
  118.   { if (out.mode==direct)
  119.       { out.buffindex = 0;
  120.         out.mode = buffered;
  121.   }   }
  122.  
  123. /* Character ausgeben: */
  124. local void out_char (int c)
  125.   { if (out.mode==buffered)
  126.       { if (out.buffindex < MAXHEADERLEN)
  127.           { out.buffer[out.buffindex++] = c; }
  128.           else
  129.           /* Buffer voll -> Buffer abschalten */
  130.           { outbuffer_off(); char_out(c); }
  131.       }
  132.       else
  133.       { char_out(c); }
  134.   }
  135.  
  136. /* lexikalische Analyse */
  137. /* ==================== */
  138.  
  139. /* Holt das nächste Character: */
  140. local int next_char (void)
  141.   { var int c = in_char();
  142.     if (!(c==EOF))
  143.       { out_char(c); } /* c auch ausgeben */
  144.     return c;
  145.   }
  146.  
  147. /* Für unsere Zwecke brauchen ++ -> != usw. nicht als eigene Token betrachtet */
  148. /* zu werden, wir kennen also nur: */
  149. /*   EOF */
  150. /*   Identifier */
  151. /*   Zahl-Konstanten */
  152. /*   Character-Konstanten */
  153. /*   String-Konstanten */
  154. /*   Operator/Separator */
  155. /* Verallgemeinerte Tokens: Expressions (mit balancierten Klammern) */
  156. enum token_type { eof, eol, ident, number, charconst, stringconst, sep, expr };
  157. typedef struct { enum token_type type;
  158.                  /* falls Bufferung aktiv: */
  159.                  uintL startindex; /* Startindex im Buffer */
  160.                  uintL endindex; /* Endindex im Buffer */
  161.                  /* bei sep (Operator/Separator): */
  162.                  uintB ch;
  163.                }
  164.         token_;
  165. typedef token_* Token;
  166.  
  167. /* globale Token-Tabelle (Inhalt nur während einer Bufferungsperiode gültig): */
  168. #define MAXTOKENS  20000
  169. local struct { uintL index;
  170.                token_ data[MAXTOKENS];
  171.              }
  172.       tokens;
  173.  
  174. /* Holt das nächste Token: */
  175. /* (Innerhalb von Präprozessor-Direktiven zählt Zeilenende als eigenes Token, */
  176. /* und '#' leitet keine verschachtelte Präprozessor-Direktive ein.) */
  177. local Token nexttoken (boolean within_prep_directive)
  178.   { if (tokens.index == MAXTOKENS)
  179.       /* kein Platz mehr in der Token-Tabelle -> nicht mehr buffern */
  180.       { outbuffer_off(); tokens.index = 0;
  181.         fprintf(stderr,"Token-Tabelle übergelaufen in Zeile %lu.\nFehler irgendwo nach Zeile %lu.\n",input_line,last_good_input_line);
  182.         exit(1);
  183.       }
  184.     /* Nun ist tokens.index < MAXTOKENS . */
  185.    {var Token token = &tokens.data[tokens.index]; /* Platz fürs nächste Token */
  186.     tokens.index++;
  187.     restart:
  188.     token->startindex = out.buffindex;
  189.     if (peek_char() == '&')
  190.       { in_char(); /* '&' überlesen */
  191.         if (peek_char() == '!')
  192.           /* '&!' */
  193.           { in_char(); goto restart; } /* '!' überlesen */
  194.           else
  195.           { out_char('&'); token->type = sep; token->ch = '&'; goto fertig; }
  196.       }
  197.     { var int c = next_char();
  198.       switch (c)
  199.         { case EOF:
  200.             /* EOF */
  201.             token->type = eof; goto fertig;
  202.           case ' ': case '\v': case '\t':
  203.             /* Whitespace. überlesen */
  204.             goto restart;
  205.           case '\n':
  206.             /* Zeilenende */
  207.             if (within_prep_directive)
  208.               { token->type = eol; goto fertig; } /* als Token zurück */
  209.               else
  210.               { goto restart; } /* überlesen */
  211.           case '\\':
  212.             if (peek_char()=='\n')
  213.               /* Zeilenende nach '\'. überlesen */
  214.               { next_char(); goto restart; }
  215.               else
  216.               goto separator;
  217.           case '/':
  218.             if (peek_char() == '*')
  219.               /* Kommentar */
  220.               { next_char();
  221.                 loop { c = next_char();
  222.                        if (c==EOF) { fprintf(stderr,"Unbeendeter Kommentar\n"); break; }
  223.                        if ((c=='*') && (peek_char()=='/')) { next_char(); break; }
  224.                      }
  225.                 goto restart;
  226.               }
  227.               else
  228.               goto separator;
  229.           case '*':
  230.             if (peek_char() == '/')
  231.               /* illegales Kommentar-Ende */
  232.               { fprintf(stderr,"Kommentar-Ende außerhalb Kommentar in Zeile %lu\n",input_line); }
  233.             goto separator;
  234.           case '#':
  235.             if (within_prep_directive)
  236.               { goto separator; }
  237.               else
  238.               { /* Präprozessor-Anweisung. */
  239.                 /* Bis Zeilenende oder EOF lesen. */
  240.                 loop
  241.                   { var Token subtoken = nexttoken(TRUE);
  242.                     if ((subtoken->type == eof) || (subtoken->type == eol))
  243.                       break;
  244.                   }
  245.                 goto restart; /* und überlesen */
  246.               }
  247.           case '.':
  248.             c = peek_char();
  249.             if (!(((c>='0') && (c<='9')) || (c=='.'))) goto separator;
  250.           case '0': case '1': case '2': case '3': case '4':
  251.           case '5': case '6': case '7': case '8': case '9':
  252.             /* Zahl. Weiterlesen, solange alphanumerisches Zeichen oder '.': */
  253.             loop
  254.               { c = peek_char();
  255.                 if (((c>='0') && (c<='9'))
  256.                     || ((c>='A') && (c<='Z')) || ((c>='a') && (c<='z'))
  257.                     || (c=='.')
  258.                    )
  259.                   { next_char(); }
  260.                   else
  261.                   break;
  262.               }
  263.             token->type = number; goto fertig;
  264.           case '\'':
  265.             /* Character-Konstante */
  266.             loop
  267.               { c = next_char();
  268.                 if (c==EOF) { fprintf(stderr,"Unbeendete Character-Konstante\n"); break; }
  269.                 if (c=='\'') break;
  270.                 if (c=='\\') { c = next_char(); }
  271.               }
  272.             token->type = charconst; goto fertig;
  273.           case '\"':
  274.             /* String-Konstante */
  275.             loop
  276.               {
  277. #ifndef QUOTE_QUOTES
  278.                 c = next_char();
  279.                 if (c==EOF) { fprintf(stderr,"Unbeendete String-Konstante\n"); break; }
  280. #else /* muß Single-Quotes in Strings quotieren: */
  281.                 c = in_char();
  282.                 if (c==EOF) { fprintf(stderr,"Unbeendete String-Konstante\n"); break; }
  283.                 if (c=='\'')
  284.                   { /* statt "'" ein "\047" ausgeben: */
  285.                     out_char('\\');
  286.                     out_char('0'+((((unsigned char)'\'')/64)%8));
  287.                     out_char('0'+((((unsigned char)'\'')/8)%8));
  288.                     out_char('0'+(((unsigned char)'\'')%8));
  289.                     continue;
  290.                   }
  291.                 out_char(c);
  292. #endif
  293.                 if (c=='\"') break;
  294.                 if (c=='\\') { c = next_char(); }
  295.               }
  296.             token->type = stringconst; goto fertig;
  297.           case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
  298.           case 'G': case 'H': case 'I': case 'J': case 'K': case 'L':
  299.           case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
  300.           case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
  301.           case 'Y': case 'Z':
  302.           case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
  303.           case 'g': case 'h': case 'i': case 'j': case 'k': case 'l':
  304.           case 'm': case 'n': case 'o': case 'p': case 'q': case 'r':
  305.           case 's': case 't': case 'u': case 'v': case 'w': case 'x':
  306.           case 'y': case 'z':
  307.           case '_':
  308.             /* Identifier. alles alphanumerische überlesen. */
  309.             loop
  310.               { c = peek_char();
  311.                 if (   ((c>='0') && (c<='9'))
  312.                     || ((c>='A') && (c<='Z')) || ((c>='a') && (c<='z'))
  313.                     || (c=='_')
  314.                    )
  315.                   { next_char(); }
  316.                   else
  317.                   break;
  318.               }
  319.             token->type = ident; goto fertig;
  320.           default:
  321.           separator:
  322.             token->type = sep; token->ch = c; goto fertig;
  323.     }   }
  324.     fertig:
  325.     token->endindex = out.buffindex;
  326.     return token;
  327.   }}
  328. #define next_token() nexttoken(FALSE)
  329.  
  330. /* Klammern mitzählen: */
  331. #define MAXBRACES 1000 /* maximale Verschachtelungstiefe von Klammern */
  332. local struct { uintL count;
  333.                struct { uintB brace_type; uintL input_line; } opening[MAXBRACES];
  334.              }
  335.       open_braces;
  336.  
  337. /* Mitzählen einer öffnenden Klammer: */
  338. local void handle_opening_token (Token token)
  339.   { if (open_braces.count < MAXBRACES)
  340.       { open_braces.opening[open_braces.count].brace_type = token->ch;
  341.         open_braces.opening[open_braces.count].input_line = input_line;
  342.       }
  343.     open_braces.count++;
  344.   }
  345.  
  346. /* Mitzählen einer schließenden Klammer (ohne Überprüfung der Verschachtelung): */
  347. /* local void handle_closing_token (Token token) */
  348. /*   { open_braces.count--; } */
  349. /* oder als Macro */
  350. #define handle_closing_token(token)  { open_braces.count--; }
  351.  
  352. /* nächste Expression mit balancierten Klammern '()', '{}', '[]' lesen: */
  353. /* (Dabei ist auf das Niveau open_braces.count=0 zu kommen, */
  354. /*  evtl. ist jetzt schon open_braces.count>0.) */
  355. local Token next_balanced_token (Token start_token)
  356.   { var uintL open_braces_start = 0; /* Ziel-Niveau: 0 */
  357.     var Token token = (start_token==NULL ? next_token() : start_token);
  358.     var uintL startindex = token->startindex;
  359.     loop
  360.       { /* Hier stets  open_braces.count >= open_braces_start . */
  361.         switch (token->type)
  362.           { case eof:
  363.               if (open_braces.count > open_braces_start)
  364.                 { if (open_braces.count <= MAXBRACES)
  365.                     fprintf(stderr,"Nicht geschlossene '%c' in Zeile %lu\n",
  366.                                    open_braces.opening[open_braces.count-1].brace_type,
  367.                                    open_braces.opening[open_braces.count-1].input_line
  368.                            );
  369.                     else
  370.                     fprintf(stderr,"Nicht geschlossene '(' oder '{' oder '['\n");
  371.                 }
  372.               return token; /* EOF-Token als Ergebnis */
  373.             case sep:
  374.               switch (token->ch)
  375.                 { case '(': case '{': case '[':
  376.                     handle_opening_token(token);
  377.                     break;
  378.                   case ')': case '}': case ']':
  379.                     if (open_braces.count > open_braces_start)
  380.                       { open_braces.count--;
  381.                         if (open_braces.count < MAXBRACES)
  382.                           { var uintB opening_ch = open_braces.opening[open_braces.count].brace_type;
  383.                             var uintB closing_ch = token->ch;
  384.                             if (!(   ((opening_ch == '(') && (closing_ch == ')'))
  385.                                   || ((opening_ch == '{') && (closing_ch == '}'))
  386.                                   || ((opening_ch == '[') && (closing_ch == ']'))
  387.                                ) )
  388.                               { fprintf(stderr,"Öffnende Klammer '%c' in Zeile %lu\n und schließende Klammer '%c'\n in Zeile %lu passen nicht zusammen.\n",
  389.                                         opening_ch,open_braces.opening[open_braces.count].input_line,
  390.                                         closing_ch,input_line
  391.                                        );
  392.                           }   }
  393.                       }
  394.                       else
  395.                       { fprintf(stderr,"Nicht geöffnete '%c' in Zeile %lu\n",
  396.                                 token->ch,input_line
  397.                                );
  398.                         goto fertig;
  399.                       }
  400.                     break;
  401.                   default:
  402.                     break;
  403.                 }
  404.             default: ;
  405.               /* alles andere ist ausbalanciert */
  406.           }
  407.         if (open_braces.count == open_braces_start) break; /* fertig ausbalanciert? */
  408.         token = next_token(); /* nein -> nächstes Token lesen */
  409.       }
  410.     fertig:
  411.     token->startindex = startindex;
  412.     return token;
  413.   }
  414.  
  415. /* Umwandlung der Funktionsdefinitions-Deklarationen auf dem ganzen File */
  416. /* vornehmen: */
  417. local void convert (void)
  418.   { input_line = 1; last_good_input_line = 1;
  419.     out.mode = direct;
  420.     open_braces.count = 0;
  421.     restart1: /* Hier out.mode=direct, neues Token lesen: */
  422.     tokens.index = 0; /* Token-Tabelle leeren */
  423.    {var Token token = next_token(); /* nächstes Token lesen */
  424.     restart2: /* Hier out.mode=direct, neues Token gelesen. */
  425.     if ((token->type == sep) && (token->ch == '(')) /* Klammer auf? */
  426.       /* ja -> aufpassen: */
  427.       { handle_opening_token(token);
  428.         outbuffer_on(); /* Buffer einschalten */
  429.         /* Es sollten nun k Identifier, getrennt durch k-1 Kommata, kommen: */
  430.         token = next_token();
  431.         if ((token->type == sep) && (token->ch == ')')) /* Klammer zu? */
  432.           /* ja -> in eine leere Parameterliste evtl. 'void' einfügen: */
  433.           { var uintL insertpoint = token->startindex;
  434.             handle_closing_token(token);
  435.             token = next_token();
  436.             if (!((token->type == sep) && (token->ch == '{'))) /* geschweifte Klammer auf? */
  437.               { outbuffer_off(); goto restart2; }
  438.             /* token = '{' */
  439.             /* Umwandeln: "void" einfügen. */
  440.             outbuffer_off_insert(insertpoint,"void");
  441.             token = next_balanced_token(token); /* Funktionsdefinition überlesen */
  442.           }
  443.           else
  444.           /* nein -> nichtleere Parameterliste verarbeiten: */
  445.           { var Token param_names[MAXARGCOUNT];
  446.             var Token param_comma[MAXARGCOUNT];
  447.             var uintL param_count = 0;
  448.             loop
  449.               { if (param_count==MAXARGCOUNT) goto nix; /* kein Platz mehr? */
  450.                 if (!(token->type == ident)) /* Identifier? */
  451.                   goto nix;
  452.                 param_names[param_count] = token; /* ja -> abspeichern */
  453.                 token = next_token();
  454.                 if (!(   ((token->type == sep) && (token->ch == ')')) /* Klammer zu? */
  455.                       || ((token->type == sep) && (token->ch == ',')) /* oder Komma? */
  456.                    ) )
  457.                   goto nix;
  458.                 param_comma[param_count] = token; /* ja -> abspeichern */
  459.                 param_count++;
  460.                 if ((token->type == sep) && (token->ch == ')')) /* Klammer zu? */
  461.                   break;
  462.                 token = next_token();
  463.               }
  464.             /* token = ')' */
  465.             handle_closing_token(token);
  466.             /* Parameter-Deklarationen verarbeiten: */
  467.            {var Token paramdecl_semicolons[MAXARGCOUNT];
  468.             var uintL paramdecl_count = 0;
  469.             loop
  470.               { token = next_token();
  471.                 if ((token->type == sep) && (token->ch == '(')) /* Klammer auf? */
  472.                   /* Entscheidung der Zweideutigkeit (Beispiel: */
  473.                   /* " macro(macroarg) (x) int x; {los();} " */
  474.                   /* -> zugunsten der Erkennung von "macro(macroarg)" und nicht */
  475.                   /* "macro": */
  476.                   { outbuffer_off(); goto restart2; }
  477.                 if ((token->type == sep) && (token->ch == '{')) /* geschweifte Klammer auf? */
  478.                   break;
  479.                 loop
  480.                   { token = next_balanced_token(token);
  481.                     if (token->type==eof) goto nix;
  482.                     if ((token->type == sep) && (token->ch == ';')) /* Semikolon? */
  483.                       break;
  484.                     /* Entscheidung der Zweideutigkeit (Beispiel: */
  485.                     /* " foo(a,b) int a; bar(x,y) int x; int y; {los();} " */
  486.                     /* -> zugunsten der Erkennung von "bar" und nicht "foo"): */
  487.                     token = next_token();
  488.                     if ((token->type == sep) && (token->ch == '(')) /* Klammer auf? */
  489.                       { outbuffer_off(); goto restart2; }
  490.                   }
  491.                 if (paramdecl_count==MAXARGCOUNT) goto nix; /* kein Platz mehr? */
  492.                 paramdecl_semicolons[paramdecl_count] = token;
  493.                 paramdecl_count++;
  494.               }
  495.             /* token = '{' */
  496.             if ((param_count == paramdecl_count) /* gleichviele Variablen wie Deklarationen? */
  497.                 && (out.mode==buffered) /* und Buffer noch da? */
  498.                )
  499.               /* ja -> Modifikation durchführen: */
  500.               /* Alle param_names und param_comma durch Leerstellen und */
  501.               /* alle paramdecl_semicolons durch Komma bzw. Klammer zu */
  502.               /* überschreiben: */
  503.               { do { param_count--;
  504.                     {var Token name = param_names[param_count];
  505.                      var uintL index = name->startindex;
  506.                      var uintL endindex = name->endindex;
  507.                      until (index==endindex) { out.buffer[index++] = ' '; }
  508.                     }
  509.                     {var Token comma = param_comma[param_count];
  510.                      var uintL index = comma->startindex;
  511.                      var uintL endindex = comma->endindex;
  512.                      until (index==endindex) { out.buffer[index++] = ' '; }
  513.                    }}
  514.                    until (param_count==0);
  515.                 out.buffer[paramdecl_semicolons[--paramdecl_count]->startindex] = ')';
  516.                 until (paramdecl_count==0)
  517.                   { out.buffer[paramdecl_semicolons[--paramdecl_count]->startindex] = ','; }
  518.               }
  519.             outbuffer_off();
  520.             last_good_input_line = input_line;
  521.             token = next_balanced_token(token); /* Funktionsdefinition überlesen */
  522.           }}
  523.       }
  524.       else
  525.       { nix: /* keine umwandelbare Funktionsdefinition */
  526.         outbuffer_off();
  527.         token = next_balanced_token(token);
  528.       }
  529.     /* Hier ist wieder out.mode=direct. */
  530.     if (!(token->type==eof)) goto restart1;
  531.     /* Bei EOF am Input: fertig (da outfile ungebuffert). */
  532.   }}
  533.  
  534. int main ()
  535.   { infile = stdin;
  536.     outfile = stdout;
  537.     convert();
  538.     if (ferror(stdin) || ferror(stdout)) { exit(1); }
  539.     exit(0);
  540.   }
  541.  
  542.