00001
00002 #include <limits.h>
00003 #include <stdio.h>
00004 #include <stdlib.h>
00005 #include <string.h>
00006 #include "header.h"
00007
00008
00009
00010
00011
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
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);
00035 }
00036
00037 static void wnl(struct generator * g) {
00038 str_append_ch(g->outbuf, '\n');
00039 g->line_count++;
00040 }
00041
00042 static void ws(struct generator * g, const char * s) {
00043 str_append_string(g->outbuf, s);
00044 }
00045
00046 static void wi(struct generator * g, int i) {
00047 str_append_int(g->outbuf, i);
00048 }
00049
00050 static void wh_ch(struct generator * g, int i) {
00051 str_append_ch(g->outbuf, "0123456789ABCDEF"[i & 0xF]);
00052 }
00053
00054 static void wh(struct generator * g, int i) {
00055 if (i >> 4) wh(g, i >> 4);
00056 wh_ch(g, i);
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);
00063 }
00064
00065 static void wvn(struct generator * g, struct name * p) {
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
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) {
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) {
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) {
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) {
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) {
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); }
00168
00169 static void wbs(struct generator * g) {
00170 wms(g, "{ ");
00171 g->margin++;
00172 }
00173
00174 static void wbe(struct generator * g) {
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) {
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) {
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) {
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) {
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) {
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) {
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) {
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 '$':
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
00339
00340
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:
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
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
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
00665
00666
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
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
00701
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;
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
00887
00888 static void generate_slicefrom(struct generator * g, struct node * p) {
00889
00890
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;
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
00995
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
01026
01027
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
01094
01095
01096
01097
01098
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
01169
01170
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
01186
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();
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;
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
01674
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");
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");
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