Parsing 如何创建应用De Morgan的语法';用yacc把s定理转化为一个表达式?
我想使用yacc和lex应用于输入 输入可以是任何表达式,如a+b、!(A+B)等:Parsing 如何创建应用De Morgan的语法';用yacc把s定理转化为一个表达式?,parsing,grammar,yacc,lex,Parsing,Grammar,Yacc,Lex,我想使用yacc和lex应用于输入 输入可以是任何表达式,如a+b、!(A+B)等: 表达式a+b的结果应该是!A.∙!b 表情!(a+b)应导致a+b 我认为lex部分已经完成了,但是我对将法律应用到表达式所需的yacc语法有困难 我试图实现的是以下算法。将下列方程视为输入:y= a+b 应用德摩根定律后,它变成:!Y=!(A+B) 最后,展开括号应该会导致!Y=!A.∙!B 此处为lex代码: %{ #include <stdio.h> #include "y.tab.h"
- 表达式a+b的结果应该是!A.∙!b
- 表情!(a+b)应导致a+b
%{
#include <stdio.h>
#include "y.tab.h"
extern int yylval;
int yywrap (void);
%}
%%
[a-zA-Z]+ {yylval = *yytext; return ALPHABET;}
"&&" return AND;
"||" return OR;
"=" return ('=');
[\t] ;
\n return 0;
. return yytext[0];
"0exit" return 0;
%%
int yywrap (void)
{
return 1;
}
%{
#包括
#包括“y.tab.h”
外部国际组织;
int-yywrap(无效);
%}
%%
[a-zA-Z]+{yylval=*yytext;返回字母表;}
“&&”返回并返回;
“| |”返回或;
“=”返回(“=”);
[\t];
\n返回0;
. 返回文本[0];
“0退出”返回0;
%%
int-yywrap(无效)
{
返回1;
}
这是我的yacc代码:
%{
#include <stdio.h>
int yylex (void);
void yyerror (char *);
extern FILE* yyin;
%}
%token ALPHABET
%left '+''*'
%right '=' '!' NOT
%left AND OR
%start check
%%
check : expr {printf("%s\n",$$);}
;
expr : plus
|plus '+' plus {$$ = $1 + $3;}
;
plus : times
|times '*' times {$$ = $1 * $3;}
;
times : and_op
|and_op AND and_op{$$ = $1 && $3;}
;
and_op : or_op
|or_op OR or_op {$$ = $1 || $3;}
;
or_op : not_op
|'!' not_op {$$ = !$2;}
;
not_op : paren
|'(' paren ')' {$$ = $2;}
;
paren :
|ALPHABET {$$ = $1;}
;
/*
E: E '+' E {$$ = $1 + $3;}
|E '*' E {$$ = $1 * $3;}
|E '=' E {$$ = $1 = $3;}
|E AND E {$$ = ($1 && $3);}
|E OR E {$$ = ($1 || $3);}
|'(' E ')' {$$ = $2;}
|'!' E %prec NOT {$$ = !$2;}
|ALPHABET {$$ = $1;}
;*/
%%
int main()
{
char filename[30];
char * line = NULL;
size_t len = 0;
printf("\nEnter filename\n");
scanf("%s",filename);
FILE *fp = fopen(filename, "r");
if(fp == NULL)
{
fprintf(stderr,"Can't read file %s\n",filename);
exit(EXIT_FAILURE);
}
yyin = fp;
// while (getline(&line, &len, fp) != -1)
// {
// printf("%s",line);
// }
// printf("Enter the expression:\n");
do
{
yyparse();
}while(!feof(yyin));
return 0;
}
%{
#包括
int yylex(无效);
无效错误(字符*);
外部文件*yyin;
%}
%符号字母表
%左'+''*'
%对“=”不
%左或右
%开始检查
%%
检查:expr{printf(“%s\n”,$$);}
;
expr:加上
|加上“+”加上{$$=$1+$3;}
;
加:次
|时间'*'时间{$$=$1*$3;}
;
泰晤士报:还有
|和_op和_op{$$=$1&&$3;}
;
和_op:或_op
|或_op或_op{$=$1 | |$3;}
;
或_op:不_op
|'!' 不是{$$=!$2;}
;
不,帕伦
|“('paren')”{$$=$2;}
;
帕伦:
|字母表{$$=$1;}
;
/*
E:E'+'E{$$=$1+$3;}
|E'*'E{$$=$1*$3;}
|E'='E{$$=$1=$3;}
|E和E{$$=($1&&$3);}
|或{$$=($1 | |$3)}
|“('E')”{$$=$2;}
|'!' E%prec不是{$$=!$2;}
|字母表{$$=$1;}
;*/
%%
int main()
{
字符文件名[30];
char*line=NULL;
尺寸长度=0;
printf(“\n输入文件名\n”);
scanf(“%s”,文件名);
FILE*fp=fopen(文件名,“r”);
如果(fp==NULL)
{
fprintf(stderr,“无法读取文件%s\n”,文件名);
退出(退出失败);
}
yyin=fp;
//while(getline(&line,&len,fp)!=-1)
// {
//printf(“%s”,第行);
// }
//printf(“输入表达式:\n”);
做
{
yyparse();
}而(!feof(yyin));
返回0;
}
您正在尝试建立一个计算机代数系统
您的任务在概念上很简单:
a*(b + !a) => a*(b)
当被解析的实际术语看起来像:
q*(a + b + c + ... !q ... + z)
查看树的“简单”过程代码现在必须在子树上任意向下走,以找到规则可以应用的位置。突然之间,编码匹配逻辑就不那么容易了,树粉碎也不能实现这种效果
如果我们忽略关联和交换问题,对于复杂的匹配和修改,代码可能会有点笨拙,难以阅读;一旦你做到了,这将是显而易见的。如果你只想做一次或多次的分解,你可以通过编码相对容易地完成。如果你想实现大量的布尔代数规则来简化,这将是一件痛苦的事情。理想情况下,您希望使用与布尔逻辑相同的表示法来表示逻辑规则,以便它们易于表示,但现在您需要能够读取和解释逻辑规则的东西。这是一段复杂的代码,但如果操作正确,您可以编写如下逻辑规则:
rule deMorgan_for_or(t1:boolexp, t2:boolexp):boolexp->boolexp
" ! (\t1 + \t2) " -> " !\t1 * !\t2 ";
一个相关的问题(步骤5)是,您希望在哪里应用逻辑规则?仅仅因为你可以在一个非常大的逻辑术语中在15个地方应用德摩根定律,并不意味着你一定要这么做。所以在某些地方,你需要有一个控制机制来决定你的许多规则中的哪一条应该适用,以及它们应该适用于哪里。这让你进入元编程,一个全新的话题
如果你的规则是“单调的”,也就是说,它们实际上只能应用一次,你只需在任何地方运行它们,并得到一个终止计算,如果单调的答案是你想要的。如果您有相反的规则(例如!(x+y)=>!x*!y和!a*!b=>!(a+b)),那么您的规则可能会永远重复运行