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