home *** CD-ROM | disk | FTP | other *** search
/ Acorn User 10 / AU_CD10.iso / Archived / Updates / Flash / writeflash / !MakeFlash / c / preprocess < prev    next >
Text File  |  2000-04-26  |  14KB  |  610 lines

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <time.h>
  5. #include <math.h>
  6. #include <ctype.h>
  7.  
  8. #include "proto.h"
  9. #include "main.h"
  10. #include "preprocess.h"
  11. #include "evaluate.h"
  12.  
  13. //#define ALLOW_ARRAYS
  14.  
  15. #define MACRONAME             0
  16. #define MACROVALUE            1
  17.  
  18. #define MAXNESTEDLOOPS        10
  19.  
  20. typedef struct loop {
  21.   U32 startoffset;
  22.   S32 current;
  23.   char name[MAXVARNAMELENGTH+1];
  24.   char *to_expr;
  25. } loop;
  26.  
  27. static loop loopinfo[MAXNESTEDLOOPS];
  28. static int loopdepth = 0;
  29.  
  30. static char *macros[MAXMACROS][2];
  31. static int macrocount = 0;
  32.  
  33. static U32 allocated, codesize, ifdefdepth, readoffset;
  34. static char *buffer;
  35.  
  36.  
  37. static int define_macro(char *line);
  38. static int insert_file(char *filename);
  39. static int macro_substitute(char *line, char *out);
  40. static int is_macro_start_char(char s);
  41. static int is_macro_char(char s);
  42. static int insert_line(char *line);
  43. static int read_line(char *line);
  44. static void strip_leading_trailing_spaces(char *in, char **out);
  45. static char *get_var_name(char *in, char *name);
  46. static char *get_expression(char *in, char *expr);
  47.  
  48.  
  49.  
  50. int preprocessor(char *filename) {
  51.  
  52.   int i;
  53.  
  54.   buffer = malloc(32*1024);
  55.   if (!buffer) {
  56.     fprintf(stderr, "No room\n");
  57.     return 1;
  58.   }
  59.   allocated = 32*1024;
  60.   codesize = 0;
  61.   macrocount = 0;
  62.   ifdefdepth = 0;
  63.   readoffset = 0;
  64.  
  65.   loopdepth = 0;
  66.   for (i = 0; i < MAXNESTEDLOOPS; i++)
  67.     loopinfo[i].name[0] = '\0';
  68.  
  69.   return insert_file(filename);
  70. }
  71.  
  72.  
  73. int end_of_file() {
  74.  
  75.   if (readoffset >= codesize)    return 1;
  76.   return 0;
  77. }
  78.  
  79.  
  80. int get_line(char *line) {
  81.  
  82.   U32 old;
  83.  
  84.   old = readoffset;
  85.   if (read_line(line))           return 1;
  86.  
  87.   if (strncmp(line, ":for ", 5) == 0) {
  88.     char name[MAXVARNAMELENGTH], expr1[MAXLINELENGTH], expr2[MAXLINELENGTH], *p;
  89.  
  90.     // :for var = expr1 to expr2
  91.     // read var
  92.     p = get_var_name(line+5, name);
  93.     if (!p) {
  94.       fprintf(stderr, "Bad ':for' instruction 1\n");
  95.       return 1;
  96.     }
  97.     if (*p != '=') {
  98.       fprintf(stderr, "Bad ':for' instruction 2\n");
  99.       return 1;
  100.     }
  101.     p = get_expression(p+1, expr1);
  102.     if (!p) {
  103.       fprintf(stderr, "Bad ':for' instruction 3\n");
  104.       return 1;
  105.     }
  106.     if (strncmp(p, "to", 2)) {
  107.       fprintf(stderr, "Bad ':for' instruction 4\n");
  108.       return 1;
  109.     }
  110.     p = get_expression(p+2, expr2);
  111.     if (!p) {
  112.       fprintf(stderr, "Bad ':for' instruction 5\n");
  113.       return 1;
  114.     }
  115.  
  116.     if (create_variable(name))                                  return 1;
  117.     if (evaluate(expr1, &loopinfo[loopdepth].current))          return 1;
  118.     loopinfo[loopdepth].to_expr = malloc(strlen(expr2)+1);
  119.     if (!loopinfo[loopdepth].to_expr) {
  120.       fprintf(stderr, "No room\n");
  121.       return 1;
  122.     }
  123.     strcpy(loopinfo[loopdepth].to_expr, expr2);
  124.     if (set_variable_value(name, loopinfo[loopdepth].current))  return 1;
  125.     loopinfo[loopdepth].startoffset = readoffset;
  126.     strcpy(loopinfo[loopdepth].name, name);
  127.     loopdepth++;
  128.     return get_line(line);
  129.  
  130.   } else if (strncmp(line, ":next", 5) == 0) {
  131.     S32 to;
  132.     if (loopdepth == 0) {
  133.       fprintf(stderr, "Unmatched ':next' encountered\n");
  134.       return 1;
  135.     }
  136.     loopinfo[loopdepth-1].current++;
  137.     if (set_variable_value(loopinfo[loopdepth-1].name,
  138.                            loopinfo[loopdepth-1].current))  return 1;
  139.     if (evaluate(loopinfo[loopdepth-1].to_expr, &to))       return 1;
  140.     if (loopinfo[loopdepth-1].current <= to) {
  141.       readoffset = loopinfo[loopdepth-1].startoffset;
  142.       return get_line(line);
  143.  
  144.     } else {
  145.       loopdepth--;
  146.       if (destroy_variable(loopinfo[loopdepth].name))   return 1;
  147.       free(loopinfo[loopdepth].to_expr);
  148.       loopinfo[loopdepth].name[0] = '\0';
  149.       return get_line(line);
  150.     }
  151.  
  152.   } else if (strncmp(line, ":print ", 7) == 0) {
  153.     char *p;
  154.  
  155.     strip_leading_trailing_spaces(line+7, &p);
  156.     if (*p == '"') {
  157.       char *end;
  158.  
  159.       end = p + strlen(p) - 1;
  160.       if (*end != '"') {
  161.         fprintf(stderr, "Bad ':print'\n");
  162.         return 1;
  163.       }
  164.       *end = '\0';
  165.       printf("%s\n", p+1);
  166.  
  167.     } else {
  168.       S32 v;
  169.       if (evaluate(p, &v))              return 1;
  170.       printf("%d\n", v);
  171.     }
  172.     return get_line(line);
  173.  
  174.   } else if (strncmp(line, ":endif", 6) == 0) {
  175.     return get_line(line);
  176.  
  177.   } else if (strncmp(line, ":var ", 5) == 0) {
  178.     char *p, name[MAXVARNAMELENGTH+1];
  179.     int n;
  180.  
  181.     p = line+5;
  182.     n = 0;
  183.     do {
  184.       p = get_var_name(p, name);
  185.       if (!p) {
  186.         fprintf(stderr, "Syntax error in ':var'\n");
  187.         return 1;
  188.       }
  189.       if (create_variable(name))  return 1;
  190.       n++;
  191.       if ((*p) && (*p != ',')) {
  192.         fprintf(stderr, "Syntax error in ':var'\n");
  193.         return 1;
  194.       }
  195.       if (*p == ',') {
  196.         p++;
  197.         while (*p == ' ')  p++;
  198.         if (!*p) {
  199.           fprintf(stderr, "Syntax error in ':var'\n");
  200.           return 1;
  201.         }
  202.       }
  203.     } while (*p);
  204.  
  205.     if (!n) {
  206.       fprintf(stderr, "Syntax error in ':var'\n");
  207.       return 1;
  208.     }
  209.  
  210.     return get_line(line);
  211.  
  212.   } else if (strncmp(line, ":if ", 4) == 0) {
  213.     S32 value;
  214.     if (evaluate(line+4, &value)) {
  215.       fprintf(stderr, "Failed to evaluate '%s'\n", line+4);
  216.       return 1;
  217.     }
  218.     if (!value) {
  219.       int ifdepth;
  220.       ifdepth = 1;
  221.       do {
  222.         if (read_line(line))   return 1;
  223.         if (strncmp(line, ":if ", 4) == 0)
  224.           ifdepth++;
  225.         if (strncmp(line, ":endif", 6) == 0)
  226.           ifdepth--;
  227.       } while (ifdepth);
  228.     }
  229.     return get_line(line);
  230.  
  231.   } else if (line[0] == ':') {
  232.     char name[MAXVARNAMELENGTH+1], *p;
  233.     S32 value, varvalue;
  234.     int error;
  235.  
  236.     p = get_var_name(line+1, name);
  237.     if (!p) {
  238.       fprintf(stderr, "Syntax error: '%s'\n", line);
  239.       return 1;
  240.     }
  241.     if (read_variable_value(name, &varvalue))  return 1;
  242.     while (*p == ' ')  p++;
  243.     error = 0;
  244.     if ((p[0] == '+') && (p[1] == '=')) {
  245.       error = evaluate(p+2, &value);
  246.       varvalue += value;
  247.     } else if ((p[0] == '-') && (p[1] == '=')) {
  248.       error = evaluate(p+2, &value);
  249.       varvalue -= value;
  250.     } else if ((p[0] == '*') && (p[1] == '=')) {
  251.       error = evaluate(p+2, &value);
  252.       varvalue *= value;
  253.     } else if ((p[0] == '/') && (p[1] == '=')) {
  254.       error = evaluate(p+2, &value);
  255.       if (value == 0) {
  256.         fprintf(stderr, "Division by zero: %s equals 0\n", p+2);
  257.         return 1;
  258.       }
  259.       varvalue /= value;
  260.     } else if (p[0] == '=') {
  261.       error = evaluate(p+1, &varvalue);
  262.     }
  263.     if (error) {
  264.       fprintf(stderr, "Syntax error: '%s'\n", line);
  265.       return 1;
  266.     }
  267.     if (set_variable_value(name, varvalue))  return 1;
  268.     return get_line(line);
  269.  
  270.   } else if (line[0] == '.') {
  271.     fprintf(stderr, "Lines are not allowed to start with a '.'\n");
  272.     return 1;
  273.   }
  274.  
  275.   return 0;
  276. }
  277.  
  278.  
  279. int find_macro(char *name) {
  280.  
  281.   int i;
  282.   char *p;
  283.  
  284.   while (isspace(name[0]))     name++;
  285.   p = name;
  286.   while (is_macro_char(*p))  p++;
  287.   *p = '\0';
  288.  
  289.   for (i = 0; i < macrocount; i++)
  290.      if (strcmp(macros[i][MACRONAME], name) == 0)  return i;
  291.  
  292.   return -1;
  293. }
  294.  
  295. // --------------------------------------------------------------------
  296.  
  297.  
  298. int is_macro_start_char(char s) {
  299.  
  300.   if (isalpha(s) || (s == '_'))     return 1;
  301.   return 0;
  302. }
  303.  
  304.  
  305. int is_macro_char(char s) {
  306.  
  307.   if (isalpha(s) || isdigit(s) || (s == '_'))     return 1;
  308.   return 0;
  309. }
  310.  
  311.  
  312. int insert_file(char *filename) {
  313.  
  314.   FILE *fh;
  315.   char line[MAXLINELENGTH];
  316.  
  317.   fh = fopen(filename, "r");
  318.   if (!fh) {
  319.     fprintf(stderr, "Failed to open file '%s'\n", filename);
  320.     return 1;
  321.   }
  322.  
  323.   do {
  324.     if (fgets(line, MAXLINELENGTH, fh)) {
  325.       int i;
  326.       // convert TAB, linefeed etc to normal spaces
  327.       for(i = 0; i < strlen(line); i++)
  328.         if (line[i] < ' ')  line[i] = ' ';
  329.  
  330.       if (line[0] == '#') {
  331.         if (strncmp(line, "#define ", 8) == 0) {
  332.           if (!ifdefdepth) {
  333.             char temp[MAXLINELENGTH];
  334.             if (macro_substitute(line+8, temp))   return 1;
  335.             if (define_macro(temp))               return 1;
  336.           }
  337.  
  338.         } else if (strncmp(line, "#undef ", 7) == 0) {
  339.           if (!ifdefdepth) {
  340.             int mi;
  341.             mi = find_macro(line+7);
  342.             if (mi >= 0) {
  343.               if (mi != macrocount-1) {
  344.                 macros[mi][MACRONAME]  = macros[macrocount-1][MACRONAME];
  345.                 macros[mi][MACROVALUE] = macros[macrocount-1][MACROVALUE];
  346.               }
  347.               macrocount--;
  348.             }
  349.           }
  350.  
  351.         } else if (strncmp(line, "#ifdef ", 7) == 0) {
  352.           if (ifdefdepth)
  353.             ifdefdepth++;
  354.           else {
  355.             if (find_macro(line+7) < 0)  ifdefdepth++;
  356.           }
  357.  
  358.         } else if (strncmp(line, "#else", 5) == 0) {
  359.           if (ifdefdepth == 1)
  360.             ifdefdepth = 0;
  361.           else if (ifdefdepth == 0)
  362.             ifdefdepth = 1;
  363.  
  364.         } else if (strncmp(line, "#ifndef ", 8) == 0) {
  365.           if (ifdefdepth)
  366.             ifdefdepth++;
  367.           else {
  368.             if (find_macro(line+8) >= 0)  ifdefdepth++;
  369.           }
  370.  
  371.         } else if (strncmp(line, "#endif", 6) == 0) {
  372.           if (ifdefdepth)  ifdefdepth--;
  373.  
  374.         } else if (strncmp(line, "#include ", 9) == 0) {
  375.           if (!ifdefdepth) {
  376.             char *filename;
  377.  
  378.             strip_leading_trailing_spaces(line+9, &filename);
  379.             if (insert_file(filename)) {
  380.               fclose(fh);
  381.               return 1;
  382.             }
  383.           }
  384.  
  385.         } else if (!ifdefdepth) {
  386.           if (insert_line(line)) {
  387.             fclose(fh);
  388.             return 1;
  389.           }
  390.         }
  391.  
  392.       } else if (!ifdefdepth) {
  393.         char output[MAXLINELENGTH];
  394.  
  395.         if (macro_substitute(line, output)) {
  396.           fclose(fh);
  397.           return 1;
  398.         }
  399.         if (insert_line(output)) {
  400.           fclose(fh);
  401.           return 1;
  402.         }
  403.       }
  404.  
  405.     } else {
  406.       fclose(fh);
  407.       return 0;
  408.     }
  409.   } while (fh);
  410.  
  411.   return 1;
  412. }
  413.  
  414.  
  415. int insert_line(char *line) {
  416.  
  417.   int len;
  418.  
  419.   len = strlen(line)+1;
  420.   if (codesize + len >= allocated)  {
  421.     char *newbuffer;
  422.     newbuffer = realloc(buffer, allocated + 32*1024);
  423.     if (!newbuffer)  return 1;
  424.     allocated += 32*1024;
  425.     buffer = newbuffer;
  426.   }
  427.   memcpy(buffer+codesize, line, len);
  428.   codesize += len;
  429.  
  430.   return 0;
  431. }
  432.  
  433.  
  434. int define_macro(char *line) {
  435.  
  436.   char macro[256], *value;
  437.   int p, l;
  438.  
  439.   if (macrocount == MAXMACROS) {
  440.     fprintf(stderr, "Too many macros\n");
  441.     return 1;
  442.   }
  443.  
  444.   p = 0;
  445.   while ((line[p] <= ' ') && (line[p]))    p++;
  446.   l = 0;
  447.   while ((is_macro_char(line[p])) && (l < 255))  macro[l++] = line[p++];
  448.   macro[l] = '\0';
  449.   if ((line[p] != ' ') || (l >= 256)) {
  450.     fprintf(stderr, "Illegal macro definition: #define %s\n", line);
  451.     return 1;
  452.   }
  453.   strip_leading_trailing_spaces(line+p, &value);
  454.  
  455.   if (!is_macro_start_char(macro[0])) {
  456.     fprintf(stderr, "Illegal macro name '%s'\n", macro);
  457.     return 1;
  458.   }
  459.   if (find_macro(macro) != -1) {
  460.     fprintf(stderr, "Dublicate definition of macro '%s'\n", macro);
  461.     return 1;
  462.   }
  463.   macros[macrocount][MACRONAME] = malloc(strlen(macro)+1);
  464.   if (!macros[macrocount][MACRONAME]) {
  465.     fprintf(stderr, "No room for macro\n");
  466.     return 1;
  467.   }
  468.   strcpy(macros[macrocount][MACRONAME], macro);
  469.   macros[macrocount][MACROVALUE] = malloc(strlen(value)+1);
  470.   if (!macros[macrocount][MACROVALUE]) {
  471.     fprintf(stderr, "No room for macro\n");
  472.     return 1;
  473.   }
  474.   strcpy(macros[macrocount][MACROVALUE], value);
  475.  
  476.   macrocount++;
  477.  
  478.   return 0;
  479. }
  480.  
  481.  
  482. int macro_substitute(char *line, char *out) {
  483.  
  484.   int rd, wr, len, checkmacro;
  485.  
  486.   len = strlen(line);
  487.   checkmacro = 1;
  488.   wr = 0;
  489.   for (rd = 0; rd < len; rd++) {
  490.     // don't do macro-substitution inside ""
  491.     if (line[rd] == '"') {
  492.       int quotes;
  493.       out[wr++] = line[rd++];
  494.       quotes = 1;
  495.       while (quotes && (line[rd])) {
  496.         if (line[rd] == '"')  quotes = 0;
  497.         out[wr++] = line[rd++];
  498.       }
  499.     }
  500.     if ((checkmacro) && (is_macro_start_char(line[rd]))) {
  501.       int m;
  502.       for (m = 0; m < macrocount; m++) {
  503.         char *macro, *value;
  504.         int len;
  505.         macro = macros[m][MACRONAME];
  506.         value = macros[m][MACROVALUE];
  507.         len = strlen(macro);
  508.         if ((strncmp(line+rd, macro, len) == 0) && (!is_macro_char(line[rd+len]))) {
  509.           if (wr + strlen(value) > MAXLINELENGTH-1) {
  510.             fprintf(stderr, "Macro-substituted line is too long\n");
  511.             return 1;
  512.           }
  513.           strcpy(out+wr, value);
  514.           wr += strlen(value);
  515.           rd += strlen(macro);
  516.           m = macrocount+1;         // abort
  517.           rd--;
  518.         }
  519.       }
  520.       if (m == macrocount)  out[wr++] = line[rd];
  521.       checkmacro = 0;
  522.  
  523.     } else {
  524.       if (!is_macro_char(line[rd]))
  525.         checkmacro = 1;
  526.       else
  527.         checkmacro = 0;
  528.       out[wr++] = line[rd];
  529.     }
  530.   }
  531.   out[wr] = '\0';
  532.  
  533.   return 0;
  534. }
  535.  
  536.  
  537. int read_line(char *line) {
  538.  
  539.   if (readoffset >= codesize)    return 1;
  540.   strcpy(line, buffer+readoffset);
  541.   readoffset += strlen(line)+1;
  542.  
  543.   return 0;
  544. }
  545.  
  546.  
  547. void strip_leading_trailing_spaces(char *in, char **out) {
  548.  
  549.   while (*in == ' ')  in++;
  550.   *out = in;
  551.   if (!*in)                   return;
  552.  
  553.   in += strlen(in)-1;
  554.   while (*in == ' ')  *in = '\0', in--;
  555. }
  556.  
  557.  
  558. char *get_var_name(char *in, char *name) {
  559.  
  560.   int len;
  561.  
  562.   while (*in == ' ')   in++;
  563.   if (!is_macro_start_char(*in))  return NULL;
  564.  
  565.   len = 0;
  566.   while ((len < MAXVARNAMELENGTH) && (is_macro_char(*in)))
  567.     name[len++] = *in++;
  568.   if (len > MAXVARNAMELENGTH)  return NULL;
  569.   name[len] = '\0';
  570.  
  571.   while (*in == ' ')  in++;
  572.  
  573.   return in;
  574. }
  575.  
  576.  
  577. char *get_expression(char *in, char *expr) {
  578.  
  579.   int bm, len, done;
  580.  
  581.   bm = 0;
  582.   len = 0;
  583.   done = 0;
  584.   do {
  585.     if (*in == ' ') {
  586.       in++;
  587.       if ((len) && (!bm))     done = 1;
  588.     } else if (*in == '(') {
  589.       expr[len++] = *in++;
  590.       bm++;
  591.     } else if (*in == ')') {
  592.       expr[len++] = *in++;
  593.       bm--;
  594.     } else
  595.       expr[len++] = *in++;
  596.  
  597.     if (!*in)                 done = 1;
  598.     if ((bm) && (len))        done = 1;
  599.   } while (!done);
  600.  
  601.   if (bm) {
  602.     fprintf(stderr, "Bad expression, or unmatched brackets\n");
  603.     return NULL;
  604.   }
  605.   expr[len] = '\0';
  606.   while (*in == ' ')  in++;
  607.  
  608.   return in;
  609. }
  610.