home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume19 / wacco / part01 / gen.C < prev    next >
C/C++ Source or Header  |  1991-05-19  |  16KB  |  672 lines

  1. // Copyright (c) 1991 by Parag Patel.  All Rights Reserved.
  2. static const char rcs_id[] = "$Header: gen.C,v 1.29 91/02/22 16:08:02 hmgr Exp $";
  3.  
  4. #include "defs.h"
  5. #include "toks.h"
  6. #include <stdarg.h>
  7.  
  8.  
  9. static FILE *fp = NULL;
  10. static long curr_lineno = 1;
  11. static const char *currfile = NULL;
  12. static const char *inputfile = NULL;
  13.  
  14. static void putf(char *fmt, ...)
  15. {
  16.     va_list ap;
  17.     char buf[1024];
  18.  
  19.     va_start(ap, fmt);
  20.     vsprintf(buf, fmt, ap);
  21.     va_end(ap);
  22.     int nl = 0;
  23.     for (char *s = buf; *s != '\0'; s++)
  24.     if (*s == '\n')
  25.         nl++;
  26.     curr_lineno += nl;
  27.     fputs(buf, fp);
  28. }
  29.  
  30. inline static void put(int ch)
  31. {
  32.     putc(ch, fp);
  33.     if (ch == '\n')
  34.     curr_lineno++;
  35. }
  36.  
  37.  
  38. static boolean saveret = FALSE;
  39. static char *mkretcode(symbol *s)
  40. {
  41.     s = NULL;
  42.     return saveret ? "_rc = " : "(void)";
  43. }
  44.  
  45. static const char *mkname(symbol *sym)
  46. {
  47.     if (*sym->name != '"')
  48.         return sym->name;
  49.     if (*sym->name == '\'' && sym->type == TERMINAL)
  50.         return sym->name;
  51.     return strbldf("_S%d/*%s*/", sym->id, sym->name);
  52. }
  53.  
  54. static const char *mkerrname(symbol *sym)
  55. {
  56.     if (sym->type == NONTERMINAL && sym->realname != NULL)
  57.         return sym->realname;
  58.     return mkname(sym);
  59. }
  60.  
  61.  
  62. static void printset(const char *name, Bitset &set)
  63. {
  64.     Bitsetiter si(set);
  65.     symbol *s;
  66.     int id;
  67.     char *pre = "";
  68.  
  69.     putf("static %s[] = { ", name);
  70.     while ((id = si()) >= 0)
  71.     {
  72.         if (id == EMPTY)
  73.             putf("%s_EMPTY", pre);
  74.             // continue;
  75.         else if (id == END)
  76.             putf("%sEOI", pre);
  77.         else
  78.         {
  79.             s = getsymbol(id);
  80.             putf("%s%s", pre, mkname(s));
  81.         }
  82.         pre = ", ";
  83.     } 
  84.     putf("%s-1 };\n", pre);
  85. }
  86.  
  87. static void printcase(char *pre, Bitset &set)
  88. {
  89.     Bitsetiter si(set);
  90.     symbol *s;
  91.     int id;
  92.  
  93.     while ((id = si()) >= 0)
  94.     {
  95.         if (id == EMPTY)
  96.             continue;
  97.  
  98.         putf("%scase ", pre);
  99.         if (id == END)
  100.             putf("EOI");
  101.         else
  102.         {
  103.             s = getsymbol(id);
  104.             putf("%s", mkname(s));
  105.         }
  106.         putf(":\n");
  107.     } 
  108. }
  109.  
  110. inline static boolean dotype(symbol *sym)
  111. {
  112.     if ((sym->usedret & RET_VALUE) || sym->rettype != NULL)
  113.         return TRUE;
  114.     else
  115.         return FALSE;
  116. }
  117.  
  118. static const char *mktype(symbol *sym, char *pre = "", char *post = NULL)
  119. {
  120.     if (!dotype(sym))
  121.     return "";
  122.     char *name;
  123.     if (sym->rettype == NULL)
  124.     name = "int";
  125.     else
  126.     {
  127.     name = sym->rettype;
  128.     if (sym->mkstruct)
  129.     {
  130.         if (sym->realname != NULL && sym->realname != sym->name
  131.             && sym->rettype == findsymbol(sym->realname)->rettype)
  132.         return strbldf("%s_T%s%s", pre, sym->realname, post);
  133.         return strbldf("%s_T%s%s", pre, sym->name, post);
  134.     }
  135.     }
  136.     return strbldf("%s%s%s", pre, name, post);
  137. }
  138.  
  139. static const char *mkvoidtype(symbol *sym, char *pre = "", char *post = NULL)
  140. {
  141.     const char *type = mktype(sym, pre, post);
  142.     if (*type == '\0')
  143.     type = "void";
  144.     return type;
  145. }
  146.  
  147. static void mkstruct(symbol *sym)
  148. {
  149.     if (!dotype(sym) || !sym->mkstruct)
  150.         return;
  151.     char *name = sym->name;
  152.     if (sym->realname != NULL && sym->realname != sym->name)
  153.     {
  154.         symbol *real = findsymbol(sym->realname);
  155.         if (real->rettype == sym->rettype)
  156.         {
  157.             if (dotype(real))
  158.                 return;
  159.             name = sym->realname;
  160.         }
  161.     }
  162.     putf("\nstruct _T%s\n{\n", name);
  163.     putf("\t%s;\n};\n", sym->rettype);
  164. }
  165.  
  166. static void mkcode(char *pre, symbol *code)
  167. {
  168.     if (code == NULL || code->code == NULL)
  169.         return;
  170.  
  171.     if (genlineinfo)
  172.         putf("#line %d \"%s\"\n", code->line, inputfile);
  173.     else
  174.         putf("/* #line %d */\n", code->line);
  175.     putf("%s%s;\n", pre, code->code);
  176.     if (genlineinfo)
  177.         putf("#line %d \"%s\"\n", curr_lineno + 1, currfile);
  178. }
  179.  
  180. static const char *mkvarname(symnode *start, symnode *node)
  181. {
  182.     if (node->alias != NULL)
  183.         return node->alias;
  184.  
  185.     int count = 0;
  186.     boolean addnum = FALSE;
  187.     char *name = node->sym->name;
  188.  
  189.     if (node->sym->realname != NULL && node->sym->name != node->sym->realname)
  190.     {
  191.         name = "_";
  192.         for (symnode *n = start; n != node; n = n->next)
  193.             if (n->sym->type == NONTERMINAL && n->sym->realname != NULL 
  194.                     && n->sym->name != n->sym->realname)
  195.                 count++;
  196.         for (n = n->next; n != NULL; n = n->next)
  197.             if (n->sym->type == NONTERMINAL && n->sym->realname != NULL 
  198.                     && n->sym->name != n->sym->realname)
  199.                 addnum = TRUE;
  200.     }
  201.     else
  202.     {
  203.         for (symnode *n = start; n != node; n = n->next)
  204.             if (n->sym == node->sym)
  205.                 count++;
  206.         for (n = n->next; n != NULL; n = n->next)
  207.             if (n->sym == node->sym)
  208.                 addnum = TRUE;
  209.     }
  210.     if (addnum || count > 0)
  211.         return strbldf("%s%d", name, count + 1);
  212.     return name;
  213. }
  214.  
  215.  
  216. static void genstmt(char *pre, symnode *node)
  217. {
  218.     symbol *s;
  219.     symnode *n;
  220.  
  221.     for (n = node; n != NULL; n = n->next)
  222.     {
  223.         if (n->sym->type != NONTERMINAL || n->sym->id == EMPTY
  224.                 || !dotype(n->sym))
  225.             continue;
  226.         putf("%s%s _rv%s;\n", pre, mktype(n->sym), mkvarname(node, n));
  227.     }
  228.  
  229.     for (n = node; n != NULL; n = n->next)
  230.     {
  231.         s = n->sym;
  232.         if (s->type == CODE)
  233.         {
  234.             if (dumpcode)
  235.                 mkcode(pre, s);
  236.             continue;
  237.         }
  238.         if (s->id == EMPTY)
  239.             continue;
  240.  
  241.         if (s->type == TERMINAL)
  242.             putf("%s%sscantoken(%s, _link, _resync%d);\n",
  243.                     pre, mkretcode(s), mkname(s), n->resync->id);
  244.         else if (optimize && s->usecount == 1 && !s->export)
  245.         {
  246.             symbol *sym = s;
  247.             symnode *nn = n;
  248.             Bitset set(numsymbols());
  249.  
  250.             putf("%s{\n", pre);
  251.             if (dotype(s))
  252.                 putf("%s = _rv%s;\n", mktype(sym, pre, " &_rr"),
  253.                         mkvarname(node, nn));
  254.             else
  255.                 putf("%s\n", mktype(sym, pre, " _rr;"));
  256.             putf("%sresynclink &_lnk = _link;\n", pre);
  257.             putf("%sresynclink _link(_lnk, _resync%d);\n\n",
  258.                     pre, nn->resync->id);
  259.  
  260.             if (sym->resync != NULL)
  261.                 putf("%s (void)scantoken(-1, _link, _resync%d);\n\n",
  262.                         pre, sym->resync->id);
  263.  
  264.             if (sym->node != NULL && sym->node->or == NULL)
  265.             {
  266.                 genstmt("\t\t\t", sym->node);
  267.                 putf("\n%s}\n\n", pre);
  268.                 // putf("\n%sreturn RETOK;\n}\n\n", pre);
  269.                 continue;
  270.             }
  271.  
  272.             boolean donedefault = FALSE;
  273.             putf("%sswitch (w_nexttoken())\n\t{\n", pre);
  274.             for (symnode *n = sym->node; n != NULL; n = n->or)
  275.             {
  276.                 set.clear();
  277.                 for (symnode *s = n; s != NULL; s = s->next)
  278.                 {
  279.                     if (s->sym->type == CODE)
  280.                         continue;
  281.                     set |= *s->sym->first;
  282.                     if (!s->sym->first->isin(EMPTY))
  283.                         break;
  284.                 }
  285.  
  286.                 if (set.size() == 0 || (set.size() == 1 && set.isin(EMPTY)))
  287.                 {
  288.                     donedefault = TRUE;
  289.                     putf("%s\tdefault:\n", pre);
  290.                     genstmt("\t\t", n);
  291.                     if (!sym->first->isin(EMPTY))
  292.                         putf("%s\t\tw_scanerr(\"illegal %s\");\n",
  293.                                 pre, mkerrname(sym));
  294.                 }
  295.                 else
  296.                 {
  297.                     printcase("\t", set);
  298.                     putf("\t\t{\n");
  299.                     genstmt("\t\t\t", n);
  300.                     putf("\t\t}\n");
  301.                 }
  302.                 putf("\t\tbreak;\n");
  303.             }
  304.  
  305.             if (!donedefault && !sym->first->isin(EMPTY))
  306.             {
  307.                 putf("%s\tdefault:\n", pre);
  308.                 putf("%s\t\tw_scanerr(\"illegal %s\");\n",
  309.                         pre, mkerrname(sym));
  310.             }
  311.             putf("%s}", pre);
  312.             putf(" }\n");
  313.         }
  314.         else if (dotype(s))
  315.             putf("%s%s_f%s(_link, _resync%d, _rv%s);\n",
  316.                     pre, mkretcode(s), mkname(s),
  317.                     n->resync->id, mkvarname(node, n));
  318.         else
  319.             putf("%s%s_f%s(_link, _resync%d);\n",
  320.                     pre, mkretcode(s), mkname(s), n->resync->id);
  321.         // putf(" }\n");
  322.     }
  323. }
  324.  
  325.  
  326. static void genheader(void)
  327. {
  328.     symbol *sym;
  329.     int i;
  330.  
  331.     putf("#ifndef _T_O_K_E_N_S_\n#define _T_O_K_E_N_S_\n\n");
  332.  
  333.     putf("#ifndef NULL\n#include <stdio.h>\n#endif\n\n");
  334.     putf("#define RETOK 1\n");
  335.     putf("#define RETERR 0\n\n");
  336.  
  337.     putf("enum tokenids\n{\n");
  338.     putf("\tEOI = 0,\n");
  339.     putf("\t_EMPTY = 256, /* nothing uses this yet */\n");
  340.     boolean doid = TRUE;
  341.     for (i = START; i < numsymbols(); i++)
  342.     {
  343.     sym = getsymbol(i);
  344.     if (sym->type != TERMINAL || *sym->name == '\'')
  345.         continue;
  346.     if (doid)
  347.         putf("\t%s = 257,\n", mkname(sym));
  348.     else
  349.         putf("\t%s,\n", mkname(sym));
  350.     doid = FALSE;
  351.     }
  352.     putf("};\n\n");
  353.  
  354.     if (gotlexstr)
  355.     {
  356.     putf("#ifdef __cplusplus\n");
  357.     putf("extern \"C\" {\n");
  358.     putf("extern int yylex(void);\n");
  359.     putf("}\n");
  360.     putf("#else\n");
  361.     putf("extern int yylex();\n");
  362.     putf("#endif\n\n");
  363.  
  364.     putf("#ifdef FLEX_SCANNER\n");
  365.     putf("#   undef YY_INPUT\n");
  366.     putf("#   define YY_INPUT(buf,result,max_size) \\\n");
  367.     putf("        result = (buf[0] = w_input()) == EOI ? YY_NULL : 1;\n");
  368.     putf("#else\n");
  369.     putf("#   undef input\n");
  370.     putf("#   define input w_input\n");
  371.     putf("#   undef unput\n");
  372.     putf("#   define unput w_unput\n");
  373.     putf("#endif\n\n");
  374.  
  375.     }
  376.  
  377.     putf("extern int w_numerrors;\n");
  378.     putf("#ifdef __cplusplus\n");
  379.     putf("extern \"C\" {\n");
  380.     putf("extern int w_scanerr(const char *, ...);\n");
  381.     putf("extern void w_flusherrs(void);\n");
  382.     putf("extern void w_closefile(void);\n");
  383.     putf("extern int w_openfile(char *);\n");
  384.     putf("extern FILE *w_getfile(void);\n");
  385.     putf("extern void w_setfile(FILE *);\n");
  386.     putf("extern int w_currcol(void);\n");
  387.     putf("extern int w_currline(void);\n");
  388.     putf("extern char *w_getcurrline(void);\n");
  389.     putf("extern int w_input(void);\n");
  390.     putf("extern int w_unput(int);\n");
  391.     putf("extern void w_output(int);\n");
  392.     putf("extern int w_gettoken(void);\n");
  393.     putf("extern int w_nexttoken(void);\n");
  394.     putf("extern void w_skiptoken(void);\n");
  395.     putf("extern char *w_tokenname(int);\n");
  396.     putf("}\n");
  397.     putf("#else\n");
  398.     putf("extern int w_scanerr();\n");
  399.     putf("extern void w_flusherrs();\n");
  400.     putf("extern void w_closefile();\n");
  401.     putf("extern int w_openfile();\n");
  402.     putf("extern FILE *w_getfile();\n");
  403.     putf("extern void w_setfile();\n");
  404.     putf("extern int w_currcol();\n");
  405.     putf("extern int w_currline();\n");
  406.     putf("extern char *w_getcurrline();\n");
  407.     putf("extern int w_input();\n");
  408.     putf("extern int w_unput();\n");
  409.     putf("extern void w_output();\n");
  410.     putf("extern int w_gettoken();\n");
  411.     putf("extern int w_nexttoken();\n");
  412.     putf("extern void w_skiptoken();\n");
  413.     putf("extern char *w_tokenname();\n");
  414.     putf("#endif\n\n");
  415.  
  416.     if (exportedname)
  417.     {
  418.     for (i = 0; i < numnonterms(); i++)
  419.     {
  420.         sym = getnonterm(i);
  421.         if (sym->type != NONTERMINAL || !sym->export)
  422.         continue;
  423.         mkstruct(sym);
  424.         putf("#ifdef __cplusplus\n");
  425.         putf("extern \"C\" { int %s(%s); }\n", mkname(sym),
  426.             mkvoidtype(sym, "", " &"));
  427.         putf("#else\n");
  428.         putf("extern int %s();\n", mkname(sym));
  429.         putf("#endif\n");
  430.     }
  431.     }
  432.     else
  433.     {
  434.     mkstruct(startsymbol);
  435.     putf("#ifdef __cplusplus\n");
  436.     putf("extern \"C\" { int %s(%s); }\n", mkname(startsymbol),
  437.         mkvoidtype(startsymbol, "", " &"));
  438.     putf("#else\n");
  439.     putf("extern int %s();\n", mkname(startsymbol));
  440.     putf("#endif\n");
  441.     }
  442.  
  443.     putf("\n\n#endif /* _T_O_K_E_N_S_ */\n");
  444. }
  445.  
  446.  
  447. static void genscanner(char *header)
  448. {
  449.     symbol *sym;
  450.     int i, c;
  451.     boolean nl = TRUE;
  452.  
  453.     // scan past the definition section
  454.     while ((c = w_input()) != END)
  455.     {
  456.         if (nl && c == '%')
  457.         {
  458.             int t = w_input();
  459.             if (t == '%')
  460.                 break;
  461.             put(c);
  462.             c = t;
  463.         }
  464.         put(c);
  465.         nl = c == '\n';
  466.     }
  467.  
  468.     // dump out our header stuff here
  469.     putf("%%{\n");
  470.     putf("#include \"%s\"\n", header);
  471.     putf("%%}\n");
  472.  
  473.     putf("%%%%\n");
  474.  
  475.     // print the lexical values from the grammer
  476.     for (i = START; i < numsymbols(); i++)
  477.     {
  478.         symbol *sym = getsymbol(i);
  479.         if (sym->type != TERMINAL || sym->lexdef || sym->lexstr == NULL)
  480.             continue;
  481.         if (casesensitive || sym->name[0] != '"')
  482.             putf("%s", sym->lexstr);
  483.         else
  484.         {
  485.             for (char *s = sym->lexstr + 1;
  486.                     *s != '\0' && !(*s == '"' && *(s + 1) == '\0');
  487.                     s++)
  488.                 if (isalpha(*s))
  489.                     putf("[%c%c]",
  490.                         islower(*s) ? toupper(*s) : *s,
  491.                         isupper(*s) ? tolower(*s) : *s);
  492.                 else if (*s == '\\' && *(s+1) == '"')
  493.                     ;
  494.                 else
  495.                     putf("\\%c", *s);
  496.         }
  497.         putf("\t{ return (int)%s; }\n", mkname(sym));
  498.         sym->lexdef = TRUE;
  499.     }
  500.  
  501.     // now add the rules at the bottom of the source
  502.     if (c != END)
  503.         while ((c = w_input()) != END)
  504.         {
  505.             if (nl && c == '%')
  506.             {
  507.                 int t = w_input();
  508.                 if (t == '%')
  509.                     break;
  510.                 put(c);
  511.                 c = t;
  512.             }
  513.             else if (nl && c == '$')
  514.             {
  515.                 char *name = getword();
  516.                 if (name == NULL)
  517.                     quit("Unexpected end-of-w_input");
  518.                 sym = findsymbol(name);
  519.  
  520.                 if (sym == NULL)
  521.                     error("Symbol %s not in grammer", name);
  522.                 if (sym->lexstr != NULL)
  523.                     error("Symbol %s lexical string redefined in lex section",
  524.                             name);
  525.  
  526.                 while ((c = w_input()) == ' ' || c == '\t')
  527.                     ;
  528.                 if (c == '\n' || c == END)
  529.                     putf("\n");
  530.                 else
  531.                 {
  532.                     for (; c != END && c != '\n'; c = w_input())
  533.                         put(c);
  534.                     putf("\t{ return (int)%s; }", name);
  535.                 }
  536.                 sym->lexdef = TRUE;
  537.             }
  538.             put(c);
  539.             nl = c == '\n';
  540.         }
  541.  
  542.     // check for missing tokens
  543.     for (i = START; i < numsymbols(); i++)
  544.     {
  545.         sym = getsymbol(i);
  546.         if (sym->type != TERMINAL || sym->lexdef)
  547.             continue;
  548.         if (sym->lexstr == NULL)
  549.             error("Lexical value for symbol %s is not defined", mkname(sym));
  550.     }
  551.  
  552.     putf("%%%%\n");
  553.  
  554.     // now copy the rest (user code)
  555.     if (c != END)
  556.         while ((c = w_input()) != END)
  557.             put(c);
  558. }
  559.  
  560.  
  561. static void dumpexport(symbol *sym)
  562. {
  563.     putf("int %s(%s)\n{\n", mkname(sym),
  564.         mkvoidtype(sym, "", " &ret"));
  565.     putf("\tresynclink _link;\n\t");
  566.     printset("_follow", *sym->follow);
  567.     putf("\tint _rval;\n");
  568.     putf("\tint _savnum = w_numerrors;\n\n");
  569.     putf("\tw_numerrors = 0;\n");
  570.     putf("\t_rval = _f%s(_link, _follow%s);\n",
  571.             mkname(sym), dotype(sym) ? ", ret" : "");
  572.     putf("\tswitch (w_nexttoken())\n\t{\n");
  573.     printcase("\t", *sym->follow);
  574.     putf("\t\tbreak;\n");
  575.     putf("\tdefault:\n");
  576.     putf("\t\t_rval = w_scanerr(\"expected end of %s\");\n",
  577.             mkname(sym));
  578.     putf("\t}\n");
  579.     putf("\tif (w_numerrors > 0) _rval = RETERR;\n");
  580.     putf("\tw_numerrors += _savnum;\n");
  581.     putf("\tw_scanerr(NULL);\n");
  582.     putf("\treturn _rval;\n");
  583.     putf("}\n\n");
  584. }
  585.  
  586.  
  587. static void genparser(char *header)
  588. {
  589.     symbol *sym;
  590.     symnode *n;
  591.     int i;
  592.  
  593.     putf("#define YYTEXT_DECL unsigned char yytext[]\n\n");
  594.     mkcode("", startcode);
  595.     putf("\n#include \"%s\"\n\n", header);
  596.     putf("extern YYTEXT_DECL;\n");
  597.     putf("int w_numerrors = 0;\n\n");
  598.  
  599.     putf("\nstruct resynclink\n{\n\tresynclink *prev;\n");
  600.     putf("\tint *resync;\n");
  601.     putf("\tresynclink() { prev = 0; resync = 0; }\n");
  602.     putf("\tresynclink(resynclink &p, int *s)");
  603.     putf(" { prev = &p; resync = s; }\n");
  604.     putf("};\n");
  605.  
  606.     for (i = 0; i < numnonterms(); i++)
  607.     {
  608.         sym = getnonterm(i);
  609.         if (sym->type != NONTERMINAL)
  610.             continue;
  611.         if (!sym->export)
  612.             mkstruct(sym);
  613.         if (optimize && sym->usecount == 1 && !sym->export)
  614.             continue;
  615.         putf("static _f%s(resynclink &, int *%s);\n", mkname(sym),
  616.                 mktype(sym, ", ", " &"));
  617.     }
  618.     putf("\n");
  619.  
  620.     putf("static char *_toknams[] =\n{\n");
  621.     putf("\t\"[]\",\n");
  622.     for (i = START; i < numsymbols(); i++)
  623.     {
  624.         sym = getsymbol(i);
  625.         if (sym->type != TERMINAL || *sym->name == '\'')
  626.             continue;
  627.         char *str = sym->lexstr;
  628.  
  629.         if (str == NULL)
  630.             putf("\t\"%s\",\n", mkname(sym));
  631.         else if (isalpha(*str))
  632.             putf("\t\"%s\",\n", str);
  633.         else if (*str == '"' && str[strlen(str) - 1] == '"')
  634.             putf("\t%s,\n", sym->lexstr);
  635.         else
  636.             putf("\t\"%s\",\n", mkname(sym));
  637.     }
  638.     putf("};\n\n");
  639.  
  640.     putf("char *w_tokenname(int tok)\n{\n");
  641.     putf("\tstatic char buf[6];\n\n");
  642.     putf("\tif (tok > 255)\n");
  643.     putf("\t\treturn _toknams[tok - 256];\n");
  644.     putf("\tif (tok == 0)\n");
  645.     putf("\t\treturn \"EOI\";\n");
  646.     putf("\tbuf[0] = '`'; buf[1] = tok; buf[2] = '\\\'';\n");
  647.     putf("\treturn buf;\n");
  648.     putf("}\n\n");
  649.  
  650.     putf("static int tok = -1;\n\n");
  651.  
  652.     putf("int w_nexttoken()\n");
  653.     putf("{\n\tif (tok < 0)\n\t\ttok = w_gettoken();\n");
  654.     putf("\treturn tok;\n}\n\n");
  655.  
  656.     putf("void w_skiptoken()\n{\n\ttok = -1;\n}\n\n");
  657.  
  658.     putf("static int scantoken(int expect, resynclink &lnk, int *resync)\n");
  659.     putf("{\n\tresynclink rlink(lnk, resync);\n\tresynclink *link;\n\n");
  660.     putf("\tif (tok < 0)\n\t\ttok = w_gettoken();\n");
  661.     putf("\tif (expect >= 0 && tok != expect)\n");
  662.     putf("\t\tw_scanerr(\"expected %%s\", w_tokenname(expect));\n");
  663.     putf("\tint level = 1;\n");
  664.     putf("\twhile (tok != expect)\n\t{\n");
  665.     putf("\t\tint l = level;\n");
  666.     putf("\t\tfor (link = &rlink; link != NULL && l-- > 0;");
  667.     putf(" link = link->prev)\n");
  668.     putf("\t\t\tfor (int i = 0; link->resync[i] >= 0; i++)\n");
  669.     putf("\t\t\t\tif (tok == link->resync[i])\n");
  670.     putf("\t\t\t\t\treturn -1;\n\n");
  671.     putf("\t\tw_scanerr(NULL);\n");
  672.