山东大学编译原理实验(新)

你需要完成一个简单的C++风格的编译器。这个实验分为若干部分。在这个部分中,你需要完成该编译器的词法分析器。

你的编译器不应当对用户输入程序进行假设(例如,假设用户输入的程序不超过若干字节,或每行不超过若干字符,或程序不超过若干符号)。

给定一个C++语言源程序,你需要将其从字符流转换为词语流。具体来说,你需要过滤源程序中的空白符(空格,注释、tab,回车、换行等),识别关键字、标识符、数字以及运算符。

输入为一段C++语言风格的源程序,输出每个单词所对应的类型。

若程序没有词法错误,输出为单词流以及每个单词的类型,每个单词以及类型占一行。

若程序有词法错误,直接输出相应的错误。一段源代码内同时有多个词法错误的,只输出最早出现的那个错误类型。

输出的最后应该有换行。

错误有以下四种:

错误描述输出内容
浮点数中不止一个小数点Malformed number: More than one decimal point in a floating point number.
小数点在浮点数的开始或者结尾Malformed number: Decimal point at the beginning or end of a floating point number.
整数或小数的整数部分中有前导零Malformed number: Leading zeros in an integer.
非注释部分有不能识别的字符,包括单独出现一次的&,| 字符Unrecognizable characters.

前三种数字错误类型的输出优先级为1》2》3

例如如果出现 1.11. 这种情况,按照第一种错误类型报错。

关键字表如下

关键字对应类型
intINTSYM
doubleDOUBLESYM
scanfSCANFSYM
printfPRINTFSYM
ifIFSYM
thenTHENSYM
whileWHILESYM
doDOSYM

符号表如下

符号对应类型
=AO
==RO
>RO
>=RO
<RO
<=RO
||LO
&&LO
!LO
!=RO
+PLUS
-MINUS
*TIMES
/DIVISION
,COMMA
(BRACE
)BRACE
{BRACE
}BRACE
;SEMICOLON

标识符以及数字

标识符应符合如下文法:

<标识符> → <字母>{<字母>|<数字>}

{}:出现0次或多次

标识符或者数字对应类型
标识符(如x)IDENT
整数(如3)INT
小数(如2.1)DOUBLE

对于注释,与C++类似,有两种方式,如下表所示:

//单行注释
/* */多行注释

假如只有/* 而没有匹配的 */,则认为从 /*往后的内容都是注释。

在词法分析中,注释的内容不应输出,即需要将这些内容过滤掉。

示例1

输入:

int a, b;

double c=1.2; // This is a comment

scanf(a);

scanf(b);

printf©;

输出:

int INTSYM

a IDENT

, COMMA

b IDENT

; SEMICOLON

double DOUBLESYM

c IDENT

= AO

1.2 DOUBLE

; SEMICOLON

scanf SCANFSYM

( BRACE

a IDENT

) BRACE

; SEMICOLON

scanf SCANFSYM

( BRACE

b IDENT

) BRACE

; SEMICOLON

printf PRINTFSYM

( BRACE

c IDENT

) BRACE

; SEMICOLON

示例2:

输入:

int a = 6037210

int b = 06356417

输出:

Malformed number: Leading zeros in an integer.

示例3:

输入:

12910
1223.219
27912.120921
2181123.
2810.
12123

输出:

Malformed number: Decimal point at the beginning or end of a floating point number.

示例4:

输入:

int a,b;
c=2;
d=123.21;
?
*
~

输出:

Unrecognizable characters.

示例5:

输入:

12738
0.2919
.0199
1210
1.111
1.201
10291.1290

输出:

Malformed number: Decimal point at the beginning or end of a floating point number.

示例6:

输入:

1234
2222222
1928301
1.87273
0.9218
3.12919
1.0291
1.1.112182
21211

输出:

Malformed number: More than one decimal point in a floating point number.

/*
    wirte by @lyz
    2024.4.26
    编译原理实验1:词法分析器
*/
#include <bits/stdc++.h>

#define LOCAL 0

std::map<std::string, std::string> mp{
    {"int", "INTSYM"},       {"double", "DOUBLESYM"}, {"scanf", "SCANFSYM"},
    {"printf", "PRINTFSYM"}, {"if", "IFSYM"},         {"then", "THENSYM"},
    {"while", "WHILESYM"},   {"do", "DOSYM"}};
std::map<std::string, std::string> mp1{
    {"=", "AO"},    {"==", "RO"},      {">", "RO"},    {">=", "RO"},
    {"<", "RO"},    {"<=", "RO"},      {"||", "LO"},   {"&&", "LO"},
    {"!", "LO"},    {"!=", "RO"},      {"+", "PLUS"},  {"-", "MINUS"},
    {"*", "TIMES"}, {"/", "DIVISION"}, {",", "COMMA"}, {"(", "BRACE"},
    {")", "BRACE"}, {"{", "BRACE"},    {"}", "BRACE"}, {";", "SEMICOLON"}};

std::vector<std::string> lexer(std::string str) {
    std::vector<std::string> ans;
    std::string s;

    // 去注释
    while (str.find("/*") != -1) {
        int pos = str.find("/*");
        int pos1 = str.find("*/");
        if (pos1 == -1) {
            str.erase(pos);
        }
        str.erase(pos, pos1 - pos + 2);
    }
    while (str.find("//") != -1) {
        int pos = str.find("//");
        int pos1 = str.find("\n", pos);
        str.erase(pos, pos1 - pos + 1);
    }

    // 加空格
    int n = str.size();
    for (int i = 0; i < n; i++) {
        if (i + 2 <= n && mp1.count(str.substr(i, 2))) {
            s.push_back(' ');
            s.push_back(str[i]);
            s.push_back(str[i + 1]);
            s.push_back(' ');
            i += 1;
        } else if (i + 1 <= n && mp1.count(str.substr(i, 1))) {
            s.push_back(' ');
            s.push_back(str[i]);
            s.push_back(' ');
        } else {
            s.push_back(str[i]);
        }
    }
    str = s;
    n = str.size();
    // 分词//
    std::string token;
    for (int i = 0; i < n; i++) {
        if (str[i] == ' ' || str[i] == '\n' || str[i] == '\t') {
            if (!token.empty()) {
                if (mp.count(token)) {
                    ans.push_back(token + ' ' + mp[token] + '\n');
                } else {
                    int idx = 0;
                    bool alp = 0;
                    bool dig = 0;
                    std::string h;
                    ///
                    while (idx < token.size()) {
                        while (isalpha(token[idx])) {
                            h += token[idx++];
                            alp = true;
                        }
                        while (isdigit(token[idx]) && alp) {
                            h += token[idx++];
                        }
                        if (!h.empty()) {
                            ans.push_back(h + " IDENT\n");
                        }
                        h.clear();
                        /
                        while (isdigit(token[idx]) || token[idx] == '.') {
                            h += token[idx++];
                            dig = 1;
                        }
                        if (dig && std::count(h.begin(), h.end(), '.') >= 2) {
                            std::cout << "Malformed number: More than one decimal point in a "
                                      "floating point number.\n";
                            return {};
                        }
                        if (dig && (h[0] == '.' || h.back() == '.')) {
                            std::cout << "Malformed number: Decimal point at the beginning "
                                      "or end of a floating point number.\n";
                            return {};
                        }
                        if (dig && h[0] == '0' && h.size() > 1) {
                            bool isok = 1;
                            if (h.find('.') != -1) {
                                for (int j = 0; j < h.size(); j++) {
                                    if (h[j] == '.') {
                                        break;
                                    }
                                    if (h[j] != '0') {
                                        isok = 0;
                                        break;
                                    }
                                }
                            } else {
                                isok = 0;
                            }
                            if (!isok) {
                                std::cout << "Malformed number: Leading zeros in an integer.\n";
                                return{};
                            }
                        }
                        if (dig && std::count(h.begin(), h.end(), '.') == 0) {
                            ans.push_back(h + ' ' + "INT\n");
                        } else if (dig) {
                            ans.push_back(h + " DOUBLE\n");
                        }
                        /
                        if (idx + 2 <= token.size() && mp1.count(token.substr(idx, 2))) {
                            ans.push_back(token.substr(idx, 2) + " " +
                                          mp1[token.substr(idx, 2)] + "\n");
                            idx += 2;
                        } else if (mp1.count(token.substr(idx, 1))) {
                            ans.push_back(token.substr(idx, 1) + " " +
                                          mp1[token.substr(idx, 1)] + "\n");
                            idx += 1;
                        }

                        if (idx < token.size() &&
                                (!isdigit(token[idx]) && !isalpha(token[idx])) &&
                                (dig == 0 && alp == 0)) {
                            std::cout << "Unrecognizable characters.\n";
                            return {};
                        }
                    }
                }
            }

            token = "";
        } else {
            token += str[i];
        }
    }

    return ans;
}

void solve() {
    std::string s, str;
    std::string last;

    // 输入流 
    std::ifstream input("C:\\Users\\LYZ\\Desktop\\untitled1\\in2.txt");
    std::ofstream fout("C:\\Users\\LYZ\\Desktop\\untitled1\\out.txt");
    if (LOCAL) {
        if (input.is_open()) {
            while (getline(input, s)) {
                str += s;
                str += '\n';
            }
            input.close();
        } else {
            std::cout << "Failed to open input file." << std::endl;
            return;
        }
    } else
        while (getline(std::cin, s)) {
            str += s;
            str += '\n';
        }

    auto ans = lexer(str);
    if (ans.empty()) return;
    // 输出流
    if (LOCAL)
        for (auto s : ans) {
            fout << s;
        }
    else
        for (auto s : ans) {
            std::cout << s;
        }
}


int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    std::cout.tie(nullptr);

    int t = 1;

    while (t--) {
        solve();
    }
    return 0;
}
山东大学编译原理实验C是指山东大学计算机科学与技术专业的编译原理实践课程中,学生需要使用C语言进行编写的实验项目。编译原理是计算机科学中的重要基础课程,主要研究如何将源代码转换为可执行的程序。在这门课程中,学生将学习如何设计和实现编译器,了解编译过程中的词法分析、语法分析、语义分析、中间代码生成等关键技术。 在山东大学编译原理实验C中,学生将通过编写C语言程序,实现这些编译器的各个模块。通过实验,学生能够深入理解编译器的工作原理和实现过程,加深对编译原理的理解。实验内容可能包括编写词法分析器,实现对源代码的词法分析和生成记号流;编写语法分析器,实现对记号流的语法分析和生成抽象语法树;编写语义分析器,对生成的抽象语法树进行语义检查和类型推导等。 在实验过程中,学生需要掌握C语言的基本语法和相关的数据结构,熟悉编程环境和工具,如gcc编译器、调试工具等。同时,学生需要学习和理解编译原理中的相关理论知识,如正则表达式、文法、自动机等,以便能够正确地进行实验设计和实现。 通过山东大学编译原理实验C,学生能够加深对编译原理的理解,并提升编程和软件设计的能力。这门实践课程为学生今后从事编译器设计和开发、编程语言实现等相关领域的研究提供了坚实的基础。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

咕噜咕噜咕噜128

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值