|
(つづきです)
/* ---------------- 構文木からNFAを作る ----------------- */
typedef struct Transition {
int input;
int to;
struct Transition *next;
} Transition;
typedef struct {
Transition **q;
int num;
} FA;
int make_fa(FA *fa, int start, Tree *t, int goal)
{
if (t == 0 || t->left == 0 && t->right == 0) {
Transition *trans = my_malloc(sizeof *trans);
trans->input = (t == 0 || t->c == EMPTY) ? EPS : t->c;
trans->to = goal;
trans->next = fa->q[start];
fa->q[start] = trans;
return trans->input == EPS;
}
switch (t->c) {
int new, r1, r2;
case CONCAT:
new = fa->num++;
r1 = make_fa(fa, start, t->left, new);
r2 = make_fa(fa, new, t->right, goal);
return r1 && r2;
case UNION:
r1 = make_fa(fa, start, t->right, goal);
r2 = make_fa(fa, start, t->left, goal);
return r1 || r2;
case CLOSURE:
make_fa(fa, start, 0, goal);
new = fa->num++;
if (make_fa(fa, start, t->left, new))
error("不正な '*' のオペランド");
make_fa(fa, new, 0, start);
return 1;
default:
assert(0);
}
}
FA *tree_to_fa(Tree *t)
{
int i; FA *fa = my_malloc(sizeof *fa);
fa->q = malloc(sizeof(*fa->q) * 1024);
for (i = 0; i < 1024; i++) fa->q[i] = 0;
fa->num = 2;
make_fa(fa, 0, t, 1);
return fa;
}
/* ---- 有限オートマトンを使ってパターンマッチを行う ---- */
char *do_match(const FA *fa, char *p, int state)
{
Transition *t; char *rt;
if (state == 1) return p;
for (t = fa->q[state]; t; t = t->next)
if (t->input == EPS || t->input == *p)
if (rt = do_match(fa, t->input == EPS ? p : p + 1, t->to))
return rt;
return 0;
}
char *match(const FA *fa, char line[], char **begin, char **end)
{
int i;
for (i = 0; i < (int)strlen(line); i++)
if (*end = do_match(fa, line + i, 0))
return *begin = line + i, *end;
return 0;
}
/* ------------ 構文木、状態遷移表の表示 ---------------- */
void print_tree_sub(Tree *t, int level)
{
if (t == 0) return;
printf("%*s", level * 2, "");
switch (t->c) {
case UNION: putchar('|'); break;
case CLOSURE: putchar('*'); break;
case CONCAT: putchar('+'); break;
case EMPTY: printf("EMPTY"); break;
default: putchar(t->c); break;
}
putchar('\n');
print_tree_sub(t->left, level + 1);
print_tree_sub(t->right, level + 1);
}
void print_tree(Tree *t)
{
printf("------ 構文木 ------\n");
print_tree_sub(t, 0);
}
void print_fa(FA *fa)
{
int i; Transition *p;
printf("---- 状態遷移表 ----\n");
printf(" ");
for (i = 0; i < fa->num; i++)
printf("%d", i % 10);
putchar('\n');
for (i = 0; i < fa->num; i++) {
char s[70+1]; sprintf(s, "%*s", 70, "");
for (p = fa->q[i]; p; p = p->next)
if (s[p->to] != ' ')
s[p->to] = '@';
else if (p->input == EPS)
s[p->to] = '?';
else
s[p->to] = p->input;
printf("%2d%s\n", i, s);
}
}
/* -------------------- ドライバ ------------------------ */
int main(int argc, char **argv)
{
char line[1024], *begin, *end; Tree *tree; FA *fa; FILE *fp = stdin;
if (argc < 2)
error("usage: program_name RE [infile]");
if (argc == 3 && (fp = fopen(argv[2], "r")) == 0)
error("cannot open the file");
/* 正規表現を構文解析して構文木を作る */
tree = re_to_tree(argv[1]);
/* 構文木からNFAを作る */
fa = tree_to_fa(tree);
/* 構文木と状態遷移表を表示 */
if (0) {
print_tree(tree);
print_fa(fa);
return 0;
}
/* 入力行に対してパターンマッチを試みる */
while (fgets(line, sizeof line, fp))
if (match(fa, line, &begin, &end)) {
if (argc == 2) {
printf("%.*s", begin - line, line);
printf("[これがマッチ→]");
printf("%.*s", end - begin, begin);
printf("[←これがマッチ]");
printf("%s", end);
} else
printf("%s", line);
}
return 0;
}
(おわり)
|