Есть такой проект -- re2c. Генерирует из заданного описания прямой C-код ДКА (без таблиц) для разбора регулярных выражений с высокой скоростью. Я ему ради интереса задал регулярное выражение требующее разбора одного из 28 токенов. На выходе получил автомат с 74 состояниями. Да, полученный автомат "вообще не использует памяти". Кроме переменной своего состояния. 74 состояния в один байт уместятся. Но такой код вручную написать практически невозможно. И боюсь, re2c на порядок превосходит описываемые ранее поделки. И самое главное -- в реальном проекте число состояний будет уже слишком велико. Попробую простенький парсер ини задать в виде регулярного выражения.
Пример:
char *lex(char *input)
{
/*!re2c
("ONE" | "TWO" | "THREE" | "FOUR" | "FIVE" | "SIX" | "SEVEN"
| "EIGHT" | "NINE" | "TEN" | "ELEVEN" | "TWELWE"
| "THIRTEEN" | "FOURTEEN" | "FIFTEEN" | "SIXTEEN"
| "SEVENTEEN" | "EIGHTEEN" | "NINETEEN" | "TWENTY"
| "THIRTY" | "FORTY" | "FIFTY" | "SIXTY" | "SEVENTY"
| "EIGHTY" | "NINETY" | "HUNDRED")
{ return 1; }
*/
}
И результат:
/* Generated by re2c 0.13.5 on Wed Mar 14 18:45:24 2012 */
#line 1 "re2c.c"
char *lex(char *input)
{
#line 8 "<stdout>"
{
YYCTYPE yych;
if ((YYLIMIT - YYCURSOR) < 9) YYFILL(9);
yych = *YYCURSOR;
switch (yych) {
case 'E': goto yy7;
case 'F': goto yy5;
case 'H': goto yy9;
case 'N': goto yy8;
case 'O': goto yy3;
case 'S': goto yy6;
case 'T': goto yy4;
default: goto yy2;
}
yy2:
YYCURSOR = YYMARKER;
goto yy16;
yy3:
yych = *++YYCURSOR;
switch (yych) {
case 'N': goto yy74;
default: goto yy2;
}
yy4:
yych = *++YYCURSOR;
switch (yych) {
case 'E': goto yy61;
case 'H': goto yy59;
case 'W': goto yy60;
default: goto yy2;
}
yy5:
yych = *++YYCURSOR;
switch (yych) {
case 'I': goto yy45;
case 'O': goto yy46;
default: goto yy2;
}
yy6:
yych = *++YYCURSOR;
switch (yych) {
case 'E': goto yy33;
case 'I': goto yy34;
default: goto yy2;
}
yy7:
yych = *++YYCURSOR;
switch (yych) {
case 'I': goto yy23;
case 'L': goto yy24;
default: goto yy2;
}
yy8:
yych = *++YYCURSOR;
switch (yych) {
case 'I': goto yy17;
default: goto yy2;
}
yy9:
yych = *++YYCURSOR;
switch (yych) {
case 'U': goto yy10;
default: goto yy2;
}
yy10:
yych = *++YYCURSOR;
switch (yych) {
case 'N': goto yy11;
default: goto yy2;
}
yy11:
yych = *++YYCURSOR;
switch (yych) {
case 'D': goto yy12;
default: goto yy2;
}
yy12:
yych = *++YYCURSOR;
switch (yych) {
case 'R': goto yy13;
default: goto yy2;
}
yy13:
yych = *++YYCURSOR;
switch (yych) {
case 'E': goto yy14;
default: goto yy2;
}
yy14:
yych = *++YYCURSOR;
switch (yych) {
case 'D': goto yy15;
default: goto yy2;
}
yy15:
++YYCURSOR;
yy16:
#line 11 "re2c.c"
{ return 1; }
#line 109 "<stdout>"
yy17:
yych = *++YYCURSOR;
switch (yych) {
case 'N': goto yy18;
default: goto yy2;
}
yy18:
yych = *++YYCURSOR;
switch (yych) {
case 'E': goto yy19;
default: goto yy2;
}
yy19:
yych = *(YYMARKER = ++YYCURSOR);
switch (yych) {
case 'T': goto yy20;
default: goto yy16;
}
yy20:
yych = *++YYCURSOR;
switch (yych) {
case 'E': goto yy21;
case 'Y': goto yy15;
default: goto yy2;
}
yy21:
yych = *++YYCURSOR;
switch (yych) {
case 'E': goto yy22;
default: goto yy2;
}
yy22:
yych = *++YYCURSOR;
switch (yych) {
case 'N': goto yy15;
default: goto yy2;
}
yy23:
yych = *++YYCURSOR;
switch (yych) {
case 'G': goto yy28;
default: goto yy2;
}
yy24:
yych = *++YYCURSOR;
switch (yych) {
case 'E': goto yy25;
default: goto yy2;
}
yy25:
yych = *++YYCURSOR;
switch (yych) {
case 'V': goto yy26;
default: goto yy2;
}
yy26:
yych = *++YYCURSOR;
switch (yych) {
case 'E': goto yy27;
default: goto yy2;
}
yy27:
yych = *++YYCURSOR;
switch (yych) {
case 'N': goto yy15;
default: goto yy2;
}
yy28:
yych = *++YYCURSOR;
switch (yych) {
case 'H': goto yy29;
default: goto yy2;
}
yy29:
yych = *++YYCURSOR;
switch (yych) {
case 'T': goto yy30;
default: goto yy2;
}
yy30:
yych = *(YYMARKER = ++YYCURSOR);
switch (yych) {
case 'E': goto yy31;
case 'Y': goto yy15;
default: goto yy16;
}
yy31:
yych = *++YYCURSOR;
switch (yych) {
case 'E': goto yy32;
default: goto yy2;
}
yy32:
yych = *++YYCURSOR;
switch (yych) {
case 'N': goto yy15;
default: goto yy2;
}
yy33:
yych = *++YYCURSOR;
switch (yych) {
case 'V': goto yy39;
default: goto yy2;
}
yy34:
yych = *++YYCURSOR;
switch (yych) {
case 'X': goto yy35;
default: goto yy2;
}
yy35:
yych = *(YYMARKER = ++YYCURSOR);
switch (yych) {
case 'T': goto yy36;
default: goto yy16;
}
yy36:
yych = *++YYCURSOR;
switch (yych) {
case 'E': goto yy37;
case 'Y': goto yy15;
default: goto yy2;
}
yy37:
yych = *++YYCURSOR;
switch (yych) {
case 'E': goto yy38;
default: goto yy2;
}
yy38:
yych = *++YYCURSOR;
switch (yych) {
case 'N': goto yy15;
default: goto yy2;
}
yy39:
yych = *++YYCURSOR;
switch (yych) {
case 'E': goto yy40;
default: goto yy2;
}
yy40:
yych = *++YYCURSOR;
switch (yych) {
case 'N': goto yy41;
default: goto yy2;
}
yy41:
yych = *(YYMARKER = ++YYCURSOR);
switch (yych) {
case 'T': goto yy42;
default: goto yy16;
}
yy42:
yych = *++YYCURSOR;
switch (yych) {
case 'E': goto yy43;
case 'Y': goto yy15;
default: goto yy2;
}
yy43:
yych = *++YYCURSOR;
switch (yych) {
case 'E': goto yy44;
default: goto yy2;
}
yy44:
yych = *++YYCURSOR;
switch (yych) {
case 'N': goto yy15;
default: goto yy2;
}
yy45:
yych = *++YYCURSOR;
switch (yych) {
case 'F': goto yy55;
case 'V': goto yy54;
default: goto yy2;
}
yy46:
yych = *++YYCURSOR;
switch (yych) {
case 'R': goto yy48;
case 'U': goto yy47;
default: goto yy2;
}
yy47:
yych = *++YYCURSOR;
switch (yych) {
case 'R': goto yy50;
default: goto yy2;
}
yy48:
yych = *++YYCURSOR;
switch (yych) {
case 'T': goto yy49;
default: goto yy2;
}
yy49:
yych = *++YYCURSOR;
switch (yych) {
case 'Y': goto yy15;
default: goto yy2;
}
yy50:
yych = *(YYMARKER = ++YYCURSOR);
switch (yych) {
case 'T': goto yy51;
default: goto yy16;
}
yy51:
yych = *++YYCURSOR;
switch (yych) {
case 'E': goto yy52;
default: goto yy2;
}
yy52:
yych = *++YYCURSOR;
switch (yych) {
case 'E': goto yy53;
default: goto yy2;
}
yy53:
yych = *++YYCURSOR;
switch (yych) {
case 'N': goto yy15;
default: goto yy2;
}
yy54:
yych = *++YYCURSOR;
switch (yych) {
case 'E': goto yy15;
default: goto yy2;
}
yy55:
yych = *++YYCURSOR;
switch (yych) {
case 'T': goto yy56;
default: goto yy2;
}
yy56:
yych = *++YYCURSOR;
switch (yych) {
case 'E': goto yy57;
case 'Y': goto yy15;
default: goto yy2;
}
yy57:
yych = *++YYCURSOR;
switch (yych) {
case 'E': goto yy58;
default: goto yy2;
}
yy58:
yych = *++YYCURSOR;
switch (yych) {
case 'N': goto yy15;
default: goto yy2;
}
yy59:
yych = *++YYCURSOR;
switch (yych) {
case 'I': goto yy68;
case 'R': goto yy67;
default: goto yy2;
}
yy60:
yych = *++YYCURSOR;
switch (yych) {
case 'E': goto yy62;
case 'O': goto yy15;
default: goto yy2;
}
yy61:
yych = *++YYCURSOR;
switch (yych) {
case 'N': goto yy15;
default: goto yy2;
}
yy62:
yych = *++YYCURSOR;
switch (yych) {
case 'L': goto yy64;
case 'N': goto yy63;
default: goto yy2;
}
yy63:
yych = *++YYCURSOR;
switch (yych) {
case 'T': goto yy66;
default: goto yy2;
}
yy64:
yych = *++YYCURSOR;
switch (yych) {
case 'W': goto yy65;
default: goto yy2;
}
yy65:
yych = *++YYCURSOR;
switch (yych) {
case 'E': goto yy15;
default: goto yy2;
}
yy66:
yych = *++YYCURSOR;
switch (yych) {
case 'Y': goto yy15;
default: goto yy2;
}
yy67:
yych = *++YYCURSOR;
switch (yych) {
case 'E': goto yy73;
default: goto yy2;
}
yy68:
yych = *++YYCURSOR;
switch (yych) {
case 'R': goto yy69;
default: goto yy2;
}
yy69:
yych = *++YYCURSOR;
switch (yych) {
case 'T': goto yy70;
default: goto yy2;
}
yy70:
yych = *++YYCURSOR;
switch (yych) {
case 'E': goto yy71;
case 'Y': goto yy15;
default: goto yy2;
}
yy71:
yych = *++YYCURSOR;
switch (yych) {
case 'E': goto yy72;
default: goto yy2;
}
yy72:
yych = *++YYCURSOR;
switch (yych) {
case 'N': goto yy15;
default: goto yy2;
}
yy73:
yych = *++YYCURSOR;
switch (yych) {
case 'E': goto yy15;
default: goto yy2;
}
yy74:
++YYCURSOR;
switch ((yych = *YYCURSOR)) {
case 'E': goto yy15;
default: goto yy2;
}
}
#line 12 "re2c.c"
}
[ZX]