首页 > 解决方案 > 从伪 C 语言到伪汇编语言的简单 lex/yacc 转换器

问题描述

不得不重复问题才能提供答案

我想使用 YACC/LEX (c++) 从 mini C 到 NASM ( 程序集) 进行某种翻译程序应该接收部分代码并在 NASM 程序集中返回包含该部分的文件

mini C 应该支持这样的代码

a = v1;
b = v2;
while(condition){
    // Some expressions +
}
if(Condition){ //
// Some expressions + 
else{
// Some expressions +
}

它应该识别正 int 值,只有简单的表达式 + ,if/else 和 while 循环条件 {<,>,==} 我知道如何使用 flex 进行词法分析部分,但解析器对我来说很麻烦,尤其是解析 while 循环和 if /别的。

那些 if/else 和 while 部分可以有 begin/end 而不是 {}

我想语法应该是这样的

Program: Block '.' 
;

Block : BEGIN_TOKEN Lines END_TOKEN
;

Lines: Lines ';' Line
| Line
;

Line: INT_TOKEN ID_TOKEN '=' NUM_TOKEN
| IF_TOKEN '(' Condition ')' Block ELSE Block
| WHILE_TOKEN '(' Condition ')' Block
| E
;

E: E + E
| ID_TOKEN
| NUM_TOKEN
;

Conditon: E '<' E
| E '>' E
| E EQ_TOKEN E
;

条件很简单,比如 a<5 , b>c , d==3... 它不需要任何类型的打印和扫描 动作应该写在单独的 c++ 文件中

标签: c++assemblycompiler-constructionyacclex

解决方案


因为我的最后一个问题被关闭了,因为有人虽然我正在写书,所以我想分享我对这个问题的解决方案。这个问题是我的作业。

词法分析器

%option noyywrap
%option nounput
%option noinput

%{
    
    #include <iostream>
    #include <cstdlib>
    
    using namespace std;
    
    #include "parser.tab.hpp"
    
%}

%%

while           {return WHILE_TOKEN;}
if              {return IF_TOKEN;}
else            {return ELSE_TOKEN;}
print           {return PRINT_TOKEN;}
"=="            {return EQ_TOKEN;}
"<="            {return LEQ_TOKEN;}
">="            {return GEQ_TOKEN;}
[-+(){}<>=;]    {return *yytext;}
[a-z]           {yylval.s = new string(yytext); return ID_TOKEN;}
(0|[1-9][0-9]*) {yylval.s = new stirng(yytext); return NUM_TOKEN;}
[ \t\n]         {}
.               {cerr<<"Lex error:  "<< *yytext << endl; exit(EXIT_FAILURE);}
%%

解析器.ypp

%{

#include <ostream>
#include <fstream>
#include <cstdlib>
#include <string>


using namespace std;

void yyerror(string s){
    cerr << s << endl;
    exit(EXIT_FAILURE);
}

extern int yylex();

ofstream out;

int next_label = 0;

%}

%union{
    string *s;
    int v;
}

%nonassoc IF_THEN
%nonassoc ELSE_TOKEN

%right '='
%left '<' '>' EQ_TOKEN LEQ_TOKEN GEQ_TOKEN
%left '+' '-'

%type<s> ID_TOKEN NUM_TOKEN
%type<v> WHILE_TOKEN IF_TOKEN ELSE_TOKEN
%token PRINT_TOKEN EQ_TOKEN LEQ_TOKEN GEQ_TOKEN WHILE_TOKEN ELSE_TOKEN IF_TOKEN ID_TOKEN NUM_TOKEN

%%

Program: Statements {out << "" << endl;}
;

Statements: Statements Statement {}
|
;

Statement: ';'
| E ';'
| '{' Statements '}'
| ID_TOKEN '=' E ';' {out << "assign_val" << endl;}
| PRINT_TOKEN '(' E ')' {out << "print" << endl;}
| WHILE_TOKEN {$1 = next_label; out << "L:" << $1 << ":" << endl; next_label+=2;} '(' E ')' {out << "L" << $1 +1 << ":" << endl;} Statement
| IF_TOKEN '(' E ')' {$1 = next_label++; out << "L" << $1 << ":" << endl;} Statement Else
;

Else: ELSE_TOKEN {$1 = next_label++; out << "jmp L" << $1 << ":" << endl;} Statement {out << "L" << $1 << ":" << endl;}
| %prec IF_THEN {}
;

E: E '+' E {out << "add" << endl;}
| E '-' E {out << "sub" << endl;}
| E '<' E {out << "compL" << endl;}
| E '>' E {out << "compG" << endl;}
| E EQ_TOKEN E {out << "compEQ" << endl;}
| E LEQ_TOKEN E {out << "compLEQ" << endl;}
| E GEQ_TOKEN E {out << "compGEQ" << endl;}
| '(' E ')'
| ID_TOKEN {out << *$1 << endl;}
| NUM_TOKEN {out << *$1 << endl;}
;

%%

int main(){
    out.open("output.s", ios_base::app);
    yyparse();
    return 0;
}

生成文件

program: parser.tab.o lex.yy.o
    g++ -Wall -o $@ $^
parser.tab.o: parser.tab.cpp parser.tab.hpp
    g++ -Wall -c -o $@ $<
lext.yy.o: lex.yy.c
    g++ -Wall -c -o $@ $<
lex.yy.c: lexer.l parser.tab.hpp
    flex $<
parser.tab.cpp parser.tab.hpp: parser.ypp
    bison -d -v $<

在终端中找到包含源文件的目录,然后运行​​make命令


推荐阅读