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

Documentation for Xapian (version 1.0.10).
Generated on 24 Dec 2008 by Doxygen 1.5.2.