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