Advertisement
overloop

excel_formula_compiler.c

Apr 10th, 2013
209
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 9.72 KB | None | 0 0
  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <stdlib.h>
  4.  
  5. #define MAX_OPERANDS 10
  6. #define MAX_DICT 1024
  7. #define FILE_BUF 1024
  8.  
  9. /* dict.dat
  10. add2    ($0+$1)
  11. add3    ($0+$1+$2)
  12. add4    ($0+$1+$2+$3)
  13. add5    ($0+$1+$2+$3+$4)
  14. add6    ($0+$1+$2+$3+$4+$5)
  15. mul2    ($0*$1)
  16. mul3    ($0*$1*$2)
  17. mul4    ($0*$1*$2*$3)
  18. mul5    ($0*$1*$2*$3*$4)
  19. mul6    ($0*$1*$2*$3*$4*$5)
  20. div2    ($0/$1)
  21. sub2    ($0-$1)
  22. sub1    (-$0)
  23. ifthen  И($0)*($1)
  24. and2    И($0;$1)*($2)
  25. interp  И($0>=$1;$0<$2)*(($0-$1)/($2-$1)*($4-$3)+$3)
  26.  
  27.  */
  28.  
  29. /*char* test = "add3(ifthen(B1<7;add6(interp(A1;0,45;0,55;4;4);interp(A1;0,55;0,65;4;3,5);interp(A1;0,65;0,75;3,5;3);interp(A1;0,75;0,85;3;2);interp(A1;0,85;0,95;0;0);interp(A1;0,95;1,05;0;0)));and2(B1>=7;B1<17;add6(interp(A1;0,45;0,55;5;5);interp(A1;0,55;0,65;5;4,5);interp(A1;0,65;0,75;4,5;4);interp(A1;0,75;0,85;4;3);interp(A1;0,85;0,95;3;2,5);interp(A1;0,95;1,05;2,5;2)));ifthen(B1>=17;add6(interp(A1;0,45;0,55;0;0);interp(A1;0,55;0,65;0;0);interp(A1;0,65;0,75;6;6);interp(A1;0,75;0,85;6;5,5);interp(A1;0,85;0,95;5,5;5);interp(A1;0,95;1,05;5;4,5))))";*/
  30.  
  31. struct excel_exp;
  32.  
  33. char* excel_alloc_string(size_t len);
  34.  
  35. struct excel_rewrite {
  36.     char* name[MAX_DICT];
  37.     char* val[MAX_DICT];
  38.     int num;
  39. } excel_rewrite_dict;
  40.  
  41. /** Читает список функций из файла dict.dat, заполняет ими excel_rewrite_dict.
  42.  *
  43.  */
  44. void excel_init_dict() {
  45.     FILE* f = fopen("dict.dat","r");
  46.     memset(&excel_rewrite_dict,0,sizeof(struct excel_rewrite));
  47.    
  48.     char buf[FILE_BUF];
  49.     if ( f==0 )
  50.     {
  51.         fprintf(stderr,"error opening file dict.dat\n");
  52.         return ;
  53.     }
  54.     int n = 0;
  55.     while (!feof(f))
  56.     {
  57.         fgets(buf,FILE_BUF,f);
  58.         char* p = strchr(buf,'\t');
  59.         int l1 = strlen(buf);
  60.         int l2 = strlen(p);
  61.        
  62.         if (p) {
  63.             char* name = excel_alloc_string(l1-l2);
  64.             strncat(name,buf,l1-l2);
  65.             char* val = excel_alloc_string(l2-1);
  66.             strncat(val,p+1,l2-2);
  67.            
  68.             excel_rewrite_dict.name[n] = name;
  69.             excel_rewrite_dict.val[n] = val;
  70.             ++n;
  71.         }
  72.     }
  73.     excel_rewrite_dict.num = n-1;
  74. }
  75.  
  76. /** Освобождает память, очищая список определенных функций
  77.  *
  78.  */
  79. void excel_uninit_dict() {
  80.     int i;
  81.     for (i=0;i<excel_rewrite_dict.num;i++)
  82.     {
  83.         free(excel_rewrite_dict.name[i]);
  84.         free(excel_rewrite_dict.val[i]);
  85.     }
  86. }
  87.  
  88. /** Выражение: имя, операнды, значение.
  89.  *  Операнды могут быть как строками op, так и вложеными выражениями ope
  90.  */
  91. struct excel_exp {
  92.     char* name;
  93.     char* op[MAX_OPERANDS];
  94.     struct excel_exp* ope[MAX_OPERANDS];
  95.     int num;
  96.     char* val;
  97. };
  98.  
  99. struct excel_exp* excel_parse(char* exp);
  100.  
  101. /** Выделяет память под выражение
  102.  *
  103.  */
  104. struct excel_exp* excel_alloc_exp() {
  105.     struct excel_exp* exp;
  106.     exp = malloc(sizeof(struct excel_exp));
  107.     memset(exp,0,sizeof(struct excel_exp));
  108. }
  109.  
  110. /** Выделяет память под строку
  111.  *
  112.  */
  113. char* excel_alloc_string(size_t len) {
  114.     char* s = (char*) malloc(len+1);
  115.     memset(s,0,len+1);
  116.     return s;
  117. }
  118.  
  119. /** Определяет является ли строка выражением.
  120.  *  Другими словами, содержит ли строка ';'
  121.  */
  122. int excel_isexp(char* exp) {
  123.     if (strchr(exp,';')!=0) {
  124.         //printf("%s is exp",exp);
  125.         return 1;
  126.     }
  127.     //printf("%s is not exp",exp);
  128.     return 0;
  129. }
  130.  
  131. /** Определяет есть ли в выражении нераспарсеные вложеные выражения
  132.  *
  133.  */
  134. int excel_isleaf(struct excel_exp* exp) {
  135.     int i=-1;
  136.     while (++i<exp->num) {
  137.         if (exp->ope[i]) return 0;
  138.     }
  139.     return 1;
  140. }
  141.  
  142. /** Очищает память, выделенную под операнды и имя функции
  143.  *
  144.  */
  145. void excel_free_op(struct excel_exp* exp) {
  146.     int j;
  147.     free(exp->name);
  148.     exp->name = 0;
  149.     for (j=0;j<exp->num;j++)
  150.     {
  151.         free(exp->op[j]);
  152.         free(exp->ope[j]);
  153.         exp->op[j] = 0;
  154.         exp->ope[j] = 0;
  155.     }
  156.     exp->num = 0;
  157. }
  158.  
  159. /** Подсчитывает число использования операндов в шаблоне
  160.  *  Операнды в шаблоне обозначаются как $0, $1 ... $9
  161.  *  @todo escaping \$
  162.  */
  163. int excel_count_vars(char* val) {
  164.     int n = 0;
  165.     char* p = val;
  166.     while (p) {
  167.         p = strchr(p+1,'$');
  168.         if (p) n++;
  169.     }
  170.     return n;
  171. }
  172.  
  173. /** Определяет длинну самого длинного операнда
  174.  *
  175.  */
  176. int excel_max_op_length(struct excel_exp* exp) {
  177.     int maxl = 0;
  178.     int li = 0;
  179.     int j;
  180.     for (j=0;j<exp->num;j++)
  181.     {
  182.         li = strlen(exp->op[j]);
  183.         if (li>maxl) maxl = li;
  184.     }
  185.     return maxl;
  186. }
  187.  
  188. /** Очищает память выделенную под выражение
  189.  *
  190.  */
  191. void excel_free_exp(struct excel_exp* exp) {
  192.     excel_free_op(exp);
  193.     free(exp->val);
  194.     free(exp);
  195. }
  196.  
  197. /** Переписывает выражение, используя словарь excel_rewrite_dict
  198.  *  Находит в словаре шаблон по имени функции и подставляет в него операнды.
  199.  *  Если не найдет поставит undefined
  200.  */
  201. void excel_rewrite(struct excel_exp* exp) {
  202.     int i,j;
  203.     for (i=0;i<excel_rewrite_dict.num;i++)
  204.     {
  205.         if (strcmp(exp->name,excel_rewrite_dict.name[i]) == 0)
  206.         {
  207.             // на результирующую строку будет достаточно n символов, где
  208.             // n = длинна шаблона + число использования операндов в шаблоне * длинна самого длинного операнда
  209.             int li = excel_max_op_length(exp);
  210.             int n = excel_count_vars(excel_rewrite_dict.val[i]);
  211.             int l = li * n + strlen(excel_rewrite_dict.val[i]);
  212.             char* val = excel_alloc_string(l);
  213.            
  214.             char* p = excel_rewrite_dict.val[i];
  215.             while(*p) {
  216.                 if (*p == '$') {
  217.                     ++p;
  218.                     n = (*p) - '0';
  219.                     if (n>=0 && n<MAX_OPERANDS && exp->op[n])
  220.                         strcat(val,exp->op[n]);
  221.                 } else {
  222.                     strncat(val,p,1);
  223.                 }
  224.                 ++p;
  225.             }
  226.             excel_free_op(exp);
  227.             exp->val = val;
  228.             return;
  229.         }
  230.     }
  231.     fprintf(stderr,"%s undefined\n",exp->name);
  232.     excel_free_op(exp);
  233.     exp->val = "undefined";
  234. }
  235.  
  236. /** Поднимается по дереву выражений, переписывая функции по словарю в бездетных
  237.  *  (крайних) нодах, разбирая дерево.
  238.  *  Если всё дерево разобрано, возвращает 1
  239.  */
  240. int excel_collapse(struct excel_exp* exp) {
  241.     int i;
  242.    
  243.     if (exp->val)
  244.         return 1;
  245.     if (excel_isleaf(exp))
  246.         excel_rewrite(exp);
  247.    
  248.     for (i=0;i<exp->num;i++)
  249.     {
  250.         if (exp->ope[i]) {
  251.             excel_collapse(exp->ope[i]);
  252.             if (exp->ope[i]->val) {
  253.                
  254.                 free(exp->op[i]);
  255.                 exp->op[i] = exp->ope[i]->val;
  256.                
  257.                 excel_free_op(exp->ope[i]);
  258.                 free(exp->ope[i]);
  259.                 exp->ope[i] = 0;
  260.             }
  261.         }
  262.     }
  263.     return 0;
  264. }
  265.  
  266. /** Парсит строку в дерево выражений, потом переписывает фунции двигаясь
  267.  *  от ветвей к корню. В exp->val оказывается результат
  268.  */
  269. struct excel_exp* excel_parse(char* exp) {
  270.    
  271.     struct excel_exp* root = excel_alloc_exp();
  272.    
  273.     /* идем по строке отмечая ; не вложеные в скобки, также отмечаем первую
  274.      * открывающую и последнюю закрывающую скобку, чтобы выделить называние
  275.      * функции и операнды
  276.      * название_функции(операнд;операнд;вложеная_функция(операнд;операнд);операнд)
  277.      * semicolon:     [0]     [1]     [2]                               [3]     [4]
  278.      * j==5; exp->num = j-1
  279.      */
  280.     size_t l = strlen(exp);
  281.     int semicolon[MAX_OPERANDS+1];
  282.     int parenthesis = 0;
  283.     int i = -1;
  284.     int j = 0;
  285.     while (++i<l) {
  286.         switch (exp[i]) {
  287.             case '(' : if (j==0) {semicolon[j++] = i;} parenthesis++; break;
  288.             case ')' : parenthesis--; if (parenthesis == 0) semicolon[j++] = i; break;
  289.             case ';' : if (parenthesis == 1) semicolon[j++] = i; break;
  290.         }
  291.         if (j>MAX_OPERANDS+1) {
  292.             fprintf(stderr,"MAX_OPERANDS exceeded in %s\n",exp);
  293.             return 0;
  294.         }
  295.     }
  296.     if (parenthesis > 0)
  297.         fprintf(stderr,"unmatched parenthesis, need %i ) more\n",parenthesis);
  298.     if (parenthesis < 0)
  299.         fprintf(stderr,"unmatched parenthesis, need %i ( more\n",-parenthesis);
  300.     --j;
  301.    
  302.     size_t li = semicolon[0];
  303.     char* name = excel_alloc_string(li);
  304.     strncpy(name,exp,li);
  305.     root->name = name;
  306.     root->num = j;
  307.    
  308.     for (i=0;i<j;i++)
  309.     {
  310.         li = semicolon[i+1] - semicolon[i] - 1;
  311.        
  312.         if (li>0)
  313.         {
  314.             char* opi = excel_alloc_string(li);
  315.             strncpy(opi, exp + semicolon[i]+1,li);
  316.            
  317.             if (excel_isexp(opi))
  318.                 root->ope[i] = excel_parse(opi);
  319.             root->op[i] = opi;
  320.         } else {
  321.             root->num = root->num - 1;
  322.         }
  323.     }
  324.    
  325.     // трясём дерево пока не упадёт
  326.     int r = 0;
  327.     while (r != 1) {
  328.         r = excel_collapse(root);
  329.     }
  330.    
  331.     return root;
  332. }
  333.  
  334. int main(int argc, char** argv) {
  335.     char* exp_string = 0;
  336.     excel_init_dict();
  337.     if (excel_rewrite_dict.num < 1) {
  338.         fprintf(stderr,"dict.dat has no records, please create dict.dat\n");
  339.         fprintf(stderr,"dict.dat format: each line has the name of the function\n");
  340.         fprintf(stderr,"and value to replace it with, separated with tab\n");
  341.         fprintf(stderr,"example:\nadd2  ($0+$1)\nmul2   ($0*$1)\n");
  342.         return 0;
  343.     }
  344.  
  345.     if (argc>1 && strcmp(argv[1],"--help")!=0 && strcmp(argv[1],"-h")!=0 && strcmp(argv[1],"/?")!=0)
  346.     {
  347.         exp_string = argv[1];
  348.     }
  349.     else
  350.     {
  351.         printf("usage: compiler.exe \"formula\"\nexample: compiler.exe \"add2(mul2(A1;A2);2)\"\n");
  352.         return 0;
  353.     }
  354.    
  355.     struct excel_exp* exp = excel_parse(exp_string);
  356.     printf("=%s",exp->val);
  357.     excel_free_exp(exp);
  358.    
  359.     excel_uninit_dict();
  360.     return 0;
  361. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement