home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / intercal.zip / src / perpetrate.c < prev    next >
Text File  |  1996-12-10  |  13KB  |  461 lines

  1. /****************************************************************************
  2.  
  3. NAME
  4.    perpetrate.c -- main routine for C-INTERCAL compiler.
  5.  
  6. DESCRIPTION
  7.    This is where all the dirty work begins and ends.
  8.  
  9. LICENSE TERMS
  10.     Copyright (C) 1996 Eric S. Raymond 
  11.  
  12.     This program is free software; you can redistribute it and/or modify
  13.     it under the terms of the GNU General Public License as published by
  14.     the Free Software Foundation; either version 2 of the License, or
  15.     (at your option) any later version.
  16.  
  17.     This program is distributed in the hope that it will be useful,
  18.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  19.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  20.     GNU General Public License for more details.
  21.  
  22.     You should have received a copy of the GNU General Public License
  23.     along with this program; if not, write to the Free Software
  24.     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  25.  
  26. ****************************************************************************/
  27. /*LINTLIBRARY */
  28. #include <stdio.h>
  29. #include <stdlib.h>
  30. #include <unistd.h>
  31. #include <string.h>
  32. #include <signal.h>
  33. #include <time.h>
  34. #include "ick.h"
  35. #include "feh.h"
  36. #include "y.tab.h"
  37. #include "sizes.h"
  38. #include "lose.h"
  39.  
  40. #ifndef ICKINCLUDEDIR
  41. #define ICKINCLUDEDIR "/usr/local/include"
  42. #endif
  43. #ifndef ICKLIBDIR
  44. #define ICKLIBDIR "/usr/local/lib"
  45. #endif
  46. #ifndef CC
  47. #define CC "gcc"
  48. #endif
  49.  
  50. #ifdef USE_YYRESTART
  51. /* function supplied by lex */
  52. extern void yyrestart(FILE*);
  53. #endif /* USE_YYRESTART */
  54.  
  55. /* function created by yacc */
  56. extern int yyparse(void);
  57.  
  58. /* compilation options */
  59. bool compile_only;     /* just compile into C, don't run the linker */
  60. bool traditional;    /* insist on strict INTERCAL-72 conformance */
  61. bool nocompilerbug;    /* disable error E774 */
  62.  
  63. static bool dooptimize;    /* do optimizations? (controlled by -O) */
  64. static bool clockface;    /* set up output to do IIII for IV */
  65.  
  66. #define SKELETON    "ick-wrap.c"
  67. #define SYSLIB          "syslib.i"
  68.  
  69. /* numeric base defaults, exported to other files */
  70. int Base = 2;
  71. int Small_digits = 16;
  72. int Large_digits = 32;
  73. unsigned int Max_small = 0xffff;
  74. unsigned int Max_large = 0xffffffff;
  75.  
  76. int lineno;    /* after yyparse, this is the total number of statements */
  77.  
  78. /* currently supported numeric bases, not exported */
  79. static int maxbase = 7;
  80. static int smallsizes[8] = {0, 0, 16, 10, 8, 6, 6, 5};
  81. static unsigned int maxsmalls[8] =
  82.   {0, 0, 65535, 59048, 65535, 15624, 46655, 16806};
  83.  
  84. static char *compiler;
  85.  
  86. atom oblist[MAXVARS], *obdex;
  87. int nonespots, ntwospots, ntails, nhybrids;
  88.  
  89. tuple tuples[MAXLINES];
  90.  
  91. static void abend(int signim)
  92. {
  93.     lose(E778, yylineno, (char *)NULL);
  94.     (void) signim;
  95. }
  96.  
  97. static void print_usage(char *prog, char *options)
  98. {
  99.     fprintf(stderr,"Usage: %s [-%s] <file> [<file> ... ]\n",prog,options);
  100.     fprintf(stderr,"\t-b\t:reduce the probability of E774 to zero\n");
  101.     fprintf(stderr,"\t-c\t:compile INTERCAL to C, but don't compile C\n");
  102.     fprintf(stderr,"\t-d\t:print debugging information (implies -c)\n");
  103.     fprintf(stderr,"\t-t\t:traditional mode, accept only INTERCAL-72\n");
  104.     fprintf(stderr,"\t-C\t:clockface output (e.g. use IIII instead of IV)\n");
  105.     fprintf(stderr,"\t-O\t:attempt to optimize generated code\n");
  106.     fprintf(stderr,"\t<file>\tINTERCAL source file(s) (use extension .i)\n");
  107.     fprintf(stderr,"\t\teach file produces a separate output program.\n");
  108. }
  109.  
  110. int main(int argc, char *argv[])
  111. {
  112.     extern int    optind;        /* set by getopt */
  113.     char    buf[BUFSIZ], buf2[BUFSIZ], *chp, *strrchr();
  114.     tuple    *tp;
  115.     atom    *op;
  116.     int    c;
  117.     char    *includedir, *libdir, *getenv();
  118.     FILE    *ifp, *ofp;
  119.     int        maxabstain, nextcount;
  120.     bool        needsyslib;
  121.  
  122.     if (!(includedir = getenv("ICKINCLUDEDIR")))
  123.       includedir = ICKINCLUDEDIR;
  124.     if (!(libdir = getenv("ICKLIBDIR")))
  125.       libdir = ICKLIBDIR;
  126.     if (!(compiler = getenv("CC")))
  127.       compiler = CC;
  128.  
  129.     while ((c = getopt(argc, argv, "bcdtOC@")) != EOF)
  130.     {
  131.     switch (c)
  132.     {
  133.     case 'b':
  134.         nocompilerbug = TRUE;
  135.         break;
  136.  
  137.     case 'c':
  138.         compile_only = TRUE;
  139.         break;
  140.  
  141.     case 'd':
  142.         yydebug = compile_only = TRUE;
  143.         break;
  144.  
  145.     case 'C':
  146.         clockface = TRUE;
  147.         break;
  148.  
  149.     case 't':
  150.         traditional = TRUE;
  151.         break;
  152.  
  153.     case 'O':
  154.         dooptimize = TRUE;
  155.         break;
  156.  
  157.     case '?':
  158.     default:
  159.     case '@':
  160.         print_usage(argv[0],"bcdtCO");
  161.         exit(1);
  162.         break;
  163.     }
  164.     }
  165.  
  166.     (void) signal(SIGSEGV, abend);
  167. #ifdef SIGBUS
  168.     (void) signal(SIGBUS, abend);
  169. #endif /* SIGBUS */
  170.  
  171.     if (!nocompilerbug) {
  172. #ifdef USG
  173.     srand48(time(NULL) + getpid());
  174. #else
  175.     srand(time(NULL));
  176. #endif /* UNIX */
  177.     }
  178.  
  179.     (void) sprintf(buf2,"%s/%s",includedir,SKELETON);
  180.  
  181.     /* now substitute in tokens in the skeleton */
  182.     if ((ifp = fopen(buf2, "r")) == (FILE *)NULL)
  183.     lose(E999, 1, (char *)NULL);
  184.     buf[strlen(buf) - 2] = '\0';
  185.  
  186.     for (; optind < argc; optind++)
  187.     {
  188.     if (freopen(argv[optind], "r", stdin) == (FILE *)NULL)
  189.         lose(E777, 1, (char *)NULL);
  190.     else
  191.     {
  192.         /* strip off the file extension */
  193.         if(!(chp = strrchr(argv[optind],'.')))
  194.         {
  195.         lose(E998, 1, (char *)NULL);
  196.         }
  197.         *chp++ = '\0';
  198.  
  199.         /* determine the file type from the extension */
  200.         while (strcmp(chp,"i"))
  201.         {
  202.         long strtol();
  203.         Base = strtol(chp,&chp,10);
  204.         if (Base < 2 || Base > maxbase)
  205.             lose(E998, 1, (char *)NULL);
  206.         else if (traditional && Base != 2)
  207.             lose(E111, 1, (char *)NULL);
  208.         Small_digits = smallsizes[Base];
  209.         Large_digits = 2 * Small_digits;
  210.         Max_small = maxsmalls[Base];
  211.         if (Max_small == 0xffff)
  212.             Max_large = 0xffffffff;
  213.         else
  214.             Max_large = (Max_small + 1) * (Max_small + 1) - 1;
  215.         }
  216.  
  217.         /* zero out tuple and oblist storage */
  218.         treset();
  219.         politesse = 0;
  220.  
  221.         /* compile tuples from current input source */
  222.         yyparse();    
  223.  
  224.         /*
  225.          * Miss Manners lives.
  226.          */
  227.         if (lineno > 2)
  228.         if (politesse == 0 || lineno / politesse > 5)
  229.             lose(E079, yylineno, (char *)NULL);
  230.         else if (lineno / politesse < 3)
  231.             lose(E099, yylineno, (char *)NULL);
  232.  
  233.         /*
  234.          * check if we need to magically include the system library
  235.          */
  236.         needsyslib = FALSE;
  237.         for (tp = tuples; tp->type; tp++) {
  238.           /*
  239.            * If some label in the (1000)-(2000) range is defined,
  240.            * then clearly the syslib is already there, so we
  241.            * can stop searching and won't need the syslib.
  242.            */
  243.           if (tp->label >= 1000 && tp->label <= 1999) {
  244.         needsyslib = FALSE;
  245.         break;
  246.           }
  247.           /*
  248.            * If some label in the (1000)-(2000) range is being
  249.            * called, we might need the system library.
  250.            */
  251.           if (tp->type == NEXT && tp->u.target >= 1000 &&
  252.           tp->u.target <= 1999)
  253.         needsyslib = TRUE;
  254.         }
  255.         if ( needsyslib ) {
  256.           (void) sprintf(buf2, "%s/%s", libdir, SYSLIB);
  257.           if ( freopen(buf2, "r", stdin) == (FILE*) NULL ) {
  258.         lose(E127, 1, (char*) NULL);
  259.           }
  260. #ifdef USE_YYRESTART
  261.           yyrestart(stdin);
  262. #endif /* USE_YYRESTART */
  263.           yyparse();
  264.         }
  265.  
  266.         /* 
  267.          * Now propagate type information up the expression tree.
  268.          * We need to do this because the unary-logical operations
  269.          * are sensitive to the type widths of their operands, so
  270.          * we have to generate different code depending on the
  271.          * deducible type of the operand.
  272.          */
  273.         for (tp = tuples; tp->type; tp++)
  274.         if (tp->type == GETS || tp->type == RESIZE
  275.             || tp->type == FORGET || tp->type == RESUME)
  276.             typecast(tp->u.node);
  277.  
  278.         codecheck();    /* check for compile-time errors */
  279.  
  280.         /* perform optimizations */
  281.         if (dooptimize)
  282.         for (tp = tuples; tp->type; tp++)
  283.             if (tp->type == GETS || tp->type == RESIZE
  284.             || tp->type == FORGET || tp->type == RESUME)
  285.             optimize(tp->u.node);
  286.  
  287.         /* set up the generated C output file name */
  288.         (void) strcpy(buf, argv[optind]);
  289.         (void) strcat(buf, ".c");
  290.         if ((ofp = fopen(buf, "w")) == (FILE *)NULL)
  291.         lose(E888, 1, (char *)NULL);
  292.         
  293.         fseek(ifp,0L,0);    /* rewind skeleton file */
  294.  
  295.         while ((c = fgetc(ifp)) != EOF)
  296.         if (c != '$')
  297.             (void) fputc(c, ofp);
  298.             else switch(fgetc(ifp))
  299.         {
  300.         case 'A':    /* source name stem */
  301.             (void) fputs(argv[optind], ofp);
  302.             break;
  303.  
  304.         case 'B':    /* # of statements */
  305.             (void) fprintf(ofp, "%d", lineno);
  306.             break;
  307.  
  308.         case 'C':    /* initial abstentions */
  309.             maxabstain = 0;
  310.             for (tp = tuples; tp->type; tp++)
  311.             if (tp->exechance <= 0 && tp - tuples + 1 > maxabstain)
  312.                 maxabstain = tp - tuples + 1;
  313.             if (maxabstain)
  314.             {
  315.             (void) fprintf(ofp, " = {");
  316.             for (tp = tuples; tp < tuples + maxabstain; tp++)
  317.                 if (tp->exechance > 0)
  318.                 (void) fprintf(ofp, "0, ");
  319.                 else {
  320.                 (void) fprintf(ofp, "1, ");
  321.                 tp->exechance = -tp->exechance;
  322.                 }
  323.             (void) fprintf(ofp, "}");
  324.             }
  325.             break;
  326.  
  327.         case 'D':    /* linetypes array for abstention handling */
  328.             maxabstain = 0;
  329.             for (tp = tuples; tp->type; tp++)
  330.             if (tp->type == ENABLE || tp->type == DISABLE)
  331.                 maxabstain++;
  332.             if (maxabstain)
  333.             {
  334.             int i;
  335.  
  336.             (void) fprintf(ofp, "#define UNKNOWN\t\t0\n");
  337.             i = 0;
  338.             for (; i < (int)(sizeof(enablers)/sizeof(char *)); i++)
  339.                 (void) fprintf(ofp,
  340.                        "#define %s\t%d\n",
  341.                        enablers[i], i+1);
  342.  
  343.             (void) fprintf(ofp, "int linetype[] = {\n");
  344.             for (tp = tuples; tp->type; tp++)
  345.                 if (tp->type >= GETS && tp->type <= COME_FROM)
  346.                 (void) fprintf(ofp,
  347.                            "    %s,\n",
  348.                            enablers[tp->type - GETS]);
  349.                 else
  350.                 (void) fprintf(ofp, "    UNKNOWN,\n");
  351.             (void) fprintf(ofp, "};\n");
  352.             }
  353.             break;
  354.  
  355.         case 'E':    /* extern to intern map */
  356.             (void) fprintf(ofp,"int Base = %d;\n",Base);
  357.             (void) fprintf(ofp,"int Small_digits = %d;\n",
  358.                    Small_digits);
  359.             (void) fprintf(ofp,"int Large_digits = %d;\n",
  360.                    Large_digits);
  361.             (void) fprintf(ofp,"unsigned int Max_small = 0x%x;\n",
  362.                    Max_small);
  363.             (void) fprintf(ofp,"unsigned int Max_large = 0x%x;\n",
  364.                    Max_large);
  365.             if (nonespots)
  366.             {
  367.             (void) fprintf(ofp,
  368.                        "static type16 onespots[%d];\n",
  369.                        nonespots);
  370.             (void) fprintf(ofp,
  371.                        "static bool oneforget[%d];\n",
  372.                        nonespots);
  373.             }
  374.             if (ntwospots)
  375.             {
  376.             (void) fprintf(ofp,
  377.                        "static type32 twospots[%d];\n",
  378.                        ntwospots);
  379.             (void) fprintf(ofp,
  380.                        "static bool twoforget[%d];\n",
  381.                        ntwospots);
  382.             }
  383.             if (ntails)
  384.             {
  385.             (void) fprintf(ofp,
  386.                        "static array tails[%d];\n",
  387.                        ntails);
  388.             (void) fprintf(ofp,
  389.                        "static bool tailforget[%d];\n",
  390.                        ntails);
  391.             }
  392.             if (nhybrids)
  393.             {
  394.             (void) fprintf(ofp,
  395.                        "static array hybrids[%d];\n",
  396.                        nhybrids);
  397.             (void) fprintf(ofp,
  398.                        "static bool hyforget[%d];\n",
  399.                        nhybrids);
  400.             }
  401.             if (yydebug || compile_only)
  402.             for (op = oblist; op < obdex; op++)
  403.                 (void) fprintf(ofp, " /* %s %d -> %d */\n",
  404.                        nameof(op->type, vartypes),
  405.                        op->extindex,
  406.                        op->intindex);
  407.             break;
  408.  
  409.         case 'F':    /* set clockface option? */
  410.             if (clockface)
  411.             (void) fprintf(ofp, "clockface(TRUE);");
  412.             break;
  413.  
  414.         case 'G':    /* degenerated code */
  415.             for (tp = tuples; tp->type; tp++)
  416.             emit(tp, ofp);
  417.             break;
  418.  
  419.         case 'H':    /* dispatching for resumes */
  420.             nextcount = 0;
  421.             for (tp = tuples; tp->type; tp++)
  422.             if (tp->type == NEXT)
  423.                 nextcount++;
  424.             if (nextcount)
  425.             {
  426.             (void) fputs("/* generated switch for resumes */",ofp);
  427.             (void) fputs("top:\n    switch(skipto)\n    {\n", ofp);
  428.             for (tp = tuples; tp->type; tp++)
  429.                 if (tp->type == NEXT)
  430.                 (void) fprintf(ofp,
  431.                            "\tcase %d: goto N%d; break;\n",
  432.                            tp-tuples+1, tp-tuples+1);
  433.             (void) fprintf(ofp, "    }");
  434.             }
  435.             break;
  436.  
  437.         case 'J':    /* # of source file lines */
  438.             (void) fprintf(ofp, "%d", yylineno);
  439.             break;
  440.         }
  441.  
  442.         (void) fclose(ofp);
  443.  
  444.         /* OK, now sic the C compiler on the results */
  445.         if (!compile_only)
  446.         {
  447.         (void) sprintf(buf2,
  448.                    "%s %s -I%s -L%s -llibick -o %s.exe",
  449.                    compiler, buf, includedir, libdir,
  450.                    argv[optind]);
  451.         (void) system(buf2);
  452.         (void) unlink(buf);
  453.         }
  454.     }
  455.     }
  456.     (void) fclose(ifp);
  457.     return 0;
  458. }
  459.  
  460. /* perpetrate.c ends here */
  461.