languages/compiler/generator.c

Go to the documentation of this file.
00001 
00002 #include <limits.h>  /* for INT_MAX */
00003 #include <stdio.h>   /* for fprintf etc */
00004 #include <stdlib.h>  /* for free etc */
00005 #include <string.h>  /* for strlen */
00006 #include "header.h"
00007 
00008 /* Define this to get warning messages when optimisations can't be used. */
00009 /* #define OPTIMISATION_WARNINGS */
00010 
00011 /* recursive use: */
00012 
00013 static void generate(struct generator * g, struct node * p);
00014 
00015 enum special_labels {
00016 
00017     x_return = -1
00018 
00019 };
00020 
00021 static int new_label(struct generator * g) {
00022     return g->next_label++;
00023 }
00024 
00025 /* Output routines */
00026 static void output_str(FILE * outfile, struct str * str) {
00027 
00028     char * s = b_to_s(str_data(str));
00029     fprintf(outfile, "%s", s);
00030     free(s);
00031 }
00032 
00033 static void wch(struct generator * g, int ch) {
00034     str_append_ch(g->outbuf, ch); /* character */
00035 }
00036 
00037 static void wnl(struct generator * g) {
00038     str_append_ch(g->outbuf, '\n'); /* newline */
00039     g->line_count++;
00040 }
00041 
00042 static void ws(struct generator * g, const char * s) {
00043     str_append_string(g->outbuf, s); /* string */
00044 }
00045 
00046 static void wi(struct generator * g, int i) {
00047     str_append_int(g->outbuf, i); /* integer */
00048 }
00049 
00050 static void wh_ch(struct generator * g, int i) {
00051     str_append_ch(g->outbuf, "0123456789ABCDEF"[i & 0xF]); /* hexchar */
00052 }
00053 
00054 static void wh(struct generator * g, int i) {
00055     if (i >> 4) wh(g, i >> 4);
00056     wh_ch(g, i); /* hex integer */
00057 }
00058 
00059 static void wi3(struct generator * g, int i) {
00060     if (i < 100) wch(g, ' ');
00061     if (i < 10)  wch(g, ' ');
00062     wi(g, i); /* integer (width 3) */
00063 }
00064 
00065 static void wvn(struct generator * g, struct name * p) {  /* variable name */
00066 
00067     int ch = "SBIrxg"[p->type];
00068     switch (p->type) {
00069         case t_external:
00070             ws(g, g->options->externals_prefix); break;
00071         case t_string:
00072         case t_boolean:
00073         case t_integer:
00074             if (g->options->make_lang == LANG_C) {
00075                 wch(g, ch); wch(g, '['); wi(g, p->count); wch(g, ']'); return;
00076             }
00077             /* FALLTHRU */
00078         default:
00079             wch(g, ch); wch(g, '_');
00080     }
00081     str_append_b(g->outbuf, p->b);
00082 }
00083 
00084 static void wv(struct generator * g, struct name * p) {  /* reference to variable */
00085     if (p->type < t_routine && g->options->make_lang == LANG_C) ws(g, "z->");
00086     wvn(g, p);
00087 }
00088 
00089 static void wlitarray(struct generator * g, symbol * p) {  /* write literal array */
00090 
00091     {
00092         int i;
00093         for (i = 0; i < SIZE(p); i++) {
00094             int ch = p[i];
00095             if (32 <= ch && ch < 127) {
00096                 wch(g, '\'');
00097                 switch (ch) {
00098                     case '\'':
00099                     case '\\': wch(g, '\\');
00100                     default:   wch(g, ch);
00101                 }
00102                 wch(g, '\'');
00103             }  else {
00104                 wch(g, '0'); wch(g, 'x'); wh(g, ch);
00105             }
00106             if (i < SIZE(p) - 1) ws(g, ", ");
00107         }
00108     }
00109 }
00110 
00111 static void wlitref(struct generator * g, symbol * p) {  /* write ref to literal array */
00112 
00113     if (SIZE(p) == 0) ws(g, "0"); else {
00114         struct str * s = g->outbuf;
00115         g->outbuf = g->declarations;
00116         ws(g, "static const symbol s_"); wi(g, g->literalstring_count); ws(g, "[] = { ");
00117         wlitarray(g, p);
00118         ws(g, " };\n");
00119         g->outbuf = s;
00120         ws(g, "s_"); wi(g, g->literalstring_count);
00121         g->literalstring_count++;
00122     }
00123 }
00124 
00125 
00126 static void wm(struct generator * g) {       /* margin */
00127     int i;
00128     for (i = 0; i < g->margin; i++) ws(g, "    ");
00129 }
00130 
00131 static void wc(struct generator * g, struct node * p) { /* comment */
00132 
00133     ws(g, " /* ");
00134     switch (p->type) {
00135         case c_mathassign:
00136         case c_plusassign:
00137         case c_minusassign:
00138         case c_multiplyassign:
00139         case c_divideassign:
00140         case c_eq:
00141         case c_ne:
00142         case c_gr:
00143         case c_ge:
00144         case c_ls:
00145         case c_le:
00146             if (p->name) {
00147                 str_append_b(g->outbuf, p->name->b);
00148                 ws(g, " ");
00149             }
00150             ws(g, (char *) name_of_token(p->type));
00151             ws(g, " <integer expression>");
00152             break;
00153         default:
00154             ws(g, (char *) name_of_token(p->type));
00155             if (p->name) {
00156                 ws(g, " ");
00157                 str_append_b(g->outbuf, p->name->b);
00158             }
00159     }
00160     ws(g, ", line "); wi(g, p->line_number); ws(g, " */");
00161     wnl(g);
00162 }
00163 
00164 static void wms(struct generator * g, const char * s) {
00165     wm(g); ws(g, s);   } /* margin + string */
00166 
00167 static void wbs(struct generator * g) { /* block start */
00168     wms(g, "{   ");
00169     g->margin++;
00170 }
00171 
00172 static void wbe(struct generator * g) {    /* block end */
00173 
00174     if (g->line_labelled == g->line_count) { wms(g, ";"); wnl(g); }
00175     g->margin--;
00176     wms(g, "}"); wnl(g);
00177 }
00178 
00179 static void w(struct generator * g, const char * s);
00180 
00181 static void wk(struct generator * g, struct node * p) {     /* keep c */
00182     ++g->keep_count;
00183     if (p->mode == m_forward) {
00184         ws(g, "int c"); wi(g, g->keep_count); w(g, " = ~zc;");
00185     } else {
00186         ws(g, "int m"); wi(g, g->keep_count); w(g, " = ~zl - ~zc; (void)m");
00187         wi(g, g->keep_count); ws(g, ";");
00188     }
00189 }
00190 
00191 static void wrestore(struct generator * g, struct node * p, int keep_token) {     /* restore c */
00192     if (p->mode == m_forward) {
00193         w(g, "~zc = c");
00194     } else {
00195         w(g, "~zc = ~zl - m");
00196     }
00197     wi(g, keep_token); ws(g, ";");
00198 }
00199 
00200 static void wrestorelimit(struct generator * g, struct node * p, int keep_token) {     /* restore limit c */
00201     if (p->mode == m_forward) {
00202         w(g, "~zl += mlimit");
00203     } else {
00204         w(g, "~zlb = mlimit");
00205     }
00206     wi(g, keep_token); ws(g, ";");
00207 }
00208 
00209 static void winc(struct generator * g, struct node * p) {     /* increment c */
00210     w(g, p->mode == m_forward ? "~zc++;" :
00211                                 "~zc--;");
00212 }
00213 
00214 static void wsetl(struct generator * g, int n) {
00215 
00216     g->margin--;
00217     wms(g, "lab"); wi(g, n); wch(g, ':'); wnl(g);
00218     g->line_labelled = g->line_count;
00219     g->margin++;
00220 }
00221 
00222 static void wgotol(struct generator * g, int n) {
00223     wms(g, "goto lab"); wi(g, n); wch(g, ';'); wnl(g);
00224 }
00225 
00226 static void wf(struct generator * g, struct node * p) {          /* fail */
00227     if (g->failure_keep_count != 0) {
00228         ws(g, "{ ");
00229         if (g->failure_keep_count > 0) {
00230             wrestore(g, p, g->failure_keep_count);
00231         } else {
00232             wrestorelimit(g, p, -g->failure_keep_count);
00233         }
00234         wch(g, ' ');
00235     }
00236     switch (g->failure_label)
00237     {
00238         case x_return:
00239            ws(g, "return 0;");
00240            break;
00241         default:
00242            ws(g, "goto lab");
00243            wi(g, g->failure_label);
00244            wch(g, ';');
00245            g->label_used = 1;
00246     }
00247     if (g->failure_keep_count != 0) ws(g, " }");
00248 }
00249 
00250 static void wlim(struct generator * g, struct node * p) {     /* if at limit fail */
00251 
00252     w(g, p->mode == m_forward ? "if (~zc >= ~zl) " :
00253                                 "if (~zc <= ~zlb) ");
00254     wf(g, p);
00255 }
00256 
00257 static void wp(struct generator * g, const char * s, struct node * p) { /* formatted write */
00258     int i = 0;
00259     int l = strlen(s);
00260     until (i >= l) {
00261         int ch = s[i++];
00262         if (ch != '~') wch(g, ch); else
00263         switch(s[i++]) {
00264             default:  wch(g, s[i - 1]); continue;
00265             case 'C': wc(g, p); continue;
00266             case 'k': wk(g, p); continue;
00267             case 'i': winc(g, p); continue;
00268             case 'l': wlim(g, p); continue;
00269             case 'f': wf(g, p); continue;
00270             case 'M': wm(g); continue;
00271             case 'N': wnl(g); continue;
00272             case '{': wbs(g); continue;
00273             case '}': wbe(g); continue;
00274             case 'S': ws(g, g->S[s[i++] - '0']); continue;
00275             case 'I': wi(g, g->I[s[i++] - '0']); continue;
00276             case 'J': wi3(g, g->I[s[i++] - '0']); continue;
00277             case 'V': wv(g, g->V[s[i++] - '0']); continue;
00278             case 'W': wvn(g, g->V[s[i++] - '0']); continue;
00279             case 'L': wlitref(g, g->L[s[i++] - '0']); continue;
00280             case 'A': wlitarray(g, g->L[s[i++] - '0']); continue;
00281             case '+': g->margin++; continue;
00282             case '-': g->margin--; continue;
00283             case '$': /* insert_s, insert_v etc */
00284                 wch(g, p->literalstring == 0 ? 'v' : 's');
00285                 continue;
00286             case 'p': ws(g, g->options->externals_prefix); continue;
00287             case 'z':
00288                 if (g->options->make_lang == LANG_C) ws(g, "z->");
00289                 continue;
00290             case 'Z':
00291                 if (g->options->make_lang == LANG_C) ws(g, s[i] == ')' ? "z" : "z, ");
00292                 continue;
00293         }
00294     }
00295 }
00296 
00297 static void w(struct generator * g, const char * s) { wp(g, s, 0); }
00298 
00299 static void generate_AE(struct generator * g, struct node * p) {
00300     char * s;
00301     switch (p->type) {
00302         case c_name:
00303             wv(g, p->name); break;
00304         case c_number:
00305             wi(g, p->number); break;
00306         case c_maxint:
00307             ws(g, "MAXINT"); break;
00308         case c_minint:
00309             ws(g, "MININT"); break;
00310         case c_neg:
00311             wch(g, '-'); generate_AE(g, p->right); break;
00312         case c_multiply:
00313             s = " * "; goto label0;
00314         case c_plus:
00315             s = " + "; goto label0;
00316         case c_minus:
00317             s = " - "; goto label0;
00318         case c_divide:
00319             s = " / ";
00320         label0:
00321             wch(g, '('); generate_AE(g, p->left);
00322             ws(g, s); generate_AE(g, p->right); wch(g, ')'); break;
00323         case c_sizeof:
00324             g->V[0] = p->name;
00325             w(g, "SIZE(~V0)"); break;
00326         case c_cursor:
00327             w(g, "~zc"); break;
00328         case c_limit:
00329             w(g, p->mode == m_forward ? "~zl" : "~zlb"); break;
00330         case c_size:
00331             w(g, "SIZE(~zp)"); break;
00332             break;
00333     }
00334 }
00335 
00336 /* K_needed() tests to see if we really need to keep c. Not true when the
00337    the command does not touch the cursor. This and repeat_score() could be
00338    elaborated almost indefinitely.
00339 */
00340 
00341 static int K_needed(struct generator * g, struct node * p) {
00342     until (p == 0) {
00343         switch (p->type) {
00344             case c_dollar:
00345             case c_leftslice:
00346             case c_rightslice:
00347             case c_mathassign:
00348             case c_plusassign:
00349             case c_minusassign:
00350             case c_multiplyassign:
00351             case c_divideassign:
00352             case c_eq:
00353             case c_ne:
00354             case c_gr:
00355             case c_ge:
00356             case c_ls:
00357             case c_le:
00358             case c_sliceto:
00359             case c_true:
00360             case c_false:
00361             case c_debug:
00362                 break;
00363 
00364             case c_call:
00365                 if (K_needed(g, p->name->definition)) return true;
00366                 break;
00367 
00368             case c_bra:
00369                 if (K_needed(g, p->left)) return true;
00370                 break;
00371 
00372             default: return true;
00373         }
00374         p = p->right;
00375     }
00376     return false;
00377 }
00378 
00379 static int repeat_score(struct generator * g, struct node * p) {
00380     int score = 0;
00381     until (p == 0)
00382     {
00383         switch (p->type) {
00384             case c_dollar:
00385             case c_leftslice:
00386             case c_rightslice:
00387             case c_mathassign:
00388             case c_plusassign:
00389             case c_minusassign:
00390             case c_multiplyassign:
00391             case c_divideassign:
00392             case c_eq:
00393             case c_ne:
00394             case c_gr:
00395             case c_ge:
00396             case c_ls:
00397             case c_le:
00398             case c_sliceto:   /* case c_not: must not be included here! */
00399             case c_debug:
00400                 break;
00401 
00402             case c_call:
00403                 score += repeat_score(g, p->name->definition);
00404                 break;
00405 
00406             case c_bra:
00407                 score += repeat_score(g, p->left);
00408                 break;
00409 
00410             case c_name:
00411             case c_literalstring:
00412             case c_next:
00413             case c_grouping:
00414             case c_non:
00415             case c_hop:
00416                 score = score + 1; break;
00417 
00418             default: score = 2; break;
00419         }
00420         p = p->right;
00421     }
00422     return score;
00423 }
00424 
00425 /* tests if an expression requires cursor reinstatement in a repeat */
00426 
00427 static int repeat_restore(struct generator * g, struct node * p) {
00428     return repeat_score(g, p) >= 2;
00429 }
00430 
00431 static void generate_bra(struct generator * g, struct node * p) {
00432     p = p->left;
00433     until (p == 0) { generate(g, p); p = p->right; }
00434 }
00435 
00436 static void generate_and(struct generator * g, struct node * p) {
00437     int keep_c = 0;
00438     if (K_needed(g, p->left)) {
00439         wp(g, "~{~k~C", p);
00440         keep_c = g->keep_count;
00441     } else {
00442         wp(g, "~M~C", p);
00443     }
00444     p = p->left;
00445     until (p == 0) {
00446         generate(g, p);
00447         if (keep_c && p->right != 0) {
00448             w(g, "~M"); wrestore(g, p, keep_c); w(g, "~N");
00449         }
00450         p = p->right;
00451     }
00452     if (keep_c) w(g, "~}");
00453 }
00454 
00455 static void generate_or(struct generator * g, struct node * p) {
00456     int keep_c = 0;
00457 
00458     int used = g->label_used;
00459     int a0 = g->failure_label;
00460     int a1 = g->failure_keep_count;
00461 
00462     int out_lab = new_label(g);
00463 
00464     if (K_needed(g, p->left)) {
00465         wp(g, "~{~k~C", p);
00466         keep_c = g->keep_count;
00467     } else {
00468         wp(g, "~M~C", p);
00469     }
00470     p = p->left;
00471     g->failure_keep_count = 0;
00472     until (p->right == 0) {
00473         g->failure_label = new_label(g);
00474         g->label_used = 0;
00475         generate(g, p);
00476         wgotol(g, out_lab);
00477         if (g->label_used)
00478             wsetl(g, g->failure_label);
00479         if (keep_c) {
00480             w(g, "~M"); wrestore(g, p, keep_c); w(g, "~N");
00481         }
00482         p = p->right;
00483     }
00484     g->label_used = used;
00485     g->failure_label = a0;
00486     g->failure_keep_count = a1;
00487 
00488     generate(g, p);
00489     if (keep_c) w(g, "~}");
00490     wsetl(g, out_lab);
00491 }
00492 
00493 static void generate_backwards(struct generator * g, struct node * p) {
00494 
00495     wp(g,"~M~zlb = ~zc; ~zc = ~zl;~C~N", p);
00496     generate(g, p->left);
00497     w(g, "~M~zc = ~zlb;~N");
00498 }
00499 
00500 
00501 static void generate_not(struct generator * g, struct node * p) {
00502     int keep_c = 0;
00503 
00504     int used = g->label_used;
00505     int a0 = g->failure_label;
00506     int a1 = g->failure_keep_count;
00507 
00508     if (K_needed(g, p->left)) {
00509         wp(g, "~{~k~C", p);
00510         keep_c = g->keep_count;
00511     } else {
00512         wp(g, "~M~C", p);
00513     }
00514 
00515     g->failure_label = new_label(g);
00516     g->label_used = 0;
00517     g->failure_keep_count = 0;
00518     generate(g, p->left);
00519 
00520     {
00521         int l = g->failure_label;
00522         int u = g->label_used;
00523 
00524         g->label_used = used;
00525         g->failure_label = a0;
00526         g->failure_keep_count = a1;
00527 
00528         wp(g, "~M~f~N", p);
00529         if (u)
00530             wsetl(g, l);
00531     }
00532     if (keep_c) {
00533         w(g, "~M"); wrestore(g, p, keep_c); w(g, "~N~}");
00534     }
00535 }
00536 
00537 
00538 static void generate_try(struct generator * g, struct node * p) {
00539     int keep_c = 0;
00540     if (K_needed(g, p->left)) {
00541         wp(g, "~{~k~C", p);
00542         keep_c = g->keep_count;
00543     } else {
00544         wp(g, "~-~M   ~+~C", p);
00545     }
00546     g->failure_keep_count = keep_c;
00547 
00548     g->failure_label = new_label(g);
00549     g->label_used = 0;
00550     generate(g, p->left);
00551 
00552     if (g->label_used)
00553         wsetl(g, g->failure_label);
00554 
00555     if (keep_c) w(g, "~}");
00556 }
00557 
00558 static void generate_set(struct generator * g, struct node * p) {
00559     g->V[0] = p->name; wp(g, "~M~V0 = 1;~C", p);
00560 }
00561 
00562 static void generate_unset(struct generator * g, struct node * p) {
00563     g->V[0] = p->name; wp(g, "~M~V0 = 0;~C", p);
00564 }
00565 
00566 static void generate_fail(struct generator * g, struct node * p) {
00567     generate(g, p->left);
00568     wp(g, "~M~f~C", p);
00569 }
00570 
00571 /* generate_test() also implements 'reverse' */
00572 
00573 static void generate_test(struct generator * g, struct node * p) {
00574     int keep_c = 0;
00575     if (K_needed(g, p->left)) {
00576         keep_c = ++g->keep_count;
00577         w(g, p->mode == m_forward ? "~{int c_test" :
00578                                     "~{int m_test");
00579         wi(g, keep_c);
00580         w(g, p->mode == m_forward ? " = ~zc;" :
00581                                     " = ~zl - ~zc;");
00582         wp(g, "~C", p);
00583     } else wp(g, "~M~C", p);
00584 
00585     generate(g, p->left);
00586 
00587     if (keep_c) {
00588         w(g, p->mode == m_forward ? "~M~zc = c_test" :
00589                                     "~M~zc = ~zl - m_test");
00590         wi(g, keep_c);
00591         wp(g, ";~N~}", p);
00592     }
00593 }
00594 
00595 static void generate_do(struct generator * g, struct node * p) {
00596     int keep_c = 0;
00597     if (K_needed(g, p->left)) {
00598         wp(g, "~{~k~C", p);
00599         keep_c = g->keep_count;
00600     } else {
00601         wp(g, "~M~C", p);
00602     }
00603 
00604     g->failure_label = new_label(g);
00605     g->label_used = 0;
00606     g->failure_keep_count = 0;
00607     generate(g, p->left);
00608 
00609     if (g->label_used)
00610         wsetl(g, g->failure_label);
00611     if (keep_c) {
00612         w(g, "~M"); wrestore(g, p, keep_c);
00613         w(g, "~N~}");
00614     }
00615 }
00616 
00617 static void generate_next(struct generator * g, struct node * p) {
00618     if (g->options->utf8) {
00619         if (p->mode == m_forward)
00620             w(g, "~{int ret = skip_utf8(~zp, ~zc, 0, ~zl, 1");
00621         else
00622             w(g, "~{int ret = skip_utf8(~zp, ~zc, ~zlb, 0, -1");
00623         wp(g, ");~N"
00624               "~Mif (ret < 0) ~f~N"
00625               "~M~zc = ret;~C"
00626               "~}", p);
00627     } else
00628         wp(g, "~M~l~N"
00629               "~M~i~C", p);
00630 }
00631 
00632 static void generate_GO_grouping(struct generator * g, struct node * p, int is_goto, int complement) {
00633 
00634     struct grouping * q = p->name->grouping;
00635     g->S[0] = p->mode == m_forward ? "" : "_b";
00636     g->S[1] = complement ? "in" : "out";
00637     g->S[2] = g->options->utf8 ? "_U" : "";
00638     g->V[0] = p->name;
00639     g->I[0] = q->smallest_ch;
00640     g->I[1] = q->largest_ch;
00641     if (is_goto) {
00642         wp(g, "~Mif (~S1_grouping~S0~S2(~Z~V0, ~I0, ~I1, 1) < 0) ~f /* goto */~C", p);
00643     } else {
00644         wp(g, "~{int ret = ~S1_grouping~S0~S2(~Z~V0, ~I0, ~I1, 1); /* gopast */~C"
00645               "~Mif (ret < 0) ~f~N", p);
00646         if (p->mode == m_forward)
00647             w(g, "~M~zc += ret;~N");
00648         else
00649             w(g, "~M~zc -= ret;~N");
00650         w(g, "~}");
00651     }
00652 }
00653 
00654 static void generate_GO(struct generator * g, struct node * p, int style) {
00655     int keep_c = 0;
00656 
00657     int used = g->label_used;
00658     int a0 = g->failure_label;
00659     int a1 = g->failure_keep_count;
00660 
00661     if (p->left->type == c_grouping || p->left->type == c_non) {
00662         /* Special case for "goto" or "gopast" when used on a grouping or an
00663          * inverted grouping - the movement of c by the matching action is
00664          * exactly what we want! */
00665 #ifdef OPTIMISATION_WARNINGS
00666         printf("Optimising %s %s\n", style ? "goto" : "gopast", p->left->type == c_non ? "non" : "grouping");
00667 #endif
00668         generate_GO_grouping(g, p->left, style, p->left->type == c_non);
00669         return;
00670     }
00671 
00672     w(g, "~Mwhile(1) {"); wp(g, "~C~+", p);
00673 
00674     if (style == 1 || repeat_restore(g, p->left)) {
00675         wp(g, "~M~k~N", p);
00676         keep_c = g->keep_count;
00677     }
00678 
00679     g->failure_label = new_label(g);
00680     g->label_used = 0;
00681     generate(g, p->left);
00682 
00683     if (style == 1) {
00684         /* include for goto; omit for gopast */
00685         w(g, "~M"); wrestore(g, p, keep_c); w(g, "~N");
00686     }
00687     w(g, "~Mbreak;~N");
00688     if (g->label_used)
00689         wsetl(g, g->failure_label);
00690     if (keep_c) {
00691         w(g, "~M"); wrestore(g, p, keep_c); w(g, "~N");
00692     }
00693 
00694     g->label_used = used;
00695     g->failure_label = a0;
00696     g->failure_keep_count = a1;
00697 
00698 /*  wp(g, "~M~l~N"
00699           "~M~i~N", p);  */
00700     generate_next(g, p);
00701     w(g, "~}");
00702 }
00703 
00704 static void generate_loop(struct generator * g, struct node * p) {
00705     w(g, "~{int i; for (i = "); generate_AE(g, p->AE); wp(g, "; i > 0; i--)~C"
00706             "~{", p);
00707 
00708     generate(g, p->left);
00709 
00710     w(g,    "~}"
00711          "~}");
00712 }
00713 
00714 static void generate_repeat(struct generator * g, struct node * p, int atleast_case) {
00715     int keep_c = 0;
00716     wp(g, "~Mwhile(1) {~C~+", p);
00717 
00718     if (repeat_restore(g, p->left)) {
00719         wp(g, "~M~k~N", p);
00720         keep_c = g->keep_count;
00721     }
00722 
00723     g->failure_label = new_label(g);
00724     g->label_used = 0;
00725     g->failure_keep_count = 0;
00726     generate(g, p->left);
00727 
00728     if (atleast_case) w(g, "~Mi--;~N");
00729 
00730     w(g, "~Mcontinue;~N");
00731     if (g->label_used)
00732         wsetl(g, g->failure_label);
00733 
00734     if (keep_c) {
00735         w(g, "~M"); wrestore(g, p, keep_c); w(g, "~N");
00736     }
00737 
00738     w(g, "~Mbreak;~N"
00739       "~}");
00740 }
00741 
00742 static void generate_atleast(struct generator * g, struct node * p) {
00743     w(g, "~{int i = "); generate_AE(g, p->AE); w(g, ";~N");
00744     {
00745         int used = g->label_used;
00746         int a0 = g->failure_label;
00747         int a1 = g->failure_keep_count;
00748 
00749         generate_repeat(g, p, true);
00750 
00751         g->label_used = used;
00752         g->failure_label = a0;
00753         g->failure_keep_count = a1;
00754     }
00755     wp(g, "~Mif (i > 0) ~f~N"
00756        "~}", p);
00757 }
00758 
00759 static void generate_setmark(struct generator * g, struct node * p) {
00760     g->V[0] = p->name;
00761     wp(g, "~M~V0 = ~zc;~C", p);
00762 }
00763 
00764 static void generate_tomark(struct generator * g, struct node * p) {
00765     g->S[0] = p->mode == m_forward ? ">" : "<";
00766 
00767     w(g, "~Mif (~zc ~S0 "); generate_AE(g, p->AE); wp(g, ") ~f~N", p);
00768     w(g, "~M~zc = "); generate_AE(g, p->AE); wp(g, ";~C", p);
00769 }
00770 
00771 static void generate_atmark(struct generator * g, struct node * p) {
00772 
00773     w(g, "~Mif (~zc != "); generate_AE(g, p->AE); wp(g, ") ~f~C", p);
00774 }
00775 
00776 static void generate_hop(struct generator * g, struct node * p) {
00777     g->S[0] = p->mode == m_forward ? "+" : "-";
00778     g->S[1] = p->mode == m_forward ? "0" :
00779         (g->options->make_lang == LANG_C ? "z->lb" : "lb");
00780     if (g->options->utf8) {
00781         w(g, "~{int ret = skip_utf8(~zp, ~zc, ~S1, ~zl, ~S0 ");
00782         generate_AE(g, p->AE); wp(g, ");~C", p);
00783         wp(g, "~Mif (ret < 0) ~f~N", p);
00784     } else {
00785         w(g, "~{int ret = ~zc ~S0 ");
00786         generate_AE(g, p->AE); wp(g, ";~C", p);
00787         wp(g, "~Mif (~S1 > ret || ret > ~zl) ~f~N", p);
00788     }
00789     wp(g, "~M~zc = ret;~N"
00790           "~}", p);
00791 }
00792 
00793 static void generate_delete(struct generator * g, struct node * p) {
00794 #if 1
00795     wp(g, "~Mif (slice_del(~Z) == -1) return -1;~C", p);
00796 #else
00797     wp(g, "~{int ret = slice_del(~Z);~C", p);
00798     wp(g, "~Mif (ret < 0) return ret;~N"
00799           "~}", p);
00800 #endif
00801 }
00802 
00803 static void generate_tolimit(struct generator * g, struct node * p) {
00804     g->S[0] = p->mode == m_forward ? "" : "b";
00805     wp(g, "~M~zc = ~zl~S0;~C", p);
00806 }
00807 
00808 static void generate_atlimit(struct generator * g, struct node * p) {
00809     g->S[0] = p->mode == m_forward ? "" : "b";
00810     g->S[1] = p->mode == m_forward ? "<" : ">";
00811     wp(g, "~Mif (~zc ~S1 ~zl~S0) ~f~C", p);
00812 }
00813 
00814 static void generate_leftslice(struct generator * g, struct node * p) {
00815     g->S[0] = p->mode == m_forward ? "bra" : "ket";
00816     wp(g, "~M~z~S0 = ~zc;~C", p);
00817 }
00818 
00819 static void generate_rightslice(struct generator * g, struct node * p) {
00820     g->S[0] = p->mode == m_forward ? "ket" : "bra";
00821     wp(g, "~M~z~S0 = ~zc;~C", p);
00822 }
00823 
00824 static void generate_assignto(struct generator * g, struct node * p) {
00825     g->V[0] = p->name;
00826     wp(g, "~M~V0 = assign_to(~Z~V0);~C", p);
00827     if (g->options->make_lang == LANG_C)
00828         wp(g, "~Mif (~V0 == 0) return -1;~C", p);
00829 }
00830 
00831 static void generate_sliceto(struct generator * g, struct node * p) {
00832     g->V[0] = p->name;
00833     wp(g, "~{symbol * ret = slice_to(~Z~V0);~C"
00834           "~Mif (ret == 0) return -1;~N"
00835           "~M~V0 = ret;~N"
00836           "~}", p);
00837 }
00838 
00839 static void generate_data_address(struct generator * g, struct node * p) {
00840 
00841     symbol * b = p->literalstring;
00842     if (b != 0) {
00843         wi(g, SIZE(b)); w(g, ", ");
00844         wlitref(g, b);
00845     } else
00846         wv(g, p->name);
00847 }
00848 
00849 static void generate_insert(struct generator * g, struct node * p, int style) {
00850 
00851     int keep_c = style == c_attach;
00852     if (p->mode == m_backward) keep_c = !keep_c;
00853     if (g->options->make_lang == LANG_C)
00854         wp(g, "~{int ret;~N", p);
00855     if (keep_c) w(g, "~{int saved_c = ~zc;~N");
00856     if (g->options->make_lang == LANG_C)
00857         wp(g, "~Mret = insert_~$(~Z~zc, ~zc, ", p);
00858     else
00859         wp(g, "~Minsert_~$(~Z~zc, ~zc, ", p);
00860     generate_data_address(g, p);
00861     wp(g, ");~C", p);
00862     if (keep_c) w(g, "~M~zc = saved_c;~N~}");
00863     if (g->options->make_lang == LANG_C)
00864         wp(g, "~Mif (ret < 0) return ret;~N"
00865               "~}", p);
00866 }
00867 
00868 static void generate_assignfrom(struct generator * g, struct node * p) {
00869 
00870     int keep_c = p->mode == m_forward; /* like 'attach' */
00871     if (g->options->make_lang == LANG_C)
00872         wp(g, "~{int ret;~N", p);
00873     if (keep_c) wp(g, "~{int saved_c = ~zc;~N", p);
00874     w(g, g->options->make_lang == LANG_C ? "~Mret =" : "~M");
00875     wp(g, keep_c ? "insert_~$(~Z~zc, ~zl, " : "insert_~$(~Z~zlb, ~zc, ", p);
00876     generate_data_address(g, p);
00877     wp(g, ");~C", p);
00878     if (keep_c) w(g, "~M~zc = saved_c;~N~}");
00879     if (g->options->make_lang == LANG_C)
00880         wp(g, "~Mif (ret < 0) return ret;~N"
00881               "~}", p);
00882 }
00883 
00884 /* bugs marked <======= fixed 22/7/02. Similar fixes required for Java */
00885 
00886 static void generate_slicefrom(struct generator * g, struct node * p) {
00887 
00888 /*  w(g, "~Mslice_from_s(~Z");   <============= bug! should be: */
00889     wp(g, "~{int ret = slice_from_~$(~Z", p);
00890     generate_data_address(g, p);
00891     wp(g, ");~C", p);
00892     wp(g, "~Mif (ret < 0) return ret;~N"
00893           "~}", p);
00894 }
00895 
00896 static void generate_setlimit(struct generator * g, struct node * p) {
00897     int keep_c;
00898     wp(g, "~{~k~C", p);
00899     keep_c = g->keep_count;
00900     w(g, "~Mint mlimit");
00901     wi(g, keep_c);
00902     w(g, ";~N");
00903     generate(g, p->left);
00904 
00905     w(g, "~Mmlimit");
00906     wi(g, keep_c);
00907     if (p->mode == m_forward) w(g, " = ~zl - ~zc; ~zl = ~zc;~N");
00908                          else w(g, " = ~zlb; ~zlb = ~zc;~N");
00909     w(g, "~M"); wrestore(g, p, keep_c); w(g, "~N");
00910     g->failure_keep_count = -keep_c;
00911     generate(g, p->aux);
00912     w(g, "~M");
00913     wrestorelimit(g, p, -g->failure_keep_count);
00914     w(g, "~N"
00915       "~}");
00916 }
00917 
00918 static const char * vars[] = { "p", "c", "l", "lb", "bra", "ket", NULL };
00919 
00920 static void generate_dollar(struct generator * g, struct node * p) {
00921 
00922     int used = g->label_used;
00923     int a0 = g->failure_label;
00924     int a1 = g->failure_keep_count;
00925     int keep_token;
00926     g->failure_label = new_label(g);
00927     g->label_used = 0;
00928     g->failure_keep_count = 0;
00929 
00930     keep_token = ++g->keep_count;
00931     g->I[0] = keep_token;
00932     if (g->options->make_lang != LANG_C) {
00933         const char ** var;
00934         wp(g, "~{~C", p);
00935         for (var = vars; *var; ++var) {
00936             g->S[0] = *var;
00937             w(g, "~Mint ~S0~I0 = ~S0;~N");
00938         }
00939     } else {
00940         wp(g, "~{struct SN_env env~I0 = * z;~C", p);
00941     }
00942     g->V[0] = p->name;
00943     wp(g, "~Mint failure = 1; /* assume failure */~N"
00944           "~M~zp = ~V0;~N"
00945           "~M~zlb = ~zc = 0;~N"
00946           "~M~zl = SIZE(~zp);~N", p);
00947     generate(g, p->left);
00948     w(g, "~Mfailure = 0; /* mark success */~N");
00949     if (g->label_used)
00950         wsetl(g, g->failure_label);
00951     g->V[0] = p->name; /* necessary */
00952 
00953     g->label_used = used;
00954     g->failure_label = a0;
00955     g->failure_keep_count = a1;
00956 
00957     g->I[0] = keep_token;
00958     if (g->options->make_lang != LANG_C) {
00959         const char ** var;
00960         w(g, "~M~V0 = ~zp;~N");
00961         for (var = vars; *var; ++var) {
00962             g->S[0] = *var;
00963             w(g, "~M~S0 = ~S0~I0;~N");
00964         }
00965         wp(g, "~Mif (failure) ~f~N~}", p);
00966     } else {
00967         wp(g, "~M~V0 = z->p;~N"
00968               "~M* z = env~I0;~N"
00969               "~Mif (failure) ~f~N~}", p);
00970     }
00971 }
00972 
00973 static void generate_integer_assign(struct generator * g, struct node * p, char * s) {
00974 
00975     g->V[0] = p->name;
00976     g->S[0] = s;
00977     w(g, "~M~V0 ~S0 "); generate_AE(g, p->AE); wp(g, ";~C", p);
00978 }
00979 
00980 static void generate_integer_test(struct generator * g, struct node * p, char * s) {
00981 
00982     g->V[0] = p->name;
00983     g->S[0] = s;
00984     w(g, "~Mif (!(~V0 ~S0 "); generate_AE(g, p->AE); wp(g, ")) ~f~C", p);
00985 }
00986 
00987 static void generate_call(struct generator * g, struct node * p) {
00988 
00989     g->V[0] = p->name;
00990     wp(g, "~{int ret = ~V0(~Z);~C", p);
00991     if (g->failure_keep_count == 0 && g->failure_label == x_return) {
00992         /* Combine the two tests in this special case for better optimisation
00993          * and clearer generated code. */
00994         wp(g, "~Mif (ret <= 0) return ret;~N~}", p);
00995     } else {
00996         wp(g, "~Mif (ret == 0) ~f~N"
00997               "~Mif (ret < 0) return ret;~N~}", p);
00998     }
00999 }
01000 
01001 static void generate_grouping(struct generator * g, struct node * p, int complement) {
01002 
01003     struct grouping * q = p->name->grouping;
01004     g->S[0] = p->mode == m_forward ? "" : "_b";
01005     g->S[1] = complement ? "out" : "in";
01006     g->S[2] = g->options->utf8 ? "_U" : "";
01007     g->V[0] = p->name;
01008     g->I[0] = q->smallest_ch;
01009     g->I[1] = q->largest_ch;
01010     wp(g, "~Mif (~S1_grouping~S0~S2(~Z~V0, ~I0, ~I1, 0)) ~f~C", p);
01011 }
01012 
01013 static void generate_namedstring(struct generator * g, struct node * p) {
01014 
01015     g->S[0] = p->mode == m_forward ? "" : "_b";
01016     g->V[0] = p->name;
01017     wp(g, "~Mif (!(eq_v~S0(~Z~V0))) ~f~C", p);
01018 }
01019 
01020 static void generate_literalstring(struct generator * g, struct node * p) {
01021     symbol * b = p->literalstring;
01022     if (SIZE(b) == 1 && *b < 128) {
01023         /* It's quite common to compare with a single ASCII character literal
01024          * string, so just inline the simpler code for this case rather than
01025          * making a function call. */
01026         char buf[8];
01027         if (*b < 32 || *b == 127 || *b == '\'' || *b == '\\') {
01028             sprintf(buf, "%d", (int)*b);
01029         } else {
01030             sprintf(buf, "'%c'", (char)*b);
01031         }
01032         g->S[0] = buf;
01033         if (p->mode == m_forward) {
01034             wp(g, "~Mif (c == l || p[c] != ~S0) ~f~N"
01035                   "~Mc++;~N", p);
01036         } else {
01037             wp(g, "~Mif (c <= lb || p[c - 1] != ~S0) ~f~N"
01038                   "~Mc--;~N", p);
01039         }
01040     } else {
01041         g->S[0] = p->mode == m_forward ? "" : "_b";
01042         g->I[0] = SIZE(b);
01043         g->L[0] = b;
01044 
01045         wp(g, "~Mif (!(eq_s~S0(~Z~I0, ~L0))) ~f~C", p);
01046     }
01047 }
01048 
01049 static void generate_define(struct generator * g, struct node * p) {
01050     struct name * q = p->name;
01051     g->next_label = 0;
01052 
01053     if (g->options->make_lang == LANG_C)
01054         g->S[0] = q->type == t_routine ? "static" : "extern";
01055     else
01056         g->S[0] = g->options->name;
01057     g->V[0] = q;
01058 
01059     if (g->options->make_lang == LANG_C)
01060         w(g, "~N~S0 int ~V0(struct SN_env * z) {");
01061     else
01062         w(g, "~Nint Xapian::~S0::~V0() {");
01063     ws(g, p->mode == m_forward ? " /* forwardmode */" : " /* backwardmode */");
01064     w(g, "~N~+");
01065     if (p->amongvar_needed) w(g, "~Mint among_var;~N");
01066     g->failure_keep_count = 0;
01067     g->failure_label = x_return;
01068     g->label_used = 0;
01069     g->keep_count = 0;
01070     generate(g, p->left);
01071     w(g, "~Mreturn 1;~N~}");
01072 }
01073 
01074 static void generate_substring(struct generator * g, struct node * p) {
01075 
01076     struct among * x = p->among;
01077     int block = -1;
01078     unsigned int bitmap = 0;
01079     struct amongvec * among_cases = x->b;
01080     int c;
01081     int empty_case = -1;
01082     int n_cases = 0;
01083     symbol cases[2];
01084     int shortest_size = INT_MAX;
01085     int shown_comment = 0;
01086 
01087     g->S[0] = p->mode == m_forward ? "" : "_b";
01088     g->I[0] = x->number;
01089     g->I[1] = x->literalstring_count;
01090 
01091     /* In forward mode with non-ASCII UTF-8 characters, the first character
01092      * of the string will often be the same, so instead look at the last
01093      * common character position.
01094      *
01095      * In backward mode, we can't match if there are fewer characters before
01096      * the current position than the minimum length.
01097      */
01098     for (c = 0; c < x->literalstring_count; ++c) {
01099         int size = among_cases[c].size;
01100         if (size != 0 && size < shortest_size) {
01101             shortest_size = size;
01102         }
01103     }
01104 
01105     for (c = 0; c < x->literalstring_count; ++c) {
01106         symbol ch;
01107         if (among_cases[c].size == 0) {
01108             empty_case = c;
01109             continue;
01110         }
01111         if (p->mode == m_forward) {
01112             ch = among_cases[c].b[shortest_size - 1];
01113         } else {
01114             ch = among_cases[c].b[among_cases[c].size - 1];
01115         }
01116         if (n_cases == 0) {
01117             block = ch >> 5;
01118         } else if (ch >> 5 != block) {
01119             block = -1;
01120             if (n_cases > 2) break;
01121         }
01122         if (block == -1) {
01123             if (ch == cases[0]) continue;
01124             if (n_cases < 2) {
01125                 cases[n_cases++] = ch;
01126             } else if (ch != cases[1]) {
01127                 ++n_cases;
01128                 break;
01129             }
01130         } else {
01131             if ((bitmap & (1u << (ch & 0x1f))) == 0) {
01132                 bitmap |= 1u << (ch & 0x1f);
01133                 if (n_cases < 2)
01134                     cases[n_cases] = ch;
01135                 ++n_cases;
01136             }
01137         }
01138     }
01139 
01140     if (block != -1 || n_cases <= 2) {
01141         char buf[64];
01142         g->I[2] = block;
01143         g->I[3] = bitmap;
01144         g->I[4] = shortest_size - 1;
01145         if (p->mode == m_forward) {
01146             const char * z = g->options->make_lang == LANG_C ? "z->" : "";
01147             sprintf(buf, "%sp[%sc + %d]", z, z, shortest_size - 1);
01148             g->S[1] = buf;
01149             if (shortest_size == 1) {
01150                 wp(g, "~Mif (~zc >= ~zl || ", p);
01151             } else {
01152                 wp(g, "~Mif (~zc + ~I4 >= ~zl || ", p);
01153             }
01154         } else {
01155             if (g->options->make_lang == LANG_C)
01156                 g->S[1] = "z->p[z->c - 1]";
01157             else
01158                 g->S[1] = "p[c - 1]";
01159             if (shortest_size == 1) {
01160                 wp(g, "~Mif (~zc <= ~zlb || ", p);
01161             } else {
01162                 wp(g, "~Mif (~zc - ~I4 <= ~zlb || ", p);
01163             }
01164         }
01165         if (n_cases == 0) {
01166             /* We get this for the degenerate case: among { '' }
01167              * This doesn't seem to be a useful construct, but it is
01168              * syntactically valid.
01169              */
01170             wp(g, "0", p);
01171         } else if (n_cases == 1) {
01172             g->I[4] = cases[0];
01173             wp(g, "~S1 != ~I4", p);
01174         } else if (n_cases == 2) {
01175             g->I[4] = cases[0];
01176             g->I[5] = cases[1];
01177             wp(g, "(~S1 != ~I4 && ~S1 != ~I5)", p);
01178         } else {
01179             wp(g, "~S1 >> 5 != ~I2 || !((~I3 >> (~S1 & 0x1f)) & 1)", p);
01180         }
01181         ws(g, ") ");
01182         if (empty_case != -1) {
01183             /* If the among includes the empty string, it can never fail
01184              * so not matching the bitmap means we match the empty string.
01185              */
01186             g->I[4] = among_cases[empty_case].result;
01187             wp(g, "among_var = ~I4; else~C", p);
01188         } else {
01189             wp(g, "~f~C", p);
01190         }
01191         shown_comment = 1;
01192     } else {
01193 #ifdef OPTIMISATION_WARNINGS
01194         printf("Couldn't shortcut among %d\n", x->number);
01195 #endif
01196     }
01197 
01198     if (x->command_count == 0 && x->starter == 0) {
01199         w(g, "~Mif (!(find_among~S0(s_pool, ~Za_~I0, ~I1, ");
01200         if (x->have_funcs) {
01201             w(g, "af_~I0, af");
01202         } else {
01203             ws(g, "0, 0");
01204         }
01205         wp(g, "))) ~f", p);
01206         wp(g, shown_comment ? "~N" : "~C", p);
01207     } else {
01208         w(g, "~Mamong_var = find_among~S0(s_pool, ~Za_~I0, ~I1, ");
01209         if (x->have_funcs) {
01210             w(g, "af_~I0, af");
01211         } else {
01212             ws(g, "0, 0");
01213         }
01214         wp(g, ");", p);
01215         wp(g, shown_comment ? "~N" : "~C", p);
01216         wp(g, "~Mif (!(among_var)) ~f~N", p);
01217     }
01218 }
01219 
01220 static void generate_among(struct generator * g, struct node * p) {
01221 
01222     struct among * x = p->among;
01223     int case_number = 1;
01224 
01225     if (x->substring == 0) generate_substring(g, p);
01226     if (x->command_count == 0 && x->starter == 0) return;
01227 
01228     unless (x->starter == 0) generate(g, x->starter);
01229 
01230     wp(g, "~Mswitch(among_var) {~C~+"
01231               "~Mcase 0: ~f~N", p);
01232 
01233     p = p->left;
01234     if (p != 0 && p->type != c_literalstring) p = p->right;
01235 
01236     until (p == 0) {
01237          if (p->type == c_bra && p->left != 0) {
01238              g->I[0] = case_number++;
01239              w(g, "~Mcase ~I0:~N~+"); generate(g, p); w(g, "~Mbreak;~N~-");
01240          }
01241          p = p->right;
01242     }
01243     w(g, "~}");
01244 }
01245 
01246 static void generate_booltest(struct generator * g, struct node * p) {
01247 
01248     g->V[0] = p->name;
01249     wp(g, "~Mif (!(~V0)) ~f~C", p);
01250 }
01251 
01252 static void generate_false(struct generator * g, struct node * p) {
01253 
01254     wp(g, "~M~f~C", p);
01255 }
01256 
01257 static void generate_debug(struct generator * g, struct node * p) {
01258 
01259     g->I[0] = g->debug_count++;
01260     g->I[1] = p->line_number;
01261     wp(g, "~Mdebug(~Z~I0, ~I1);~C", p);
01262 
01263 }
01264 
01265 static void generate(struct generator * g, struct node * p) {
01266 
01267     int used = g->label_used;
01268     int a0 = g->failure_label;
01269     int a1 = g->failure_keep_count;
01270 
01271     switch (p->type)
01272     {
01273         case c_define:        generate_define(g, p); break;
01274         case c_bra:           generate_bra(g, p); break;
01275         case c_and:           generate_and(g, p); break;
01276         case c_or:            generate_or(g, p); break;
01277         case c_backwards:     generate_backwards(g, p); break;
01278         case c_not:           generate_not(g, p); break;
01279         case c_set:           generate_set(g, p); break;
01280         case c_unset:         generate_unset(g, p); break;
01281         case c_try:           generate_try(g, p); break;
01282         case c_fail:          generate_fail(g, p); break;
01283         case c_reverse:
01284         case c_test:          generate_test(g, p); break;
01285         case c_do:            generate_do(g, p); break;
01286         case c_goto:          generate_GO(g, p, 1); break;
01287         case c_gopast:        generate_GO(g, p, 0); break;
01288         case c_repeat:        generate_repeat(g, p, false); break;
01289         case c_loop:          generate_loop(g, p); break;
01290         case c_atleast:       generate_atleast(g, p); break;
01291         case c_setmark:       generate_setmark(g, p); break;
01292         case c_tomark:        generate_tomark(g, p); break;
01293         case c_atmark:        generate_atmark(g, p); break;
01294         case c_hop:           generate_hop(g, p); break;
01295         case c_delete:        generate_delete(g, p); break;
01296         case c_next:          generate_next(g, p); break;
01297         case c_tolimit:       generate_tolimit(g, p); break;
01298         case c_atlimit:       generate_atlimit(g, p); break;
01299         case c_leftslice:     generate_leftslice(g, p); break;
01300         case c_rightslice:    generate_rightslice(g, p); break;
01301         case c_assignto:      generate_assignto(g, p); break;
01302         case c_sliceto:       generate_sliceto(g, p); break;
01303         case c_assign:        generate_assignfrom(g, p); break;
01304         case c_insert:
01305         case c_attach:        generate_insert(g, p, p->type); break;
01306         case c_slicefrom:     generate_slicefrom(g, p); break;
01307         case c_setlimit:      generate_setlimit(g, p); break;
01308         case c_dollar:        generate_dollar(g, p); break;
01309         case c_mathassign:    generate_integer_assign(g, p, "="); break;
01310         case c_plusassign:    generate_integer_assign(g, p, "+="); break;
01311         case c_minusassign:   generate_integer_assign(g, p, "-="); break;
01312         case c_multiplyassign:generate_integer_assign(g, p, "*="); break;
01313         case c_divideassign:  generate_integer_assign(g, p, "/="); break;
01314         case c_eq:            generate_integer_test(g, p, "=="); break;
01315         case c_ne:            generate_integer_test(g, p, "!="); break;
01316         case c_gr:            generate_integer_test(g, p, ">"); break;
01317         case c_ge:            generate_integer_test(g, p, ">="); break;
01318         case c_ls:            generate_integer_test(g, p, "<"); break;
01319         case c_le:            generate_integer_test(g, p, "<="); break;
01320         case c_call:          generate_call(g, p); break;
01321         case c_grouping:      generate_grouping(g, p, false); break;
01322         case c_non:           generate_grouping(g, p, true); break;
01323         case c_name:          generate_namedstring(g, p); break;
01324         case c_literalstring: generate_literalstring(g, p); break;
01325         case c_among:         generate_among(g, p); break;
01326         case c_substring:     generate_substring(g, p); break;
01327         case c_booltest:      generate_booltest(g, p); break;
01328         case c_false:         generate_false(g, p); break;
01329         case c_true:          break;
01330         case c_debug:         generate_debug(g, p); break;
01331         default: fprintf(stderr, "%d encountered\n", p->type);
01332                  exit(1);
01333     }
01334 
01335     if (g->failure_label != a0)
01336         g->label_used = used;
01337     g->failure_label = a0;
01338     g->failure_keep_count = a1;
01339 }
01340 
01341 static void generate_start_comment(struct generator * g) {
01342 
01343     if (g->options->make_lang == LANG_C)
01344         w(g, "~N/* This file was generated automatically by the Snowball to ANSI C compiler */~N");
01345     else
01346         w(g, "/* This file was generated automatically by the Snowball to ISO C++ compiler */~N");
01347 }
01348 
01349 static void generate_head(struct generator * g) {
01350 
01351     if (g->options->make_lang != LANG_C) {
01352         const char * s = g->options->output_file;
01353         const char * leaf;
01354         w(g, "~N"
01355              "#include <limits.h>~N");
01356         if (!s) abort(); /* checked in driver.c */
01357         leaf = strrchr(s, '/');
01358         if (leaf) ++leaf; else leaf = s;
01359         ws(g, "#include \"");
01360         ws(g, leaf);
01361         w(g, ".h\"~N~N");
01362         return;
01363     }
01364 
01365     if (g->options->runtime_path == 0) {
01366         w(g, "~N#include \"header.h\"~N~N");
01367     } else {
01368         w(g, "~N#include \"");
01369         ws(g, g->options->runtime_path);
01370         if (g->options->runtime_path[strlen(g->options->runtime_path) - 1] != '/')
01371             wch(g, '/');
01372         w(g, "header.h\"~N~N");
01373     }
01374 }
01375 
01376 static void generate_routine_headers(struct generator * g) {
01377     struct name * q;
01378     if (g->options->make_lang != LANG_C) return;
01379 
01380     q = g->analyser->names;
01381     until (q == 0) {
01382         g->V[0] = q;
01383         switch (q->type) {
01384             case t_routine:
01385                 w(g, "static int ~W0(struct SN_env * z);~N");
01386                 break;
01387             case t_external:
01388                 w(g,
01389                   "#ifdef __cplusplus~N"
01390                   "extern \"C\" {~N"
01391                   "#endif~N"
01392                   "extern int ~W0(struct SN_env * z);~N"
01393                   "#ifdef __cplusplus~N"
01394                   "}~N"
01395                   "#endif~N"
01396                   );
01397                 break;
01398         }
01399         q = q->next;
01400     }
01401 }
01402 
01403 static unsigned pool_size = 0;
01404 
01405 static void generate_among_pool(struct generator * g, struct among * x) {
01406 
01407     while (x) {
01408         struct amongvec * v = x->b;
01409         int have_funcs = 0;
01410         int i;
01411 
01412         g->I[0] = x->number;
01413         
01414         for (i = 0; i < x->literalstring_count; i++)
01415         {
01416             g->I[1] = i;
01417             g->L[0] = v->b;
01418             unless (v->size == 0) {
01419                 if (pool_size == 0) {
01420                     w(g, "static const symbol s_pool[] = {~N");
01421                 }
01422                 g->I[2] = pool_size;
01423                 w(g, "#define s_~I0_~I1 ~I2~N");
01424                 w(g, "~A0,~N");
01425                 pool_size += v->size;
01426             }
01427             v++;
01428         }
01429 
01430         x = x->next;
01431     }
01432     if (pool_size != 0) {
01433         w(g, "};~N~N");
01434     }
01435 }
01436 
01437 static void generate_among_table(struct generator * g, struct among * x) {
01438 
01439     struct amongvec * v = x->b;
01440     int have_funcs = 0;
01441 
01442     g->I[0] = x->number;
01443     g->I[1] = x->literalstring_count;
01444     w(g, "~N~Mstatic const struct among a_~I0[~I1] =~N{~N");
01445 
01446     v = x->b;
01447     {
01448         int i;
01449         for (i = 0; i < x->literalstring_count; i++) {
01450             g->I[1] = i;
01451             g->I[2] = v->size;
01452             g->I[3] = v->i;
01453             g->I[4] = v->result;
01454             g->S[0] = i < x->literalstring_count - 1 ? "," : "";
01455 
01456             w(g, "/*~J1 */ { ~I2, ");
01457             if (v->size == 0) w(g, "0,");
01458                          else w(g, "s_~I0_~I1,");
01459             w(g, " ~I3, ~I4");
01460             if (v->function) have_funcs = 1;
01461             w(g, "}~S0~N");
01462             v++;
01463         }
01464     }
01465     w(g, "};~N~N");
01466 
01467     x->have_funcs = have_funcs;
01468     if (have_funcs) {
01469         g->I[1] = x->literalstring_count;
01470         w(g, "~Mstatic const unsigned char af_~I0[~I1] =~N{~N");
01471 
01472         v = x->b;
01473         {
01474             int i;
01475             for (i = 0; i < x->literalstring_count; i++) {
01476                 g->I[1] = i;
01477 
01478                 w(g, "/*~J1 */ ");
01479                 if (v[i].function == 0) {
01480                     w(g, "0");
01481                 } else {
01482                     wi(g, v[i].function->among_func_count);
01483                     g->V[0] = v[i].function;
01484                     w(g, " /* t~W0 */");
01485                 }
01486                 if (i < x->literalstring_count - 1) w(g, ",~N");
01487             }
01488         }
01489         w(g, "~N};~N~N");
01490     }
01491 }
01492 
01493 static void generate_amongs(struct generator * g) {
01494     struct among * x = g->analyser->amongs;
01495     struct name * q;
01496     int among_func_count = 0;
01497 
01498     g->S[0] = g->options->name;
01499     for (q = g->analyser->names; q; q = q->next) {
01500         if (q->type == t_routine && q->routine_called_from_among) {
01501             q->among_func_count = ++among_func_count;
01502             g->V[0] = q;
01503             w(g, "static int t~V0(Xapian::Stem::Internal * this_ptr) {~N"
01504                  "    return (static_cast<Xapian::~S0 *>(this_ptr))->~V0();~N"
01505                  "}~N"
01506                  "~N");
01507         }
01508     }
01509 
01510     if (among_func_count) {
01511         g->I[0] = among_func_count;
01512         w(g, "~Mstatic const among_function af[~I0] =~N{~N");
01513 
01514         q = g->analyser->names;
01515         g->S[0] = g->options->name;
01516         for (q = g->analyser->names; q; q = q->next) {
01517             if (q->type == t_routine && q->routine_called_from_among) {
01518                 g->V[0] = q;
01519                 g->I[0] = q->among_func_count;
01520                 w(g, "/*~J0 */ t~V0");
01521                 if (q->among_func_count < among_func_count) w(g, ",~N"); else w(g, "~N");
01522             }
01523         }
01524 
01525         w(g, "};~N~N");
01526     }
01527 
01528     generate_among_pool(g, x);
01529 
01530     until (x == 0) {
01531         generate_among_table(g, x);
01532         x = x->next;
01533     }
01534 }
01535 
01536 static void set_bit(symbol * b, int i) { b[i/8] |= 1 << i%8; }
01537 
01538 static void generate_grouping_table(struct generator * g, struct grouping * q) {
01539 
01540     int range = q->largest_ch - q->smallest_ch + 1;
01541     int size = (range + 7)/ 8;  /* assume 8 bits per symbol */
01542     symbol * b = q->b;
01543     symbol * map = create_b(size);
01544     int i;
01545     for (i = 0; i < size; i++) map[i] = 0;
01546 
01547     for (i = 0; i < SIZE(b); i++) set_bit(map, b[i] - q->smallest_ch);
01548 
01549     {
01550         g->V[0] = q->name;
01551 
01552         w(g, "static const unsigned char ~V0[] = { ");
01553         for (i = 0; i < size; i++) {
01554              wi(g, map[i]);
01555              if (i < size - 1) w(g, ", ");
01556         }
01557         w(g, " };~N~N");
01558     }
01559     lose_b(map);
01560 }
01561 
01562 static void generate_groupings(struct generator * g) {
01563     struct grouping * q = g->analyser->groupings;
01564     until (q == 0) {
01565         generate_grouping_table(g, q);
01566         q = q->next;
01567     }
01568 }
01569 
01570 static void generate_create(struct generator * g) {
01571 
01572     int * p = g->analyser->name_count;
01573 
01574     if (g->options->make_lang != LANG_C) {
01575         struct name * q = g->analyser->names;
01576         int first = true;
01577         const char * dtor;
01578         g->S[0] = g->options->name;
01579         dtor = strrchr(g->options->name, ':');
01580         if (dtor) ++dtor; else dtor = g->options->name;
01581         g->S[1] = dtor;
01582         w(g, "~N"
01583              "Xapian::~S0::~S1()");
01584         while (q) {
01585             if (q->type < t_routine) {
01586                 w(g, first ? "~N    : " : ", ");
01587                 first = false;
01588                 g->V[0] = q;
01589                 w(g, "~W0(0)");
01590             }
01591             q = q->next;
01592         }
01593         w(g, "~N{~N");
01594         q = g->analyser->names;
01595         while (q) {
01596             if (q->type == t_string) {
01597                 g->V[0] = q;
01598                 w(g, "    ~W0 = create_s();~N");
01599             }
01600             q = q->next;
01601         }
01602         w(g, "}~N");
01603 
01604         return;
01605     }
01606 
01607     g->I[0] = p[t_string];
01608     g->I[1] = p[t_integer];
01609     g->I[2] = p[t_boolean];
01610     w(g, "~N"
01611          "extern struct SN_env * ~pcreate_env(void) { return SN_create_env(~I0, ~I1, ~I2); }"
01612          "~N");
01613 }
01614 
01615 static void generate_close(struct generator * g) {
01616 
01617     int * p = g->analyser->name_count;
01618     if (g->options->make_lang != LANG_C) {
01619         struct name * q = g->analyser->names;
01620         const char * dtor;
01621         const char * lang;
01622         g->S[0] = g->options->name;
01623         dtor = strrchr(g->options->name, ':');
01624         if (dtor) ++dtor; else dtor = g->options->name;
01625         g->S[1] = dtor;
01626         lang = strrchr(g->options->output_file, '/');
01627         if (lang) ++lang; else lang = g->options->output_file;
01628         g->S[2] = lang;
01629         w(g, "~N"
01630              "Xapian::~S0::~~~S1()~N"
01631              "{~N");
01632         while (q) {
01633             if (q->type == t_string) {
01634                 g->V[0] = q;
01635                 w(g, "    lose_s(~W0);~N");
01636             }
01637             q = q->next;
01638         }
01639         w(g, "}~N");
01640 
01641         w(g, "~N"
01642              "const char *~N"
01643              "Xapian::~S0::get_description() const~N"
01644              "{~N"
01645              "    return \"~S2\";~N"
01646              "}~N");
01647         return;
01648     }
01649 
01650     g->I[0] = p[t_string];
01651     w(g, "~Nextern void ~pclose_env(struct SN_env * z) { SN_close_env(z, ~I0); }~N~N");
01652 }
01653 
01654 static void generate_create_and_close_templates(struct generator * g) {
01655     w(g, "~N"
01656          "extern struct SN_env * ~pcreate_env(void);~N"
01657          "extern void ~pclose_env(struct SN_env * z);~N"
01658          "~N");
01659 }
01660 
01661 static void generate_header_file(struct generator * g) {
01662 
01663     struct name * q = g->analyser->names;
01664     char * vp = g->options->variables_prefix;
01665     g->S[0] = vp;
01666 
01667     if (g->options->make_lang != LANG_C) {
01668         const char * p;
01669         w(g, "~N"
01670              "#include \"steminternal.h\"~N"
01671              "~N"
01672              "namespace Xapian {~N"
01673              "~N");
01674 
01675         g->S[1] = g->options->name;
01676         w(g, "class ~S1 ");
01677         if (g->options->parent_class_name) {
01678             g->S[1] = g->options->parent_class_name;
01679             w(g, ": public ~S1 ");
01680         }
01681         w(g, "{~N");
01682         for (q = g->analyser->names; q; q = q->next) {
01683             switch (q->type) {
01684                 case t_string:  g->S[1] = "symbol *"; goto label1;
01685                 case t_integer: g->S[1] = "int"; goto label1;
01686                 case t_boolean: g->S[1] = "unsigned char";
01687                 label1:
01688                     g->V[0] = q;
01689                     w(g, "    ~S1 ~W0;~N");
01690                     break;
01691              }
01692         }
01693 
01694         /* FIXME: currently we need to make the routines public in case they
01695          * are used in a "struct among". */
01696         w(g, "  public:~N");
01697         for (q = g->analyser->names; q; q = q->next) {
01698             if (q->type == t_routine) {
01699                 g->V[0] = q;
01700                 w(g, "    int ~W0();~N");
01701             }
01702         }
01703 
01704         w(g, "~N");
01705         p = strrchr(g->options->name, ':');
01706         if (p) ++p; else p = g->options->name;
01707         g->S[1] = p;
01708         w(g, "    ~S1();~N"
01709              "    ~~~S1();~N");
01710         for (q = g->analyser->names; q; q = q->next) {
01711             if (q->type == t_external) {
01712                 g->V[0] = q;
01713                 w(g, "    int ~W0();~N");
01714             }
01715         }
01716 
01717         w(g, "    const char * get_description() const;~N"
01718              "};~N"
01719              "~N"
01720              "}~N");
01721 
01722         return;
01723     }
01724 
01725     w(g, "~N"
01726          "#ifdef __cplusplus~N"
01727          "extern \"C\" {~N"
01728          "#endif~N");            /* for C++ */
01729 
01730     generate_create_and_close_templates(g);
01731     until (q == 0) {
01732         g->V[0] = q;
01733         switch (q->type)
01734         {
01735             case t_external:
01736                 w(g, "extern int ~W0(struct SN_env * z);~N");
01737                 break;
01738             case t_string:  g->S[1] = "S"; goto label0;
01739             case t_integer: g->S[1] = "I"; goto label0;
01740             case t_boolean: g->S[1] = "B";
01741             label0:
01742                 if (vp) {
01743                     g->I[0] = q->count;
01744                     w(g, "#define ~S0");
01745                     str_append_b(g->outbuf, q->b);
01746                     w(g, " (~S1[~I0])~N");
01747                 }
01748                 break;
01749         }
01750         q = q->next;
01751     }
01752 
01753     w(g, "~N"
01754          "#ifdef __cplusplus~N"
01755          "}~N"
01756          "#endif~N");            /* for C++ */
01757 
01758     w(g, "~N");
01759 }
01760 
01761 extern void generate_program_c(struct generator * g) {
01762 
01763     g->outbuf = str_new();
01764     generate_start_comment(g);
01765     generate_head(g);
01766     generate_routine_headers(g);
01767     if (g->options->make_lang == LANG_C) {
01768         w(g, "#ifdef __cplusplus~N"
01769              "extern \"C\" {~N"
01770              "#endif~N"
01771              "~N");
01772         generate_create_and_close_templates(g);
01773         w(g, "~N"
01774              "#ifdef __cplusplus~N"
01775              "}~N"
01776              "#endif~N");
01777     }
01778     generate_amongs(g);
01779     generate_groupings(g);
01780     g->declarations = g->outbuf;
01781     g->outbuf = str_new();
01782     g->literalstring_count = 0;
01783     {
01784         struct node * p = g->analyser->program;
01785         until (p == 0) { generate(g, p); p = p->right; }
01786     }
01787     generate_create(g);
01788     generate_close(g);
01789     output_str(g->options->output_c, g->declarations);
01790     str_delete(g->declarations);
01791     output_str(g->options->output_c, g->outbuf);
01792     str_clear(g->outbuf);
01793 
01794     generate_start_comment(g);
01795     generate_header_file(g);
01796     output_str(g->options->output_h, g->outbuf);
01797     str_delete(g->outbuf);
01798 }
01799 
01800 extern struct generator * create_generator_c(struct analyser * a, struct options * o) {
01801     NEW(generator, g);
01802     g->analyser = a;
01803     g->options = o;
01804     g->margin = 0;
01805     g->debug_count = 0;
01806     g->line_count = 0;
01807     return g;
01808 }
01809 
01810 extern void close_generator_c(struct generator * g) {
01811 
01812     FREE(g);
01813 }
01814 

Documentation for Xapian (version 1.0.20).
Generated on 28 Apr 2010 by Doxygen 1.5.2.