编译原理课程设计(四)

以下是全流程步骤:

1. 创建项目目录:

在你选择的位置创建一个新目录,例如 SimpleCompiler

mkdir SimpleCompiler
cd SimpleCompiler

2. 创建 Lex 文件:

在项目目录中创建 lex.l 文件,将下面的内容复制到文件中。

%{
#include "main.h"
#include "yacc.tab.h"
extern "C" {
int yylval;
}
%}

%%
[ \t\n] ; // Skip whitespace
[a-zA-Z][a-zA-Z0-9]* {
yylval = strdup(yytext);
return IDENTIFIER;
}
:= return ASSIGN;
[0-9]+ {
yylval = atoi(yytext);
return INTEGER;
}
\; return SEMICOLON;
\. return PERIOD;
. ;
%%

3. 创建 Yacc 文件:

在项目目录中创建 yacc.y 文件,将下面的内容复制到文件中。

   %{
#include "main.h"
#include <iostream>
#include <vector>

std::vector<std::string> variables; // 保存变量信息

extern "C" {
int yylex();
void yyerror(const char* s);
}

%union {
int intval;
char* strval;
}

%token <intval> INTEGER
%token <strval> IDENTIFIER
%token ASSIGN SEMICOLON PERIOD

%start program

%%

program: block PERIOD {
printf("Compilation successful!\n");
exit(0);
}

block: BEGIN statement_list END {
printf("Executing program...\n");
}

statement_list: statement {
printf("Statement executed\n");
}
| statement_list SEMICOLON statement {
printf("Statement executed\n");
}

statement: assignment {
printf("Assignment statement\n");
}

assignment: IDENTIFIER ASSIGN expression {
// 生成赋值代码
printf("%s = %d;\n", $1, $3);
}

expression: INTEGER {
$$ = $1;
}
| IDENTIFIER {
// 在表达式中使用变量,保存变量信息
variables.push_back($1);
$$ = lookup_variable($1);
}

%%

int lookup_variable(const char* var) {
// Dummy implementation for variable lookup
printf("Looking up variable %s\n", var);
return 0;
}

int main() {
printf("Simple Pascal Compiler\n");
yyparse();

// 打印变量信息
printf("Variables used in the program:\n");
for (const std::string& var : variables) {
printf("%s\n", var.c_str());
}

return 0;
}

4. 创建主文件:

在项目目录中创建 main.cpp 文件,将下面的内容复制到文件中。

#include <cstdio>
#include "main.h"
extern "C" {
int yylex();
int yyparse();
}

int main() {
printf("Simple Pascal Compiler\n");
yyparse();
return 0;
}

5. 创建头文件:

在项目目录中创建 main.h 文件,将下面的内容复制到文件中。

#ifndef MAIN_HPP
#define MAIN_HPP

#include <cstdlib>

#define YYSTYPE Type

struct Type {
int intval;
char* strval;
};

#endif

6. 创建 CMakeLists.txt 文件:

在项目目录中创建 CMakeLists.txt 文件,将下面的内容复制到文件中。

cmake_minimum_required(VERSION 3.10)

project(SimpleCompiler)

# Find Flex and Bison
find_package(FLEX REQUIRED)
find_package(BISON REQUIRED)

# Generate Lex and Yacc files
FLEX_TARGET(MyScanner lex.l ${CMAKE_CURRENT_BINARY_DIR}/lex.yy.c)
BISON_TARGET(MyParser yacc.y ${CMAKE_CURRENT_BINARY_DIR}/y.tab.c)

# Add Flex and Bison output files to the project
ADD_FLEX_BISON_DEPENDENCY(MyScanner MyParser)

# Include directories
include_directories(${CMAKE_CURRENT_BINARY_DIR})

# Create executable
add_executable(simple_compiler main.cpp ${FLEX_MyScanner_OUTPUTS} ${BISON_MyParser_OUTPUTS})

7. 构建项目:

打开终端,进入项目目录,然后运行以下命令构建项目。

mkdir build
cd build
cmake ..
make

这将在 build 文件夹中生成一个名为 simple_compiler 的可执行文件。

8. 运行编译器:

在终端中,你可以使用以下命令运行生成的编译器,并将 Pascal 代码作为输入。

./simple_compiler

编译器会提示 “Simple Pascal Compiler”,然后等待输入。你可以输入Pascal代码并按Ctrl+D结束输入。

请注意,由于我们的示例编译器没有实际的代码生成,它只输出一些信息以演示流程。在实际编译器中,你需要更多的规则来覆盖Pascal语言的其他方面,并生成实际的目标代码。