Every man should father a child, build a house, plant a tree, and write a compiler compiler. This one is mine.
yiyiyacc is a small lalr(1) syntax generator, designed to output very slim self-contained c methods.
Among others, it has been used to generate the expression evaluation in swfc.
yiyiyacc source codeThis is an example for a yiyiyacc grammar:
E -> E '+' T %% = %1 + %2; E -> '-' T %% = 0 - %1; E -> E '-' T %% = %1 - %2; E -> T T -> T '*' F %% = %1 * %2; T -> T '/' F %% = %1 / %2; T -> F F -> <*> F -> '(' E ')' %% = %1; <*> %% = atof(%1);
And below is the C code that will be generated. Notice that the complete parser is contained in a single function.
/* automatically generated by yiyiyacc, http://www.quiss.org/yiyiyacc/ */ double parse(const char*s) { static int chr2index[256]; static int initialized=0; if(!initialized) { initialized=1; memset(chr2index, -1, sizeof(chr2index)); chr2index['+'] = 0; chr2index['-'] = 1; chr2index['*'] = 2; chr2index['/'] = 3; chr2index['('] = 5; chr2index[')'] = 6; chr2index['\0'] = 7; } int stackpos = 1; int stack[256]; double values[256]; stack[0]=0; int accept = 18; static int left[10]={11,8,8,8,8,9,9,9,10,10}; //production left side static int plen[10]={1,3,2,3,1,3,3,1,1,3}; //production size static int table[18][12] = { {0, 4, 0, 0, 5, 6, 0, 0, 1, 2, 3, 0}, {7, 8, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0}, {-4, -4, 9, 10, 0, 0, -4, -4, 0, 0, 0, 0}, {-7, -7, -7, -7, 0, 0, -7, -7, 0, 0, 0, 0}, {0, 0, 0, 0, 5, 6, 0, 0, 0, 11, 3, 0}, {-8, -8, -8, -8, 0, 0, -8, -8, 0, 0, 0, 0}, {0, 4, 0, 0, 5, 6, 0, 0, 12, 2, 3, 0}, {0, 0, 0, 0, 5, 6, 0, 0, 0, 13, 3, 0}, {0, 0, 0, 0, 5, 6, 0, 0, 0, 14, 3, 0}, {0, 0, 0, 0, 5, 6, 0, 0, 0, 0, 15, 0}, {0, 0, 0, 0, 5, 6, 0, 0, 0, 0, 16, 0}, {-2, -2, 9, 10, 0, 0, -2, -2, 0, 0, 0, 0}, {7, 8, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0}, {-1, -1, 9, 10, 0, 0, -1, -1, 0, 0, 0, 0}, {-3, -3, 9, 10, 0, 0, -3, -3, 0, 0, 0, 0}, {-5, -5, -5, -5, 0, 0, -5, -5, 0, 0, 0, 0}, {-6, -6, -6, -6, 0, 0, -6, -6, 0, 0, 0, 0}, {-9, -9, -9, -9, 0, 0, -9, -9, 0, 0, 0, 0}}; const char*p = s; while(1) { const char*pnext = p+1; int action; double value; if(!stackpos) { fprintf(stderr, "Error in expression\n"); return 0.0; } if(chr2index[*p]<0) { action = table[stack[stackpos-1]][4]; if(action>0) { while(chr2index[*pnext]<0) pnext++; value = atof(p); } } else { action = table[stack[stackpos-1]][chr2index[*p]]; } if(action == accept) { return values[stack[stackpos-1]]; } else if(action>0) { // shift if(stackpos>254) { fprintf(stderr, "Stack overflow while parsing expression\n"); return 0.0; } values[stackpos]=value; stack[stackpos++]=action; p=pnext; } else if(action<0) { // reduce stackpos-=plen[-action]; stack[stackpos] = table[stack[stackpos-1]][left[-action]]; switch(-action) { case 1: values[stackpos] = values[stackpos+0] + values[stackpos+2]; break; case 2: values[stackpos] = 0 - values[stackpos+1]; break; case 3: values[stackpos] = values[stackpos+0] - values[stackpos+2]; break; case 5: values[stackpos] = values[stackpos+0] * values[stackpos+2]; break; case 6: values[stackpos] = values[stackpos+0] / values[stackpos+2]; break; case 9: values[stackpos] = values[stackpos+1]; break; } stackpos++; } else { fprintf(stderr, "Syntax error in expression\n"); return 0.0; } } }