#include <boost/foreach.hpp>
#include <boost/algorithm/string.hpp>
#include <cassert>
#include <algorithm>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "lemon_c.h"
lemon_c::lemon_c(char *argv0, const std::string & filename, bool basisflag,
bool nolinenosflag)
: lemon(argv0, filename, basisflag, nolinenosflag)
, mhflag(false)
{
}
lemon_c::~lemon_c()
{
}
void lemon_c::makeheaders(bool mhflag)
{
this->mhflag = mhflag;
}
void lemon_c::doOutput()
{
this->ReportTable("lempar.c");
this->ReportHeader();
}
/*
** Append text to a dynamically allocated string. If zText is 0 then
** reset the string to be empty again. Always return the complete text
** of the string (which is overwritten with each call).
**
** n bytes of zText are stored. If n==0 then all of zText up to the first
** \000 terminator is stored. zText can contain up to two instances of
** %d. The values of p1 and p2 are written into the first and second
** %d.
**
** If n==-1, then the previous character is overwritten.
*/
char *append_str(const char *zText, int n, int p1, int p2)
{
static char *z = 0;
static unsigned int alloced = 0;
static unsigned int used = 0;
int c;
char zInt[40];
if (zText == 0) {
used = 0;
return z;
}
if (n <= 0) {
if (n < 0) {
used += n;
assert(used >= 0);
}
n = strlen(zText);
}
if (n + sizeof(zInt) * 2 + used >= alloced) {
alloced = n + sizeof(zInt) * 2 + used + 200;
z = (char *)realloc(z, alloced);
}
if (z == 0)
return "";
while (n-- > 0) {
c = *(zText++);
if (c == '%' && n > 0 && zText[0] == 'd') {
sprintf(zInt, "%d", p1);
p1 = p2;
strcpy(&z[used], zInt);
used += strlen(&z[used]);
zText++;
n--;
} else {
z[used++] = c;
}
}
z[used] = 0;
return z;
}
/*
** Compare to axset structures for sorting purposes
*/
static int axset_compare(const void *a, const void *b)
{
struct axset *p1 = (struct axset *)a;
struct axset *p2 = (struct axset *)b;
return p2->nAction - p1->nAction;
}
/* Generate C source code for the parser */
/* Output in makeheaders format if true */
void lemon_c::ReportTable(const std::string &templatename)
{
FILE *out, *in;
char line[LINESIZE];
int lineno;
state *stp;
rule *rp;
acttab Acttab;
int i, j, n;
const char *name;
int mnTknOfst, mxTknOfst;
int mnNtOfst, mxNtOfst;
axset *ax;
in = this->tplt_open(templatename);
if (in == 0)
return;
out = this->file_open(".c", "wb");
if (out == 0) {
fclose(in);
return;
}
lineno = 1;
tplt_xfer(this->name, in, out, &lineno);
/* Generate the include code, if any */
this->tplt_print(out, this->include, &lineno);
if (this->mhflag) {
std::string * name = lemon::file_makename(this->filename, ".h");
fprintf(out, "#include \"%s\"\n", name->c_str());
lineno++;
delete name;
}
tplt_xfer(this->name, in, out, &lineno);
/* Generate #defines for all tokens */
if (this->mhflag) {
fprintf(out, "#if INTERFACE\n");
lineno++;
const char *prefix;
if (this->tokenprefix)
prefix = this->tokenprefix;
else
prefix = "";
for (int i = 1; i < this->nterminal; i++) {
fprintf(out, "#define %s%-30s %2d\n", prefix,
this->symbols[i]->name, i);
lineno++;
}
fprintf(out, "#endif\n");
lineno++;
}
tplt_xfer(this->name, in, out, &lineno);
/* Generate the defines */
fprintf(out, "#define YYCODETYPE %s\n",
minimum_size_type(0, this->nsymbol + 1));
lineno++;
fprintf(out, "#define YYNOCODE %d\n", this->nsymbol + 1);
lineno++;
fprintf(out, "#define YYACTIONTYPE %s\n",
minimum_size_type(0, this->nstate + this->nrule + 5));
lineno++;
if (this->wildcard) {
fprintf(out, "#define YYWILDCARD %d\n", this->wildcard->index);
lineno++;
}
this->print_stack_union(out, &lineno);
fprintf(out, "#ifndef YYSTACKDEPTH\n");
lineno++;
if (this->stacksize) {
fprintf(out, "#define YYSTACKDEPTH %s\n", this->stacksize);
lineno++;
} else {
fprintf(out, "#define YYSTACKDEPTH 100\n");
lineno++;
}
fprintf(out, "#endif\n");
lineno++;
if (this->mhflag) {
fprintf(out, "#if INTERFACE\n");
lineno++;
}
name = this->name ? this->name : lemon::Parse_string;
if (this->arg && this->arg[0]) {
int i;
i = strlen(this->arg);
while (i >= 1 && isspace(this->arg[i - 1]))
i--;
while (i >= 1
&& (isalnum(this->arg[i - 1])
|| this->arg[i - 1] == '_'))
i--;
fprintf(out, "#define %sARG_SDECL %s;\n", name, this->arg);
lineno++;
fprintf(out, "#define %sARG_PDECL ,%s\n", name, this->arg);
lineno++;
fprintf(out, "#define %sARG_FETCH %s = yypParser->%s\n",
name, this->arg, &this->arg[i]);
lineno++;
fprintf(out, "#define %sARG_STORE yypParser->%s = %s\n",
name, &this->arg[i], &this->arg[i]);
lineno++;
} else {
fprintf(out, "#define %sARG_SDECL\n", name);
lineno++;
fprintf(out, "#define %sARG_PDECL\n", name);
lineno++;
fprintf(out, "#define %sARG_FETCH\n", name);
lineno++;
fprintf(out, "#define %sARG_STORE\n", name);
lineno++;
}
if (this->mhflag) {
fprintf(out, "#endif\n");
lineno++;
}
fprintf(out, "#define YYNSTATE %d\n", this->nstate);
lineno++;
fprintf(out, "#define YYNRULE %d\n", this->nrule);
lineno++;
if (this->errsym->useCnt) {
fprintf(out, "#define YYERRORSYMBOL %d\n", this->errsym->index);
lineno++;
fprintf(out, "#define YYERRSYMDT yy%d\n", this->errsym->dtnum);
lineno++;
}
if (this->has_fallback) {
fprintf(out, "#define YYFALLBACK 1\n");
lineno++;
}
tplt_xfer(this->name, in, out, &lineno);
/* Generate the action table and its associates:
**
** yy_action[] A single table containing all actions.
** yy_lookahead[] A table containing the lookahead for each entry in
** yy_action. Used to detect hash collisions.
** yy_shift_ofst[] For each state, the offset into yy_action for
** shifting terminals.
** yy_reduce_ofst[] For each state, the offset into yy_action for
** shifting non-terminals after a reduce.
** yy_default[] Default action for each state.
*/
/* Compute the actions on all states and count them up */
ax = (axset *) calloc(this->nstate * 2, sizeof(ax[0]));
MemoryCheck(ax);
for (i = 0; i < this->nstate; i++) {
stp = this->sorted[i];
ax[i * 2].stp = stp;
ax[i * 2].isTkn = 1;
ax[i * 2].nAction = stp->nTknAct;
ax[i * 2 + 1].stp = stp;
ax[i * 2 + 1].isTkn = 0;
ax[i * 2 + 1].nAction = stp->nNtAct;
}
mxTknOfst = mnTknOfst = 0;
mxNtOfst = mnNtOfst = 0;
/* Compute the action table. In order to try to keep the size of the
** action table to a minimum, the heuristic of placing the largest action
** sets first is used.
*/
qsort(ax, this->nstate * 2, sizeof(ax[0]), axset_compare);
for (i = 0; i < this->nstate * 2 && ax[i].nAction > 0; i++) {
stp = ax[i].stp;
if (ax[i].isTkn) {
BOOST_FOREACH(action *ap, stp->actions) {
if (ap->sp->index >= this->nterminal)
continue;
int action = this->compute_action(ap);
if (action < 0)
continue;
Acttab.do_action(ap->sp->index, action);
}
stp->iTknOfst = Acttab.insert();
if (stp->iTknOfst < mnTknOfst)
mnTknOfst = stp->iTknOfst;
if (stp->iTknOfst > mxTknOfst)
mxTknOfst = stp->iTknOfst;
} else {
BOOST_FOREACH(action *ap, stp->actions) {
if (ap->sp->index < this->nterminal)
continue;
if (ap->sp->index == this->nsymbol)
continue;
int action = this->compute_action(ap);
if (action < 0)
continue;
Acttab.do_action(ap->sp->index, action);
}
stp->iNtOfst = Acttab.insert();
if (stp->iNtOfst < mnNtOfst)
mnNtOfst = stp->iNtOfst;
if (stp->iNtOfst > mxNtOfst)
mxNtOfst = stp->iNtOfst;
}
}
free(ax);
/* Output the yy_action table */
fprintf(out, "static const YYACTIONTYPE yy_action[] = {\n");
lineno++;
n = Acttab.size();
for (i = j = 0; i < n; i++) {
int action = Acttab.yyaction(i);
if (action < 0)
action = this->nstate + this->nrule + 2;
if (j == 0)
fprintf(out, " /* %5d */ ", i);
fprintf(out, " %4d,", action);
if (j == 9 || i == n - 1) {
fprintf(out, "\n");
lineno++;
j = 0;
} else {
j++;
}
}
fprintf(out, "};\n");
lineno++;
/* Output the yy_lookahead table */
fprintf(out, "static const YYCODETYPE yy_lookahead[] = {\n");
lineno++;
for (i = j = 0; i < n; i++) {
int la = Acttab.yylookahead(i);
if (la < 0)
la = this->nsymbol;
if (j == 0)
fprintf(out, " /* %5d */ ", i);
fprintf(out, " %4d,", la);
if (j == 9 || i == n - 1) {
fprintf(out, "\n");
lineno++;
j = 0;
} else {
j++;
}
}
fprintf(out, "};\n");
lineno++;
/* Output the yy_shift_ofst[] table */
fprintf(out, "#define YY_SHIFT_USE_DFLT (%d)\n", mnTknOfst - 1);
lineno++;
n = this->nstate;
while (n > 0 && this->sorted[n - 1]->iTknOfst == NO_OFFSET)
n--;
fprintf(out, "#define YY_SHIFT_MAX %d\n", n - 1);
lineno++;
fprintf(out, "static const %s yy_shift_ofst[] = {\n",
minimum_size_type(mnTknOfst - 1, mxTknOfst));
lineno++;
for (i = j = 0; i < n; i++) {
int ofst;
stp = this->sorted[i];
ofst = stp->iTknOfst;
if (ofst == NO_OFFSET)
ofst = mnTknOfst - 1;
if (j == 0)
fprintf(out, " /* %5d */ ", i);
fprintf(out, " %4d,", ofst);
if (j == 9 || i == n - 1) {
fprintf(out, "\n");
lineno++;
j = 0;
} else {
j++;
}
}
fprintf(out, "};\n");
lineno++;
/* Output the yy_reduce_ofst[] table */
fprintf(out, "#define YY_REDUCE_USE_DFLT (%d)\n", mnNtOfst - 1);
lineno++;
n = this->nstate;
while (n > 0 && this->sorted[n - 1]->iNtOfst == NO_OFFSET)
n--;
fprintf(out, "#define YY_REDUCE_MAX %d\n", n - 1);
lineno++;
fprintf(out, "static const %s yy_reduce_ofst[] = {\n",
minimum_size_type(mnNtOfst - 1, mxNtOfst));
lineno++;
for (i = j = 0; i < n; i++) {
int ofst;
stp = this->sorted[i];
ofst = stp->iNtOfst;
if (ofst == NO_OFFSET)
ofst = mnNtOfst - 1;
if (j == 0)
fprintf(out, " /* %5d */ ", i);
fprintf(out, " %4d,", ofst);
if (j == 9 || i == n - 1) {
fprintf(out, "\n");
lineno++;
j = 0;
} else {
j++;
}
}
fprintf(out, "};\n");
lineno++;
/* Output the default action table */
fprintf(out, "static const YYACTIONTYPE yy_default[] = {\n");
lineno++;
n = this->nstate;
for (i = j = 0; i < n; i++) {
stp = this->sorted[i];
if (j == 0)
fprintf(out, " /* %5d */ ", i);
fprintf(out, " %4d,", stp->iDflt);
if (j == 9 || i == n - 1) {
fprintf(out, "\n");
lineno++;
j = 0;
} else {
j++;
}
}
fprintf(out, "};\n");
lineno++;
tplt_xfer(this->name, in, out, &lineno);
/* Generate the table of fallback tokens.
*/
if (this->has_fallback) {
int mx = this->nterminal - 1;
while (mx > 0 && this->symbols[mx]->fallback == 0) {
mx--;
}
for (i = 0; i <= mx; i++) {
symbol *p = this->symbols[i];
if (p->fallback == 0) {
fprintf(out, " 0, /* %10s => nothing */\n",
p->name);
} else {
fprintf(out, " %3d, /* %10s => %s */\n",
p->fallback->index, p->name,
p->fallback->name);
}
lineno++;
}
}
tplt_xfer(this->name, in, out, &lineno);
/* Generate a table containing the symbolic name of every symbol
*/
for (i = 0; i < this->nsymbol; i++) {
sprintf(line, "\"%s\",", this->symbols[i]->name);
fprintf(out, " %-15s", line);
if ((i & 3) == 3) {
fprintf(out, "\n");
lineno++;
}
}
if ((i & 3) != 0) {
fprintf(out, "\n");
lineno++;
}
tplt_xfer(this->name, in, out, &lineno);
/* Generate a table containing a text string that describes every
** rule in the rule set of the grammar. This information is used
** when tracing REDUCE actions.
*/
for (i = 0, rp = this->rules; rp; rp = rp->next, i++) {
assert(rp->index == i);
fprintf(out, " /* %3d */ \"", i);
rp->writeRuleText(out);
fprintf(out, "\",\n");
lineno++;
}
tplt_xfer(this->name, in, out, &lineno);
/* Generate code which executes every time a symbol is popped from
** the stack while processing errors or while destroying the parser.
** (In other words, generate the %destructor actions)
*/
if (this->tokendest) {
int once = 1;
for (i = 0; i < this->nsymbol; i++) {
symbol *sp = this->symbols[i];
if (sp == 0 || sp->type != symbol::TERMINAL)
continue;
if (once) {
fprintf(out,
" /* TERMINAL Destructor */\n");
lineno++;
once = 0;
}
fprintf(out, " case %d: /* %s */\n", sp->index,
sp->name);
lineno++;
}
for (i = 0;
i < this->nsymbol
&& this->symbols[i]->type != symbol::TERMINAL; i++) ;
if (i < this->nsymbol) {
this->emit_destructor_code(out, this->symbols[i],
&lineno);
fprintf(out, " break;\n");
lineno++;
}
}
if (this->vardest) {
symbol *dflt_sp = 0;
int once = 1;
for (i = 0; i < this->nsymbol; i++) {
symbol *sp = this->symbols[i];
if (sp == 0 || sp->type == symbol::TERMINAL ||
sp->index <= 0 || sp->destructor != 0)
continue;
if (once) {
fprintf(out,
" /* Default NON-TERMINAL Destructor */\n");
lineno++;
once = 0;
}
fprintf(out, " case %d: /* %s */\n", sp->index,
sp->name);
lineno++;
dflt_sp = sp;
}
if (dflt_sp != 0) {
this->emit_destructor_code(out, dflt_sp, &lineno);
}
fprintf(out, " break;\n");
lineno++;
}
for (i = 0; i < this->nsymbol; i++) {
symbol *sp = this->symbols[i];
if (sp == 0 || sp->type == symbol::TERMINAL
|| sp->destructor == 0)
continue;
fprintf(out, " case %d: /* %s */\n", sp->index, sp->name);
lineno++;
/* Combine duplicate destructors into a single case */
for (j = i + 1; j < this->nsymbol; j++) {
symbol *sp2 = this->symbols[j];
if (sp2 && sp2->type != symbol::TERMINAL
&& sp2->destructor && sp2->dtnum == sp->dtnum
&& strcmp(sp->destructor, sp2->destructor) == 0) {
fprintf(out, " case %d: /* %s */\n",
sp2->index, sp2->name);
lineno++;
sp2->destructor = 0;
}
}
this->emit_destructor_code(out, this->symbols[i], &lineno);
fprintf(out, " break;\n");
lineno++;
}
tplt_xfer(this->name, in, out, &lineno);
/* Generate code which executes whenever the parser stack overflows */
this->tplt_print(out, this->overflow, &lineno);
tplt_xfer(this->name, in, out, &lineno);
/* Generate the table of rule information
**
** Note: This code depends on the fact that rules are number
** sequentually beginning with 0.
*/
for (rp = this->rules; rp; rp = rp->next) {
fprintf(out, " { %d, %d },\n", rp->lhs->index, rp->rhs.size());
lineno++;
}
tplt_xfer(this->name, in, out, &lineno);
/* Generate code which execution during each REDUCE action */
for (rp = this->rules; rp; rp = rp->next) {
this->translate_code(rp);
}
/* First output rules other than the default: rule */
for (rp = this->rules; rp; rp = rp->next) {
rule *rp2; /* Other rules with the same action */
if (rp->code == 0)
continue;
if (rp->code[0] == '\n' && rp->code[1] == 0)
continue; /* Will be default: */
fprintf(out, " case %d: /* ", rp->index);
rp->writeRuleText(out);
fprintf(out, " */\n");
lineno++;
for (rp2 = rp->next; rp2; rp2 = rp2->next) {
if (rp2->code == rp->code) {
fprintf(out, " case %d: /* ", rp2->index);
rp2->writeRuleText(out);
fprintf(out, " */ yytestcase(yyruleno==%d);\n",
rp2->index);
lineno++;
rp2->code = 0;
}
}
this->emit_code(out, rp, &lineno);
fprintf(out, " break;\n");
lineno++;
rp->code = 0;
}
/* Finally, output the default: rule. We choose as the default: all
** empty actions. */
fprintf(out, " default:\n");
lineno++;
for (rp = this->rules; rp; rp = rp->next) {
if (rp->code == 0)
continue;
assert(rp->code[0] == '\n' && rp->code[1] == 0);
fprintf(out, " /* (%d) ", rp->index);
rp->writeRuleText(out);
fprintf(out, " */ yytestcase(yyruleno==%d);\n", rp->index);
lineno++;
}
fprintf(out, " break;\n");
lineno++;
tplt_xfer(this->name, in, out, &lineno);
/* Generate code which executes if a parse fails */
this->tplt_print(out, this->failure, &lineno);
tplt_xfer(this->name, in, out, &lineno);
/* Generate code which executes when a syntax error occurs */
this->tplt_print(out, this->error, &lineno);
tplt_xfer(this->name, in, out, &lineno);
/* Generate code which executes when the parser accepts its input */
this->tplt_print(out, this->accept, &lineno);
tplt_xfer(this->name, in, out, &lineno);
/* Append any addition code the user desires */
this->tplt_print(out, this->extracode, &lineno);
fclose(in);
fclose(out);
return;
}
/* Generate a header file for the parser */
void lemon_c::ReportHeader()
{
if (this->mhflag)
return;
FILE *out, *in;
const char *prefix;
char line[LINESIZE];
char pattern[LINESIZE];
int i;
if (this->tokenprefix)
prefix = this->tokenprefix;
else
prefix = "";
in = file_open(".h", "rb");
if (in) {
for (i = 1; i < this->nterminal && fgets(line, LINESIZE, in);
i++) {
sprintf(pattern, "#define %s%-30s %2d\n", prefix,
this->symbols[i]->name, i);
if (strcmp(line, pattern))
break;
}
fclose(in);
if (i == this->nterminal) {
/* No change in the file. Don't rewrite it. */
return;
}
}
out = this->file_open(".h", "wb");
if (out) {
for (i = 1; i < this->nterminal; i++) {
fprintf(out, "#define %s%-30s %2d\n", prefix,
this->symbols[i]->name, i);
}
fclose(out);
}
return;
}
/*
** Print the definition of the union used for the parser's data stack.
** This union contains fields for every possible data type for tokens
** and nonterminals. In the process of computing and printing this
** union, also set the ".dtnum" field of every terminal and nonterminal
** symbol.
*/
/* out = The output stream */
/* plineno = Pointer to the line number */
void lemon_c::print_stack_union(FILE * out, int *plineno)
{
int lineno = *plineno; /* The line number of the output */
std::vector<char*> types(this->nsymbol*2, (char*)0);
/* Build a hash table of datatypes. The ".dtnum" field of each symbol
** is filled in with the hash index plus 1. A ".dtnum" value of 0 is
** used for terminal symbols. If there is no %default_type defined then
** 0 is also used as the .dtnum value for nonterminals which do not specify
** a datatype using the %type directive.
*/
for (int i = 0; i < this->nsymbol; i++) {
symbol *sp = this->symbols[i];
if (sp == this->errsym) {
sp->dtnum = types.size() + 1;
continue;
}
if (sp->type != symbol::NONTERMINAL
|| (sp->datatype == 0 && this->vartype == 0)) {
sp->dtnum = 0;
continue;
}
char *cp = sp->datatype;
if (cp == 0)
cp = this->vartype;
std::string stddt(cp); /* Standardized name for a datatype */
boost::trim(stddt);
if (this->tokentype && strcmp(stddt.c_str(), this->tokentype) == 0) {
sp->dtnum = 0;
continue;
}
int hash = 0;
BOOST_FOREACH(char c, stddt) {
hash = hash * 53 + c;
}
hash = (hash & 0x7fffffff) % types.size();
while (types[hash]) {
if (strcmp(types[hash], stddt.c_str()) == 0) {
sp->dtnum = hash + 1;
break;
}
hash++;
if (hash >= types.size())
hash = 0;
}
if (types[hash] == 0) {
sp->dtnum = hash + 1;
types[hash] = (char *)malloc(stddt.length() + 1);
if (types[hash] == 0) {
fprintf(stderr, "Out of memory.\n");
exit(1);
}
strcpy(types[hash], stddt.c_str());
}
}
/* Print out the definition of YYTOKENTYPE and YYMINORTYPE */
const char *name = this->name ? this->name : Parse_string;
lineno = *plineno;
if (this->mhflag) {
fprintf(out, "#if INTERFACE\n");
lineno++;
}
fprintf(out, "#define %sTOKENTYPE %s\n", name,
this->tokentype ? this->tokentype : "void*");
lineno++;
if (this->mhflag) {
fprintf(out, "#endif\n");
lineno++;
}
fprintf(out, "typedef union {\n");
lineno++;
fprintf(out, " int yyinit;\n");
lineno++;
fprintf(out, " %sTOKENTYPE yy0;\n", name);
lineno++;
for (size_t i = 0; i < types.size(); i++) {
if (types[i] == 0)
continue;
fprintf(out, " %s yy%d;\n", types[i], i + 1);
lineno++;
free(types[i]);
}
if (this->errsym->useCnt) {
fprintf(out, " int yy%d;\n", this->errsym->dtnum);
lineno++;
}
fprintf(out, "} YYMINORTYPE;\n");
lineno++;
*plineno = lineno;
}
/*
** Return the name of a C datatype able to represent values between
** lwr and upr, inclusive.
*/
const char *lemon_c::minimum_size_type(int lwr, int upr)
{
if (lwr >= 0) {
if (upr <= 255) {
return "unsigned char";
} else if (upr < 65535) {
return "unsigned short int";
} else {
return "unsigned int";
}
} else if (lwr >= -127 && upr <= 127) {
return "signed char";
} else if (lwr >= -32767 && upr < 32767) {
return "short";
} else {
return "int";
}
}
/*
** zCode is a string that is the action associated with a rule. Expand
** the symbols in this string so that the refer to elements of the parser
** stack.
*/
void lemon_c::translate_code(rule *rp)
{
char *cp, *xp;
bool lhsused = false; /* True if the LHS element has been used */
bool used[MAXRHS]; /* True for each RHS element which is used */
for (size_t i = 0; i < rp->rhs.size(); ++i)
used[i] = false;
if (rp->code == 0) {
rp->code = "\n";
rp->line = rp->ruleline;
}
append_str(0, 0, 0, 0);
for (cp = rp->code; *cp; cp++) {
if (isalpha(*cp)
&& (cp == rp->code
|| (!isalnum(cp[-1]) && cp[-1] != '_'))) {
char saved;
for (xp = &cp[1]; isalnum(*xp) || *xp == '_'; xp++) ;
saved = *xp;
*xp = 0;
if (rp->lhsalias && strcmp(cp, rp->lhsalias) == 0) {
append_str("yygotominor.yy%d", 0,
rp->lhs->dtnum, 0);
cp = xp;
lhsused = true;
} else {
for (size_t i = 0; i < rp->rhs.size(); ++i) {
if (rp->rhsalias[i]
&& strcmp(cp,
rp->rhsalias[i]) == 0) {
if (cp != rp->code
&& cp[-1] == '@') {
/* If the argument is of the form @X then substituted
** the token number of X, not the value of X */
append_str
("yymsp[%d].major",
-1,
i -
rp->rhs.size() + 1,
0);
} else {
symbol *sp =
rp->rhs[i];
int dtnum;
if (sp->type ==
symbol::
MULTITERMINAL) {
dtnum =
sp->
subsym[0]->
dtnum;
} else {
dtnum =
sp->dtnum;
}
append_str
("yymsp[%d].minor.yy%d",
0,
i -
rp->rhs.size() + 1,
dtnum);
}
cp = xp;
used[i] = true;
break;
}
}
}
*xp = saved;
}
append_str(cp, 1, 0, 0);
} /* End loop */
/* Check to make sure the LHS has been used */
if (rp->lhsalias && !lhsused) {
ErrorMsg(this->filename, rp->ruleline,
"Label \"%s\" for \"%s(%s)\" is never used.",
rp->lhsalias, rp->lhs->name, rp->lhsalias);
this->errorcnt++;
}
/* Generate destructor code for RHS symbols which are not used in the
** reduce code */
for (size_t i = 0; i < rp->rhs.size(); ++i) {
if (rp->rhsalias[i] && !used[i]) {
ErrorMsg(this->filename, rp->ruleline,
"Label %s for \"%s(%s)\" is never used.",
rp->rhsalias[i], rp->rhs[i]->name,
rp->rhsalias[i]);
this->errorcnt++;
} else if (rp->rhsalias[i] == 0) {
if (this->has_destructor(rp->rhs[i])) {
append_str
(" yy_destructor(yypParser,%d,&yymsp[%d].minor);\n",
0, rp->rhs[i]->index,
i - rp->rhs.size() + 1);
} else {
/* No destructor defined for this term */
}
}
}
if (rp->code) {
cp = append_str(0, 0, 0, 0);
rp->code = Strsafe(cp ? cp : "");
}
}
/*
** Generate code which executes when the rule "rp" is reduced. Write
** the code to "out". Make sure lineno stays up-to-date.
*/
void lemon_c::emit_code(FILE * out, rule *rp, int *lineno)
{
char *cp;
/* Generate code to do the reduce action */
if (rp->code) {
if (!this->nolinenosflag) {
(*lineno)++;
tplt_linedir(out, rp->line, this->filename);
}
fprintf(out, "{%s", rp->code);
for (cp = rp->code; *cp; cp++) {
if (*cp == '\n')
(*lineno)++;
} /* End loop */
fprintf(out, "}\n");
(*lineno)++;
if (!this->nolinenosflag) {
(*lineno)++;
char *filename = strdup(this->outname->c_str());
tplt_linedir(out, *lineno, filename);
free(filename);
}
}
/* End if( rp->code ) */
return;
}
acttab::acttab()
: nAction(0)
, nActionAlloc(0)
, aAction(0)
, aLookahead(0)
, mnLookahead(0)
, mnAction(0)
, mxLookahead(0)
, nLookahead(0)
, nLookaheadAlloc(0)
{
}
acttab::~acttab()
{
free(this->aAction);
free(this->aLookahead);
}
/* Add a new action to the current transaction set
*/
void acttab::do_action(int lookahead, int action)
{
if (this->nLookahead >= this->nLookaheadAlloc) {
this->nLookaheadAlloc += 25;
this->aLookahead = (acttab::action *) realloc(this->aLookahead,
sizeof(this->
aLookahead[0])
*
this->nLookaheadAlloc);
MemoryCheck(this->aLookahead);
}
if (this->nLookahead == 0) {
this->mxLookahead = lookahead;
this->mnLookahead = lookahead;
this->mnAction = action;
} else {
if (this->mxLookahead < lookahead)
this->mxLookahead = lookahead;
if (this->mnLookahead > lookahead) {
this->mnLookahead = lookahead;
this->mnAction = action;
}
}
this->aLookahead[this->nLookahead].lookahead = lookahead;
this->aLookahead[this->nLookahead].action = action;
this->nLookahead++;
}
/*
** Add the transaction set built up with prior calls to acttab_action()
** into the current action table. Then reset the transaction set back
** to an empty set in preparation for a new round of acttab_action() calls.
**
** Return the offset into the action table of the new transaction.
*/
int acttab::insert()
{
int i, j, k, n;
assert(this->nLookahead > 0);
/* Make sure we have enough space to hold the expanded action table
** in the worst case. The worst case occurs if the transaction set
** must be appended to the current action table
*/
n = this->mxLookahead + 1;
if (this->nAction + n >= this->nActionAlloc) {
int oldAlloc = this->nActionAlloc;
this->nActionAlloc = this->nAction + n + this->nActionAlloc + 20;
this->aAction = (acttab::action *) realloc(this->aAction,
sizeof(this->aAction[0]) *
this->nActionAlloc);
MemoryCheck(this->aAction);
for (i = oldAlloc; i < this->nActionAlloc; i++) {
this->aAction[i].lookahead = -1;
this->aAction[i].action = -1;
}
}
/* Scan the existing action table looking for an offset where we can
** insert the current transaction set. Fall out of the loop when that
** offset is found. In the worst case, we fall out of the loop when
** i reaches this->nAction, which means we append the new transaction set.
**
** i is the index in this->aAction[] where this->mnLookahead is inserted.
*/
for (i = 0; i < this->nAction + this->mnLookahead; i++) {
if (this->aAction[i].lookahead < 0) {
for (j = 0; j < this->nLookahead; j++) {
k = this->aLookahead[j].lookahead -
this->mnLookahead + i;
if (k < 0)
break;
if (this->aAction[k].lookahead >= 0)
break;
}
if (j < this->nLookahead)
continue;
for (j = 0; j < this->nAction; j++) {
if (this->aAction[j].lookahead ==
j + this->mnLookahead - i)
break;
}
if (j == this->nAction) {
break; /* Fits in empty slots */
}
} else if (this->aAction[i].lookahead == this->mnLookahead) {
if (this->aAction[i].action != this->mnAction)
continue;
for (j = 0; j < this->nLookahead; j++) {
k = this->aLookahead[j].lookahead -
this->mnLookahead + i;
if (k < 0 || k >= this->nAction)
break;
if (this->aLookahead[j].lookahead !=
this->aAction[k].lookahead)
break;
if (this->aLookahead[j].action !=
this->aAction[k].action)
break;
}
if (j < this->nLookahead)
continue;
n = 0;
for (j = 0; j < this->nAction; j++) {
if (this->aAction[j].lookahead < 0)
continue;
if (this->aAction[j].lookahead ==
j + this->mnLookahead - i)
n++;
}
if (n == this->nLookahead) {
break; /* Same as a prior transaction set */
}
}
}
/* Insert transaction set at index i. */
for (j = 0; j < this->nLookahead; j++) {
k = this->aLookahead[j].lookahead - this->mnLookahead + i;
this->aAction[k] = this->aLookahead[j];
if (k >= this->nAction)
this->nAction = k + 1;
}
this->nLookahead = 0;
/* Return the offset that is added to the lookahead in order to get the
** index into yy_action of the action */
return i - this->mnLookahead;
}
/*
** The following routine emits code for the destructor for the
** symbol sp
*/
void lemon_c::emit_destructor_code(FILE * out, struct symbol *sp, int *lineno)
{
char *cp = 0;
if (sp->type == symbol::TERMINAL) {
cp = this->tokendest;
if (cp == 0)
return;
fprintf(out, "{\n");
(*lineno)++;
} else if (sp->destructor) {
cp = sp->destructor;
fprintf(out, "{\n");
(*lineno)++;
if (!this->nolinenosflag) {
(*lineno)++;
tplt_linedir(out, sp->destLineno, this->filename);
}
} else if (this->vardest) {
cp = this->vardest;
if (cp == 0)
return;
fprintf(out, "{\n");
(*lineno)++;
} else {
assert(0); /* Cannot happen */
}
for (; *cp; cp++) {
if (*cp == '$' && cp[1] == '$') {
fprintf(out, "(yypminor->yy%d)", sp->dtnum);
cp++;
continue;
}
if (*cp == '\n')
(*lineno)++;
fputc(*cp, out);
}
fprintf(out, "\n");
(*lineno)++;
if (!this->nolinenosflag) {
(*lineno)++;
char *filename = strdup(this->outname->c_str());
tplt_linedir(out, *lineno, filename);
free(filename);
}
fprintf(out, "}\n");
(*lineno)++;
return;
}