Loops flex和bison项目
我使用了flex和bison来制作词法分析器和语法分析器。这项工作完成了!我的意思是,当我把一个文件和我写的程序放在一起时,我可以看到程序是否有错误。如果没有,我可以根据我使用的语法在屏幕上看到整个程序。我在这方面没有问题 现在,我想使用循环处理和循环展开。我应该换哪一部分?词法分析器?解析器?还是解析器后面的main?怎么做?导言 由于我们看不到您的代码片段来了解您如何在解析器中处理循环并输出代码,以及您可能希望展开的特定循环的示例,因此很难给出比已经给出的更详细的建议。全球任何地方都不可能有比那些已经阅读您的问题的人更有经验的编译器作者或教师!因此,我们需要探索其他方法来解释如何解决这样的问题 经常发生的情况是,人们无法发布代码示例,因为他们从作为类练习的一部分或从开源存储库提供的重要代码库开始,并且他们不完全理解如何找到合适的代码片段进行发布。让我们想象一下,您拥有一个真正语言的工作编译器的完整源代码,并希望向现有的工作编译器添加一些循环优化,然后您可能会说,“什么源代码,我如何显示一些源代码?”(因为实际上它有成千上万行代码) 示例编译器 如果没有一些代码可供参考,另一种方法是创建一个示例来解释问题和解决方案。在编译器教科书或编译器类中通常是这样做的。我将使用一个类似的简单示例来演示如何使用flex和bison工具实现此类优化 首先,我们需要定义示例的语言。为了使答案保持在合理的大小限制之内,语言必须非常简单。我将使用简单的表达式赋值作为我的语言中唯一的语句形式。这种语言中的变量是单字母,常量是正整数。唯一的表达式运算符是plus(Loops flex和bison项目,loops,bison,flex-lexer,ebnf,Loops,Bison,Flex Lexer,Ebnf,我使用了flex和bison来制作词法分析器和语法分析器。这项工作完成了!我的意思是,当我把一个文件和我写的程序放在一起时,我可以看到程序是否有错误。如果没有,我可以根据我使用的语法在屏幕上看到整个程序。我在这方面没有问题 现在,我想使用循环处理和循环展开。我应该换哪一部分?词法分析器?解析器?还是解析器后面的main?怎么做?导言 由于我们看不到您的代码片段来了解您如何在解析器中处理循环并输出代码,以及您可能希望展开的特定循环的示例,因此很难给出比已经给出的更详细的建议。全球任何地方都不可能有
+
)。我的语言中的示例程序可能是:
i = j + k; j = 1 + 2
编译器生成的输出代码将是单个累加器机器的简单汇编程序,具有四条指令,LDA
、STO
、ADD
和STP
。为上述语句生成的代码为:
LDA j
ADD k
STO i
LDA #1
ADD #2
STO j
STP
如果LDA
将值或变量加载到累加器中,ADD
将变量或值添加到累加器中,STO
将累加器存储回变量中<代码>STP是程序结束时的“停止”
flex程序
上面显示的语言需要标识ID和数字,并且应该跳过空白。以下几点就足够了:
%{
#define yyterminate() return (END);
%}
digit [0-9]
id [a-z]
ws [\t\n\r ]
%%
{ws}+ /* Skip whitespace */
{digit}+ {yylval = (int)(0l - atol(yytext)); return(NUMBER); }
{id} {yylval = yytext[0]; return(ID); }
"+" {return('+'); }
"=" {return('='); }
血淋淋的细节只是一些关于如何工作的注释。我使用了
atol
来转换整数,以便处理读取MAXINT时可能出现的整数溢出。我对常数求反,这样就可以很容易地将它们与一个字节内为正的标识符区分开来。我存储单字符标识符是为了避免说明符号表代码的负担,从而允许使用非常小的lexer、解析器和代码生成器
野牛计划
要解析语言并从bison操作生成一些代码,我们可以通过以下bison程序实现这一点:
%{
#include <stdio.h>
%}
%token NUMBER ID END
%%
program : statements END { printf("STP\n"); return(0) ; }
;
statements : statement
| statements ';' statement
;
statement : ID '=' expression { printf("STO %c\n",$1); }
|
;
expression : operand {
/* Load operand into accumulator */
if ($1 <= 0)
printf("LDA #%d\n",(int)0l-$1);
else printf("LDA %c\n",$1);
}
| expression '+' operand {
/* Add operand to accumulator */
if ($3 <= 0)
printf("ADD #%d\n",(int)0l-$3);
else printf("ADD %c\n",$3);
}
;
operand : NUMBER
| ID
;
%%
#include "lex.yy.c"
优化方法是将其视为:
i = 3
因此,1+2
的添加是由编译器完成的,而不是放在生成的代码中,以便在运行时发生。我们预计会产生以下结果:
LDA #3
STO i
改进的代码生成器
我们可以通过寻找在表达式“+”操作数的两侧都有一个数字的显式情况来实现改进的代码。为此,我们必须延迟对表达式:操作数
执行任何操作,以允许值向前传播。由于表达式
的值可能未被计算,我们可能必须在赋值和加法时进行计算,这会导致if
语句的轻微爆炸。我们只需要更改规则语句
和表达式
的操作,如下所示:
statement : ID '=' expression {
/* Check for constant expression */
if ($3 <= 0) printf("LDA #%d\n",(int)0l-$3);
else
/* Check if expression in accumulator */
if ($3 != 'A') printf("LDA %c\n",$3);
/* Now store accumulator */
printf("STO %c\n",$1);
}
| /* empty statement */
;
expression : operand { $$ = $1 ; }
| expression '+' operand {
/* First check for constant expression */
if ( ($1 <= 0) && ($3 <= 0)) $$ = $1 + $3 ;
else { /* No constant folding */
/* See if $1 already in accumulator */
if ($1 != 'A')
/* Load operand $1 into accumulator */
if ($1 <= 0)
printf("LDA #%d\n",(int)0l-$1);
else printf("LDA %c\n",$1);
/* Add operand $3 to accumulator */
if ($3 <= 0)
printf("ADD #%d\n",(int)0l-$3);
else printf("ADD %c\n",$3);
$$ = 'A'; /* Note accumulator result */
}
}
;
应导致:
LDA j
INC
STO i
最终代码生成器
要更改为n+1
生成的代码,我们只需要重新编码表达式
语义的一部分,只需测试在不折叠常量时,要使用的常量是否为1
(在本例中为否定)。结果代码变为:
expression : operand { $$ = $1 ; }
| expression '+' operand {
/* First check for constant expression */
if ( ($1 <= 0) && ($3 <= 0)) $$ = $1 + $3 ;
else { /* No constant folding */
/* Check for special case of constant 1 on LHS */
if ($1 == -1) {
/* Swap LHS/RHS to permit INC usage */
$1 = $3;
$3 = -1;
}
/* See if $1 already in accumulator */
if ($1 != 'A')
/* Load operand $1 into accumulator */
if ($1 <= 0)
printf("LDA #%d\n",(int)0l-$1);
else printf("LDA %c\n",$1);
/* Add operand $3 to accumulator */
if ($3 <= 0)
/* test if ADD or INC */
if ($3 == -1) printf("INC\n");
else printf("ADD #%d\n",(int)0l-$3);
else printf("ADD %c\n",$3);
$$ = 'A'; /* Note accumulator result */
}
}
;
表达式:操作数{$$=$1;}
|表达式“+”操作数{
/*首先检查常量表达式*/
如果(($1欢迎使用StackOverflow。是的,我们可以提供帮助,但我们需要查看您所做的一些代码才能提供帮助。根据代码,解释您需要帮助的内容。这里的每个人都可以这样做,但我们不了解您到目前为止做了什么,理解了多少,以及您遇到了什么困难。您需要更加详细和明确。否则答案只有一个词是的,我们可以提供帮助,但这不是你想要的答案。你的最后两个问题也很模糊。你需要学习如何提问。我编辑了我的问题。我如何向你展示代码?抱歉。我无法理解这不是聊天板。Flex和bison用于解析。如果你想在解析后进行程序转换,请yOU应该在解析之后执行它们。您可以增量地执行它们(在解析PAR后调用BISY代码中的转换例程)。
LDA j
INC
STO i
expression : operand { $$ = $1 ; }
| expression '+' operand {
/* First check for constant expression */
if ( ($1 <= 0) && ($3 <= 0)) $$ = $1 + $3 ;
else { /* No constant folding */
/* Check for special case of constant 1 on LHS */
if ($1 == -1) {
/* Swap LHS/RHS to permit INC usage */
$1 = $3;
$3 = -1;
}
/* See if $1 already in accumulator */
if ($1 != 'A')
/* Load operand $1 into accumulator */
if ($1 <= 0)
printf("LDA #%d\n",(int)0l-$1);
else printf("LDA %c\n",$1);
/* Add operand $3 to accumulator */
if ($3 <= 0)
/* test if ADD or INC */
if ($3 == -1) printf("INC\n");
else printf("ADD #%d\n",(int)0l-$3);
else printf("ADD %c\n",$3);
$$ = 'A'; /* Note accumulator result */
}
}
;