├── .gitignore ├── LICENSE ├── README.md ├── 第一次实验 └── 编译原理第一次实验 │ ├── 文档文件夹 │ └── 编译原理实验一.pdf │ └── 源程序文件夹 │ └── lexer │ ├── Xmapping.json │ ├── json.qrc │ ├── lexer.pro │ ├── lexer.pro.user │ ├── lexerwindow.cpp │ ├── lexerwindow.h │ ├── lexerwindow.ui │ ├── main.cpp │ └── mapping.json ├── 第三次实验 └── lab3 │ └── 编译原理实验三 │ ├── 文档文件夹 │ └── 编译原理实验三.pdf │ └── 源代码文件夹 │ ├── tinySyntaxTree.zip │ └── tinySyntaxTree │ ├── main.cpp │ ├── mainwindow.cpp │ ├── mainwindow.h │ ├── mainwindow.ui │ ├── mapping.json │ ├── resource.qrc │ ├── tinySyntaxTree.pro │ ├── tinySyntaxTree.pro.user │ ├── utils.cpp │ └── utils.h ├── 第二次实验 ├── build-regex2dfa-Desktop_Qt_5_12_12_MinGW_32_bit-Debug │ ├── .qmake.stash │ ├── Makefile │ ├── Makefile.Debug │ ├── Makefile.Release │ ├── debug │ │ ├── moc_codedialog.cpp │ │ ├── moc_mainwindow.cpp │ │ └── moc_predefs.h │ ├── ui_codedialog.h │ └── ui_mainwindow.h ├── regex2dfa │ ├── codedialog.cpp │ ├── codedialog.h │ ├── codedialog.ui │ ├── dfa.cpp │ ├── dfa.h │ ├── main.cpp │ ├── mainwindow.cpp │ ├── mainwindow.h │ ├── mainwindow.ui │ ├── nfa.cpp │ ├── nfa.h │ ├── regex2dfa.pro │ ├── regex2dfa.pro.user │ ├── regex2dfa.zip │ ├── utils.cpp │ └── utils.h ├── 编译原理实验二.zip └── 编译原理实验二 │ ├── 文档文件夹 │ └── 编译原理实验二.pdf │ └── 源代码文件夹 │ └── regex2dfa │ ├── codedialog.cpp │ ├── codedialog.h │ ├── codedialog.ui │ ├── dfa.cpp │ ├── dfa.h │ ├── main.cpp │ ├── mainwindow.cpp │ ├── mainwindow.h │ ├── mainwindow.ui │ ├── nfa.cpp │ ├── nfa.h │ ├── regex2dfa.pro │ ├── regex2dfa.pro.user │ ├── utils.cpp │ └── utils.h └── 第四次实验 └── 编译原理实验四 ├── 文档文件夹 └── 编译原理实验四.pdf └── 源程序文件夹 ├── LALR.pro ├── LALR.pro.user ├── lalr.cpp ├── lalr.h ├── main.cpp ├── mainwindow.cpp ├── mainwindow.h └── mainwindow.ui /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | *.smod 22 | 23 | # Compiled Static libraries 24 | *.lai 25 | *.la 26 | *.a 27 | *.lib 28 | 29 | # Executables 30 | *.exe 31 | *.out 32 | *.app 33 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Linzexun 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Compiler_Design_SCNU 2 | 2022级华南师范大学编译原理实验 3 | 4 | 一共有四个实验: 5 | 6 | 1. C++单词拼装分类器 7 | 2. XLEX生成器(正则表达式->NFA->DFA->最小化) 8 | 3. Tiny语言扩充语法分析(递归子程序) 9 | 4. LALR(1)语法分析生成器 10 | 11 | -------------------------------------------------------------------------------- /第一次实验/编译原理第一次实验/文档文件夹/编译原理实验一.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WA-automat/Compiler_Design_SCNU/0f3e92c521e9b785ae8af9784feade5078582a6f/第一次实验/编译原理第一次实验/文档文件夹/编译原理实验一.pdf -------------------------------------------------------------------------------- /第一次实验/编译原理第一次实验/源程序文件夹/lexer/Xmapping.json: -------------------------------------------------------------------------------- 1 | { 2 | "(": "SEPARATOR", 3 | ")": "SEPARATOR", 4 | "{": "SEPARATOR", 5 | "}": "SEPARATOR", 6 | "[": "SEPARATOR", 7 | "]": "SEPARATOR", 8 | "@": "SEPARATOR", 9 | ".": "SEPARATOR", 10 | "any": "KEYWORD", 11 | "bool": "KEYWORD", 12 | "character": "KEYWORD", 13 | "integer": "KEYWORD", 14 | "float": "KEYWORD", 15 | "double": "KEYWORD", 16 | "signed": "KEYWORD", 17 | "unsigned": "KEYWORD", 18 | "False": "KEYWORD", 19 | "True": "KEYWORD", 20 | "enum": "KEYWORD", 21 | "union": "KEYWORD", 22 | "struct": "KEYWORD", 23 | "class": "KEYWORD", 24 | "wchar_t": "KEYWORD", 25 | "sizeof": "KEYWORD", 26 | "typeid": "KEYWORD", 27 | "typedef": "KEYWORD", 28 | "static": "KEYWORD", 29 | "public": "KEYWORD", 30 | "protected": "KEYWORD", 31 | "private": "KEYWORD", 32 | "virtual": "KEYWORD", 33 | "override": "KEYWORD", 34 | "final": "KEYWORD", 35 | "operator": "KEYWORD", 36 | "const": "KEYWORD", 37 | "constexpr": "KEYWORD", 38 | "using": "KEYWORD", 39 | "namespace": "KEYWORD", 40 | "inline": "KEYWORD", 41 | "new": "KEYWORD", 42 | "delete": "KEYWORD", 43 | "this": "KEYWORD", 44 | "nullptr": "KEYWORD", 45 | "void": "KEYWORD", 46 | "friend": "KEYWORD", 47 | "template": "KEYWORD", 48 | "if": "KEYWORD", 49 | "else": "KEYWORD", 50 | "foreach": "KEYWORD", 51 | "do": "KEYWORD", 52 | "switch": "KEYWORD", 53 | "case": "KEYWORD", 54 | "default": "KEYWORD", 55 | "end": "KEYWORD", 56 | "restart": "KEYWORD", 57 | "jump": "KEYWORD", 58 | "and": "KEYWORD", 59 | "not": "KEYWORD", 60 | "or": "KEYWORD", 61 | "xor": "KEYWORD", 62 | "return": "KEYWORD", 63 | "try": "KEYWORD", 64 | "catch": "KEYWORD", 65 | "throw": "KEYWORD", 66 | "noexcept": "KEYWORD", 67 | "static_cast": "KEYWORD", 68 | "const_cast": "KEYWORD", 69 | "dynamic_cast": "KEYWORD", 70 | "reinterpret_cast": "KEYWORD", 71 | "static_assert": "KEYWORD", 72 | "register": "KEYWORD", 73 | "explicit": "KEYWORD", 74 | "extern": "KEYWORD", 75 | "import": "KEYWORD", 76 | "define": "KEYWORD", 77 | "ifdef": "KEYWORD", 78 | "ifndef": "KEYWORD", 79 | "elif": "KEYWORD", 80 | "endif": "KEYWORD", 81 | "pragma": "KEYWORD", 82 | "&&": "OPERATOR", 83 | "||": "OPERATOR", 84 | "!": "OPERATOR", 85 | "+": "OPERATOR", 86 | "-": "OPERATOR", 87 | "*": "OPERATOR", 88 | "/": "OPERATOR", 89 | "%": "OPERATOR", 90 | "++": "OPERATOR", 91 | "--": "OPERATOR", 92 | "&": "OPERATOR", 93 | "|": "OPERATOR", 94 | "^": "OPERATOR", 95 | "~": "OPERATOR", 96 | "<<": "OPERATOR", 97 | ">>": "OPERATOR", 98 | "=": "OPERATOR", 99 | "+=": "OPERATOR", 100 | "-=": "OPERATOR", 101 | "*=": "OPERATOR", 102 | "/=": "OPERATOR", 103 | "%=": "OPERATOR", 104 | "&=": "OPERATOR", 105 | "^=": "OPERATOR", 106 | "|=": "OPERATOR", 107 | "==": "OPERATOR", 108 | "!=": "OPERATOR", 109 | ">": "OPERATOR", 110 | "<": "OPERATOR", 111 | ">=": "OPERATOR", 112 | "<=": "OPERATOR", 113 | ",": "OPERATOR", 114 | ".": "OPERATOR", 115 | "->": "OPERATOR", 116 | "::": "OPERATOR", 117 | "?": "OPERATOR", 118 | ":": "OPERATOR" 119 | } 120 | -------------------------------------------------------------------------------- /第一次实验/编译原理第一次实验/源程序文件夹/lexer/json.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | mapping.json 4 | Xmapping.json 5 | 6 | 7 | -------------------------------------------------------------------------------- /第一次实验/编译原理第一次实验/源程序文件夹/lexer/lexer.pro: -------------------------------------------------------------------------------- 1 | QT += core gui 2 | 3 | greaterThan(QT_MAJOR_VERSION, 4): QT += widgets 4 | 5 | CONFIG += c++11 6 | 7 | # You can make your code fail to compile if it uses deprecated APIs. 8 | # In order to do so, uncomment the following line. 9 | #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 10 | 11 | SOURCES += \ 12 | main.cpp \ 13 | lexerwindow.cpp 14 | 15 | HEADERS += \ 16 | lexerwindow.h 17 | 18 | FORMS += \ 19 | lexerwindow.ui 20 | 21 | # Default rules for deployment. 22 | qnx: target.path = /tmp/$${TARGET}/bin 23 | else: unix:!android: target.path = /opt/$${TARGET}/bin 24 | !isEmpty(target.path): INSTALLS += target 25 | 26 | RESOURCES += \ 27 | json.qrc 28 | -------------------------------------------------------------------------------- /第一次实验/编译原理第一次实验/源程序文件夹/lexer/lexerwindow.cpp: -------------------------------------------------------------------------------- 1 | #include "lexerwindow.h" 2 | #include "ui_lexerwindow.h" 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | LexerWindow::LexerWindow(QWidget *parent) 15 | : QMainWindow(parent) 16 | , ui(new Ui::LexerWindow) 17 | { 18 | ui->setupUi(this); 19 | 20 | // 基本布局信息 21 | this->setWindowTitle("编译原理实验一:分词器"); 22 | QScreen *screen = QGuiApplication::primaryScreen(); 23 | QRect screenGeometry = screen->geometry(); 24 | int screenWidth = screenGeometry.width(); 25 | int screenHeight = screenGeometry.height(); 26 | int newWidth = screenWidth * 0.64; 27 | int newHeight = screenHeight * 0.48; 28 | this->resize(newWidth, newHeight); 29 | ui->pushButton->setFixedHeight(200); 30 | ui->xPushButton->setFixedHeight(200); 31 | ui->uploadButton->setFixedHeight(200); 32 | 33 | // 设置表格窗口 34 | ui->tableWidget->setColumnCount(2); 35 | ui->tableWidget->setHorizontalHeaderLabels(QStringList() << "token" << "类型"); 36 | ui->tableWidget->setColumnWidth(0, newWidth / 4); 37 | ui->tableWidget->horizontalHeader()->setStretchLastSection(true); // 最后一列自适应宽度 38 | ui->tableWidget->setEditTriggers(QAbstractItemView::NoEditTriggers); 39 | 40 | // 判断分词类型的变量 41 | int type = 1; 42 | 43 | // 按钮事件: 打开某文件获取其中的所有文本 44 | connect(ui->uploadButton, &QPushButton::clicked, this, [&]() { 45 | type = 1; 46 | QString fileName = QFileDialog::getOpenFileName(this, "选择C++文件"); 47 | if (!fileName.isEmpty()) { 48 | QFile file(fileName); 49 | if (file.open(QIODevice::ReadOnly | QIODevice::Text)) { 50 | QTextStream in(&file); 51 | in.setCodec("UTF-8"); // 设置编码格式为 UTF-8 52 | ui->fileBrowser->setText(in.readAll()); 53 | file.close(); 54 | } 55 | } 56 | }); 57 | connect(ui->xPushButton, &QPushButton::clicked, this, [&]() { 58 | type = 2; 59 | QString fileName = QFileDialog::getOpenFileName(this, "选择XC++文件"); 60 | if (!fileName.isEmpty()) { 61 | QFile file(fileName); 62 | if (file.open(QIODevice::ReadOnly | QIODevice::Text)) { 63 | QTextStream in(&file); 64 | in.setCodec("UTF-8"); // 设置编码格式为 UTF-8 65 | ui->fileBrowser->setText(in.readAll()); 66 | file.close(); 67 | } 68 | } 69 | }); 70 | 71 | // 按钮事件:分词 72 | connect(ui->pushButton, &QPushButton::clicked, this, [&]() { 73 | QString text = ui->fileBrowser->toPlainText(); 74 | QVector> list = LexerWindow::lexer(text, type); 75 | ui->tableWidget->setRowCount(list.size()); 76 | for (int i = 0; i < list.size(); i++) { 77 | ui->tableWidget->setItem(i, 0, new QTableWidgetItem(list[i].first)); 78 | ui->tableWidget->setItem(i, 1, new QTableWidgetItem(list[i].second)); 79 | } 80 | for (int row = 0; row < ui->tableWidget->rowCount(); ++row) { 81 | QTableWidgetItem *item = ui->tableWidget->item(row, 1); 82 | if (item) item->setTextAlignment(Qt::AlignCenter); 83 | } 84 | ui->tableWidget->show(); 85 | }); 86 | 87 | } 88 | 89 | LexerWindow::~LexerWindow() 90 | { 91 | delete ui; 92 | } 93 | 94 | QVector> LexerWindow::lexer(QString content, int type) 95 | { 96 | /* 97 | * 功能:将文本字符串content分词 98 | * 类别:关键词、运算符、数字类型、标识符,注释,分界符号 99 | * 返回:键值对序列(词:类型) 100 | */ 101 | 102 | // 读取json文件:关键字,运算符,边界符号等 103 | QString mappingPath; 104 | if (type == 1) { 105 | mappingPath = ":/json/mapping.json"; 106 | } else { 107 | mappingPath = ":/json/Xmapping.json"; 108 | } 109 | 110 | qDebug() << mappingPath << endl; 111 | 112 | QFile file(mappingPath); 113 | QHash hash; 114 | if (file.open(QIODevice::ReadOnly | QIODevice::Text)) { 115 | QByteArray data = file.readAll(); 116 | QJsonDocument jsonDocument = QJsonDocument::fromJson(data); 117 | 118 | if (!jsonDocument.isNull()) { 119 | QJsonObject jsonObject = jsonDocument.object(); 120 | 121 | // 遍历 JSON 对象的所有键值对,并添加到哈希表中 122 | for (auto it = jsonObject.begin(); it != jsonObject.end(); ++it) { 123 | QString key = it.key(); 124 | QString value = it.value().toString(); 125 | hash.insert(key, value); 126 | qDebug() << key << ' ' << value << endl; 127 | } 128 | } 129 | } 130 | 131 | // 开始分词 132 | QVector> tokenList(0); 133 | QStringList lines = content.split("\n"); 134 | for (int index = 0; index < lines.size(); index++) { 135 | const QString& line = lines[index]; 136 | int pos = 0; 137 | int len = line.size(); 138 | 139 | // 跳过空格与tab 140 | while (pos < len && (line[pos] == ' ' || line[pos] == '\t')) pos++; 141 | if (pos == len) continue; 142 | 143 | // 单行注释 144 | if (line[pos] == '/' && line[pos + 1] == '/') { 145 | tokenList.append(qMakePair(line.mid(pos), QString("注释"))); 146 | continue; 147 | } 148 | 149 | // 遍历单行 150 | while (pos < len) { 151 | // qDebug() << index << ' ' << pos; 152 | if (hash.contains(line[pos]) && hash[line[pos]] == "SEPARATOR") { 153 | // 分隔符 154 | tokenList.append(qMakePair(QString(line[pos++]), QString("分界符号"))); 155 | } else if (pos != len && (line[pos] == '\"' || line[pos] == '\'')) { 156 | // 字符串或字符 157 | int endIndex = line.indexOf(line[pos], pos + 1); 158 | if (endIndex != -1) { 159 | while (endIndex != -1 && line[endIndex - 1] == '\\') endIndex = line.indexOf(line[pos], endIndex + 1); 160 | if (endIndex == -1) { 161 | break; 162 | } 163 | QString str = line.mid(pos, endIndex - pos + 1); 164 | tokenList.append(qMakePair(str, line[pos] == '\"' ? QString("字符串") : QString("字符"))); 165 | pos = endIndex + 1; 166 | } else { 167 | break; 168 | } 169 | } else if (line[pos].isDigit()) { 170 | // 数字类型 171 | QString number; 172 | // 读取前置数字 173 | while (pos < len && (line[pos].isDigit())) number += line[pos++]; 174 | 175 | if (line[pos] == 'x') { 176 | number += line[pos++]; 177 | while (pos < len && (line[pos].isDigit() || (line[pos].toLower() >= 'a' && line[pos].toLower() <= 'f'))) number += line[pos++]; 178 | tokenList.append(qMakePair(number, QString("十六进制整数"))); 179 | } else if (line[pos] == 'b') { 180 | number += line[pos++]; 181 | while (pos < len && (line[pos] == '0' || line[pos] == '1')) number += line[pos++]; 182 | tokenList.append(qMakePair(number, QString("二进制整数"))); 183 | } else if (pos < len && (line[pos].toLower() == 'e' || line[pos] == '.')) { 184 | number += line[pos++]; 185 | while (pos < len && (line[pos].isDigit())) number += line[pos++]; 186 | tokenList.append(qMakePair(number, QString("浮点数"))); 187 | } else { 188 | if (number[0] == '0') { 189 | bool isOctal = true; 190 | for (int i = 1; i < number.size(); i++) { 191 | if (number[i] < '0' || number[i] > '8') { 192 | isOctal = false; 193 | break; 194 | } 195 | } 196 | if (isOctal) { 197 | tokenList.append(qMakePair(number, QString("八进制整数"))); 198 | } else { 199 | tokenList.append(qMakePair(number, QString("整数"))); 200 | } 201 | } else { 202 | tokenList.append(qMakePair(number, QString("整数"))); 203 | } 204 | } 205 | } else if (line[pos].isLetter() || line[pos] == '_') { 206 | // 标识符、关键字类型 207 | QString identifier; 208 | while (pos < len && (line[pos].isLetter() || line[pos] == '_' || line[pos].isDigit())) identifier += line[pos++]; 209 | 210 | if (hash.contains(identifier) && hash[identifier] == "KEYWORD") { 211 | // 捕获指针类型 212 | if (LexerWindow::isType(identifier)) { 213 | while (pos < len && (line[pos] == ' ' || line[pos] == "*")) { 214 | if (line[pos] == ' ') pos++; 215 | else identifier += line[pos++]; 216 | } 217 | } 218 | tokenList.append(qMakePair(identifier, QString("关键字"))); 219 | if (identifier == "include" || identifier == "import") { 220 | if (line.indexOf('<', pos) != -1) { 221 | int beginHeaderIndex = line.indexOf('<', pos); 222 | int endHeaderIndex = line.indexOf('>', pos); 223 | tokenList.append(qMakePair(line.mid(beginHeaderIndex, endHeaderIndex - beginHeaderIndex + 1), QString("头文件"))); 224 | pos = endHeaderIndex + 1; 225 | } else { 226 | int beginHeaderIndex = line.indexOf('\"', pos); 227 | int endHeaderIndex = line.indexOf('\"', beginHeaderIndex + 1); 228 | tokenList.append(qMakePair(line.mid(beginHeaderIndex, endHeaderIndex - beginHeaderIndex + 1), QString("头文件"))); 229 | pos = endHeaderIndex + 1; 230 | } 231 | } 232 | } else { 233 | tokenList.append(qMakePair(identifier, QString("标识符"))); 234 | } 235 | } else if (hash.contains(line[pos]) && hash[line[pos]] == "OPERATOR") { 236 | // 运算符 237 | QString op; 238 | if (line[pos] == '/') { 239 | // 判断是否为注释 240 | if (pos != len && (line[pos + 1] == '/' || line[pos + 1] == '*')) { 241 | if (line[pos + 1] == '/') { 242 | tokenList.append(qMakePair(line.mid(pos), QString("注释"))); 243 | break; 244 | } else { 245 | int endStar = line.indexOf('*', pos + 2); 246 | // 找第一行 247 | while (endStar != -1 && endStar < len - 1) { 248 | if (line[endStar + 1] == '/') { 249 | tokenList.append(qMakePair(line.mid(pos, endStar + 2 - pos), QString("注释"))); 250 | pos = endStar + 2; 251 | break; 252 | } 253 | endStar = line.indexOf('*', endStar + 1); 254 | } 255 | if (endStar == -1 || endStar == len - 1) { 256 | tokenList.append(qMakePair(line.mid(pos), QString("注释"))); 257 | // 接下来继续找 258 | while (index + 1 < lines.size()) { 259 | bool flag = true; 260 | index++; 261 | QString newLine = lines[index]; 262 | len = newLine.size(); 263 | pos = 0; 264 | 265 | // 跳过空格与tab 266 | while (pos < len && (newLine[pos] == ' ' || newLine[pos] == '\t')) pos++; 267 | if (pos == len) continue; 268 | 269 | endStar = newLine.indexOf('*', pos); 270 | while (endStar != -1 && endStar < len - 1) { 271 | if (newLine[endStar + 1] == '/') { 272 | tokenList.append(qMakePair(newLine.mid(pos, endStar + 2 - pos), QString("注释"))); 273 | pos = endStar + 2; 274 | flag = false; 275 | break; 276 | } 277 | endStar = newLine.indexOf('*', endStar + 1); 278 | } 279 | if (endStar == -1 || endStar == len - 1) { 280 | tokenList.append(qMakePair(newLine.mid(pos), QString("注释"))); 281 | } 282 | if (!flag) break; 283 | } 284 | } 285 | } 286 | } else { 287 | op += line[pos++]; 288 | tokenList.append(qMakePair(op, QString("运算符"))); 289 | } 290 | } else { 291 | while (pos < len && (hash.contains(line[pos]) && hash[line[pos]] == "OPERATOR")) op += line[pos++]; 292 | tokenList.append(qMakePair(op, QString("运算符"))); 293 | } 294 | } else { 295 | pos++; 296 | } 297 | } 298 | } 299 | 300 | return tokenList; 301 | } 302 | 303 | bool LexerWindow::isType(QString s) 304 | { 305 | if (s == "int" || s == "short" || s == "long" || s == "bool" || s == "char" || 306 | s == "void" || s == "float" || s == "double" || s == "signed" || s == "unsigned" || s == "auto") { 307 | return true; 308 | } 309 | return false; 310 | } 311 | -------------------------------------------------------------------------------- /第一次实验/编译原理第一次实验/源程序文件夹/lexer/lexerwindow.h: -------------------------------------------------------------------------------- 1 | #ifndef LEXERWINDOW_H 2 | #define LEXERWINDOW_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | QT_BEGIN_NAMESPACE 10 | namespace Ui { class LexerWindow; } 11 | QT_END_NAMESPACE 12 | 13 | class LexerWindow : public QMainWindow 14 | { 15 | Q_OBJECT 16 | 17 | public: 18 | LexerWindow(QWidget *parent = nullptr); 19 | ~LexerWindow(); 20 | 21 | private: 22 | 23 | // 工具函数,用于分词 24 | static QVector> lexer(QString content, int type); 25 | static bool isType(QString s); 26 | 27 | Ui::LexerWindow *ui; 28 | }; 29 | #endif // LEXERWINDOW_H 30 | -------------------------------------------------------------------------------- /第一次实验/编译原理第一次实验/源程序文件夹/lexer/lexerwindow.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | LexerWindow 4 | 5 | 6 | 7 | 0 8 | 0 9 | 1301 10 | 643 11 | 12 | 13 | 14 | LexerWindow 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | Qt::Horizontal 25 | 26 | 27 | QSizePolicy::Fixed 28 | 29 | 30 | 31 | 40 32 | 20 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 上传cpp文件 44 | 45 | 46 | 47 | 48 | 49 | 50 | 上传xcpp文件 51 | 52 | 53 | 54 | 55 | 56 | 57 | 分词 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | Qt::Horizontal 68 | 69 | 70 | QSizePolicy::Fixed 71 | 72 | 73 | 74 | 40 75 | 20 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 0 89 | 0 90 | 1301 91 | 21 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | -------------------------------------------------------------------------------- /第一次实验/编译原理第一次实验/源程序文件夹/lexer/main.cpp: -------------------------------------------------------------------------------- 1 | #include "lexerwindow.h" 2 | 3 | #include 4 | 5 | int main(int argc, char *argv[]) 6 | { 7 | QApplication a(argc, argv); 8 | LexerWindow w; 9 | w.show(); 10 | return a.exec(); 11 | } 12 | -------------------------------------------------------------------------------- /第一次实验/编译原理第一次实验/源程序文件夹/lexer/mapping.json: -------------------------------------------------------------------------------- 1 | { 2 | "(": "SEPARATOR", 3 | ")": "SEPARATOR", 4 | "{": "SEPARATOR", 5 | "}": "SEPARATOR", 6 | "[": "SEPARATOR", 7 | "]": "SEPARATOR", 8 | "#": "SEPARATOR", 9 | ";": "SEPARATOR", 10 | "auto": "KEYWORD", 11 | "bool": "KEYWORD", 12 | "char": "KEYWORD", 13 | "int": "KEYWORD", 14 | "short": "KEYWORD", 15 | "long": "KEYWORD", 16 | "float": "KEYWORD", 17 | "double": "KEYWORD", 18 | "signed": "KEYWORD", 19 | "unsigned": "KEYWORD", 20 | "false": "KEYWORD", 21 | "true": "KEYWORD", 22 | "enum": "KEYWORD", 23 | "union": "KEYWORD", 24 | "struct": "KEYWORD", 25 | "class": "KEYWORD", 26 | "wchar_t": "KEYWORD", 27 | "sizeof": "KEYWORD", 28 | "typeid": "KEYWORD", 29 | "typedef": "KEYWORD", 30 | "static": "KEYWORD", 31 | "public": "KEYWORD", 32 | "protected": "KEYWORD", 33 | "private": "KEYWORD", 34 | "virtual": "KEYWORD", 35 | "override": "KEYWORD", 36 | "final": "KEYWORD", 37 | "operator": "KEYWORD", 38 | "const": "KEYWORD", 39 | "constexpr": "KEYWORD", 40 | "using": "KEYWORD", 41 | "namespace": "KEYWORD", 42 | "inline": "KEYWORD", 43 | "new": "KEYWORD", 44 | "delete": "KEYWORD", 45 | "this": "KEYWORD", 46 | "nullptr": "KEYWORD", 47 | "void": "KEYWORD", 48 | "friend": "KEYWORD", 49 | "template": "KEYWORD", 50 | "if": "KEYWORD", 51 | "else": "KEYWORD", 52 | "for": "KEYWORD", 53 | "while": "KEYWORD", 54 | "do": "KEYWORD", 55 | "switch": "KEYWORD", 56 | "case": "KEYWORD", 57 | "default": "KEYWORD", 58 | "break": "KEYWORD", 59 | "continue": "KEYWORD", 60 | "goto": "KEYWORD", 61 | "and": "KEYWORD", 62 | "not": "KEYWORD", 63 | "or": "KEYWORD", 64 | "xor": "KEYWORD", 65 | "return": "KEYWORD", 66 | "try": "KEYWORD", 67 | "catch": "KEYWORD", 68 | "throw": "KEYWORD", 69 | "noexcept": "KEYWORD", 70 | "static_cast": "KEYWORD", 71 | "const_cast": "KEYWORD", 72 | "dynamic_cast": "KEYWORD", 73 | "reinterpret_cast": "KEYWORD", 74 | "static_assert": "KEYWORD", 75 | "register": "KEYWORD", 76 | "explicit": "KEYWORD", 77 | "extern": "KEYWORD", 78 | "include": "KEYWORD", 79 | "define": "KEYWORD", 80 | "ifdef": "KEYWORD", 81 | "ifndef": "KEYWORD", 82 | "elif": "KEYWORD", 83 | "endif": "KEYWORD", 84 | "pragma": "KEYWORD", 85 | "&&": "OPERATOR", 86 | "||": "OPERATOR", 87 | "!": "OPERATOR", 88 | "+": "OPERATOR", 89 | "-": "OPERATOR", 90 | "*": "OPERATOR", 91 | "/": "OPERATOR", 92 | "%": "OPERATOR", 93 | "++": "OPERATOR", 94 | "--": "OPERATOR", 95 | "&": "OPERATOR", 96 | "|": "OPERATOR", 97 | "^": "OPERATOR", 98 | "~": "OPERATOR", 99 | "<<": "OPERATOR", 100 | ">>": "OPERATOR", 101 | "=": "OPERATOR", 102 | "+=": "OPERATOR", 103 | "-=": "OPERATOR", 104 | "*=": "OPERATOR", 105 | "/=": "OPERATOR", 106 | "%=": "OPERATOR", 107 | "&=": "OPERATOR", 108 | "^=": "OPERATOR", 109 | "|=": "OPERATOR", 110 | "==": "OPERATOR", 111 | "!=": "OPERATOR", 112 | ">": "OPERATOR", 113 | "<": "OPERATOR", 114 | ">=": "OPERATOR", 115 | "<=": "OPERATOR", 116 | ",": "OPERATOR", 117 | ".": "OPERATOR", 118 | "->": "OPERATOR", 119 | "::": "OPERATOR", 120 | "?": "OPERATOR", 121 | ":": "OPERATOR" 122 | } 123 | -------------------------------------------------------------------------------- /第三次实验/lab3/编译原理实验三/文档文件夹/编译原理实验三.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WA-automat/Compiler_Design_SCNU/0f3e92c521e9b785ae8af9784feade5078582a6f/第三次实验/lab3/编译原理实验三/文档文件夹/编译原理实验三.pdf -------------------------------------------------------------------------------- /第三次实验/lab3/编译原理实验三/源代码文件夹/tinySyntaxTree.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WA-automat/Compiler_Design_SCNU/0f3e92c521e9b785ae8af9784feade5078582a6f/第三次实验/lab3/编译原理实验三/源代码文件夹/tinySyntaxTree.zip -------------------------------------------------------------------------------- /第三次实验/lab3/编译原理实验三/源代码文件夹/tinySyntaxTree/main.cpp: -------------------------------------------------------------------------------- 1 | #include "mainwindow.h" 2 | 3 | #include 4 | 5 | int main(int argc, char *argv[]) 6 | { 7 | QApplication a(argc, argv); 8 | MainWindow w; 9 | w.show(); 10 | return a.exec(); 11 | } 12 | -------------------------------------------------------------------------------- /第三次实验/lab3/编译原理实验三/源代码文件夹/tinySyntaxTree/mainwindow.h: -------------------------------------------------------------------------------- 1 | #ifndef MAINWINDOW_H 2 | #define MAINWINDOW_H 3 | 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | #include "utils.h" 11 | 12 | QT_BEGIN_NAMESPACE 13 | namespace Ui { class MainWindow; } 14 | QT_END_NAMESPACE 15 | 16 | typedef struct SyntaxNode { 17 | QString nodeStr; 18 | QVector children; 19 | QVector brother; 20 | 21 | SyntaxNode(QString str): nodeStr(str), children(QVector()), brother(QVector()) {} 22 | SyntaxNode(): SyntaxNode("") {} 23 | }SyntaxNode, * SyntaxTree; 24 | 25 | class MainWindow : public QMainWindow 26 | { 27 | Q_OBJECT 28 | 29 | public: 30 | MainWindow(QWidget *parent = nullptr); 31 | ~MainWindow(); 32 | 33 | QVector> tokenList; 34 | QVector errorList; 35 | QString TOKEN; 36 | int curType, curRow, curCol; 37 | int tokenIndex; 38 | SyntaxTree root; 39 | 40 | private: 41 | Ui::MainWindow *ui; 42 | 43 | /** 44 | * @brief getToken 45 | * 获取下一个token 46 | */ 47 | void getToken(); 48 | 49 | // 匹配需要的token或者指定类型的token 50 | void match(QString expectedToken); 51 | void match(int expectedTokenType); 52 | 53 | /** 54 | * @brief ERROR 55 | * 错误函数 56 | */ 57 | void ERROR(int errorType); 58 | 59 | // 程序系列 60 | SyntaxTree program(); // 完整程序 61 | SyntaxTree stmt_sequence(); // 语句序列 62 | SyntaxTree statement(); // 语句 63 | 64 | // 语句系列 65 | SyntaxTree if_stmt(); // if 语句 66 | SyntaxTree repeat_stmt(); // repeat 语句 67 | SyntaxTree for_stmt(); // for 语句 68 | SyntaxTree while_stmt(); // while 语句 69 | SyntaxTree assign_stmt(); // 赋值语句 70 | SyntaxTree read_stmt(); // 读语句 71 | SyntaxTree write_stmt(); // 写语句 72 | SyntaxTree write_sub_stmt(); // 写子语句 73 | SyntaxTree assign_sub_stmt(); // 赋值语句子语句(区分算术表达式与正则表达式赋值) 74 | 75 | // 正则表达式系列 76 | SyntaxTree re(); 77 | SyntaxTree orre(); 78 | SyntaxTree conre(); 79 | SyntaxTree repre(); 80 | 81 | // 算术表达式系列 82 | SyntaxTree exp(); 83 | SyntaxTree simple_exp(); 84 | SyntaxTree term(); 85 | SyntaxTree factor(); 86 | SyntaxTree selfexp(); 87 | SyntaxTree resexp(); 88 | 89 | // 重置程序 90 | void reset(); 91 | 92 | // 清除语法树 93 | void remove(SyntaxTree tr); 94 | 95 | // 展示语法树 96 | void showTree(QTreeWidgetItem* item, SyntaxTree tr); 97 | 98 | }; 99 | #endif // MAINWINDOW_H 100 | -------------------------------------------------------------------------------- /第三次实验/lab3/编译原理实验三/源代码文件夹/tinySyntaxTree/mainwindow.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | MainWindow 4 | 5 | 6 | 7 | 0 8 | 0 9 | 800 10 | 600 11 | 12 | 13 | 14 | 15 | 16777215 16 | 16777215 17 | 18 | 19 | 20 | MainWindow 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 生成语法树 34 | 35 | 36 | 37 | 38 | 39 | 40 | 打开源文件 41 | 42 | 43 | 44 | 45 | 46 | 47 | 重置 48 | 49 | 50 | 51 | 52 | 53 | 54 | 保存源文件 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 16777215 66 | 300 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 0 81 | 82 | 83 | 84 | 词法展示 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 语法树展示 95 | 96 | 97 | 98 | 99 | 100 | 101 | 1 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 0 116 | 0 117 | 800 118 | 21 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | -------------------------------------------------------------------------------- /第三次实验/lab3/编译原理实验三/源代码文件夹/tinySyntaxTree/mapping.json: -------------------------------------------------------------------------------- 1 | { 2 | "read": "keyword", 3 | "write": "keyword", 4 | "if": "keyword", 5 | "else": "keyword", 6 | "repeat": "keyword", 7 | "until": "keyword", 8 | "for": "keyword", 9 | "while": "keyword", 10 | "endwhile": "keyword", 11 | "endfor": "keyword", 12 | "endif": "keyword", 13 | ":=": "operator", 14 | "<": "operator", 15 | "=": "operator", 16 | ">": "operator", 17 | "<=": "operator", 18 | ">=": "operator", 19 | "<>": "operator", 20 | "+": "operator", 21 | "-": "operator", 22 | "*": "operator", 23 | "/": "operator", 24 | "%": "operator", 25 | "^": "operator", 26 | "++": "operator", 27 | "--": "operator", 28 | "|": "operator", 29 | "&": "operator", 30 | "#": "operator", 31 | "?": "operator", 32 | "==": "operator", 33 | "(": "separator", 34 | ")": "separator", 35 | ";": "separator" 36 | } 37 | -------------------------------------------------------------------------------- /第三次实验/lab3/编译原理实验三/源代码文件夹/tinySyntaxTree/resource.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | mapping.json 4 | 5 | 6 | -------------------------------------------------------------------------------- /第三次实验/lab3/编译原理实验三/源代码文件夹/tinySyntaxTree/tinySyntaxTree.pro: -------------------------------------------------------------------------------- 1 | QT += core gui 2 | 3 | greaterThan(QT_MAJOR_VERSION, 4): QT += widgets 4 | 5 | CONFIG += c++11 6 | 7 | # You can make your code fail to compile if it uses deprecated APIs. 8 | # In order to do so, uncomment the following line. 9 | #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 10 | 11 | SOURCES += \ 12 | main.cpp \ 13 | mainwindow.cpp \ 14 | utils.cpp 15 | 16 | HEADERS += \ 17 | mainwindow.h \ 18 | utils.h 19 | 20 | FORMS += \ 21 | mainwindow.ui 22 | 23 | # Default rules for deployment. 24 | qnx: target.path = /tmp/$${TARGET}/bin 25 | else: unix:!android: target.path = /opt/$${TARGET}/bin 26 | !isEmpty(target.path): INSTALLS += target 27 | 28 | RESOURCES += \ 29 | resource.qrc 30 | -------------------------------------------------------------------------------- /第三次实验/lab3/编译原理实验三/源代码文件夹/tinySyntaxTree/utils.cpp: -------------------------------------------------------------------------------- 1 | #include "utils.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | QVector > lexer(QString content) 11 | { 12 | 13 | // 获取关键字与运算符 14 | QFile file(":/mapping.json"); 15 | QHash hash; 16 | if (file.open(QIODevice::ReadOnly | QIODevice::Text)) { 17 | QByteArray data = file.readAll(); 18 | QJsonDocument jsonDocument = QJsonDocument::fromJson(data); 19 | 20 | if (!jsonDocument.isNull()) { 21 | QJsonObject jsonObject = jsonDocument.object(); 22 | 23 | for (auto it = jsonObject.begin(); it != jsonObject.end(); ++it) { 24 | QString key = it.key(); 25 | QString value = it.value().toString(); 26 | hash.insert(key, value); 27 | } 28 | } 29 | } 30 | 31 | // 开始分词 32 | QVector> tokenList; 33 | QStringList lines = content.split("\n"); 34 | bool finishCom = false; 35 | int cachePos = 0; 36 | for (int index = 0; index < lines.size(); index++) { 37 | const QString& line = lines[index]; 38 | int pos = finishCom ? cachePos : 0; 39 | int len = line.size(); 40 | 41 | finishCom = false; 42 | 43 | // 跳过空格与tab 44 | while (pos < len && (line[pos] == ' ' || line[pos] == '\t')) pos++; 45 | if (pos == len) continue; 46 | 47 | // 遍历单行 48 | while (pos < len) { 49 | // qDebug() << line[pos] << ' ' << hash.contains(QString(line[pos])) << endl; 50 | if (hash.contains(line[pos]) && hash[line[pos]] == "separator") { 51 | // 判断 (、)、; 等分隔符号 52 | tokenList.append(qMakePair(QString(line[pos]), LexerInfo(0, index, pos))); 53 | pos++; 54 | } else if (pos != len && line[pos] == '\'') { 55 | // 字符类型 56 | int endIndex = line.indexOf(line[pos], pos + 1); 57 | if (endIndex != -1) { 58 | while (endIndex != -1 && line[endIndex - 1] == '\\') endIndex = line.indexOf(line[pos], endIndex + 1); 59 | if (endIndex == -1) { 60 | break; 61 | } 62 | QString str = line.mid(pos, endIndex - pos + 1); 63 | tokenList.append(qMakePair(str, LexerInfo(1, index, pos))); 64 | pos = endIndex + 1; 65 | } else { 66 | // 出现错误 67 | break; 68 | } 69 | } else if (line[pos] == '+' || line[pos] == '-' || line[pos].isDigit()) { 70 | // 数字类型或运算符 71 | if (line[pos] == '+' || line[pos] == '-') { 72 | // 判断 + 与 - 是运算符还是数字的一部分 73 | 74 | if (tokenList.back().second.lexerType != 5) { 75 | // 在tiny语言中,上一个token不为运算符,则当前+-必定为运算符 76 | tokenList.append(qMakePair(QString(line[pos]), LexerInfo(5, index, pos))); 77 | pos++; 78 | continue; 79 | } 80 | // qDebug() << tokenList.back().first << ' ' << line[pos]; 81 | if (tokenList.back().first == line[pos] && tokenList.size() > 1 && tokenList[tokenList.size() - 2].second.lexerType != 2) { 82 | // qDebug() << pos << endl; 83 | tokenList.pop_back(); 84 | tokenList.append(qMakePair(QString(line[pos] == '+' ? "++" : "--"), LexerInfo(5, index, pos - 1))); 85 | pos++; 86 | continue; 87 | } 88 | if (pos == len - 1 || !line[pos + 1].isDigit()) { 89 | // + 与 - 位于最后一个位置或后续字符不为数字 90 | tokenList.append(qMakePair(QString(line[pos]), LexerInfo(5, index, pos))); 91 | pos++; 92 | continue; 93 | } 94 | } 95 | 96 | // 完整数字匹配 97 | QString number = ((line[pos] == '+' || line[pos] == '-' ) ? line[pos] : QString("")); 98 | if (line[pos] == '+' || line[pos] == '-') pos++; 99 | while (pos < len && line[pos].isDigit()) number += line[pos++]; 100 | if (pos < len - 1 && line[pos] == '.' && line[pos + 1].isDigit()) number += line[pos++]; 101 | while (pos < len && line[pos].isDigit()) number += line[pos++]; 102 | if (pos < len - 1 && (line[pos] == 'E' || line[pos] == 'e') && line[pos + 1].isDigit()) number += line[pos++]; 103 | while (pos < len && line[pos].isDigit()) number += line[pos++]; 104 | tokenList.append(qMakePair(QString(number), LexerInfo(2, index, pos - number.size()))); 105 | 106 | } else if (line[pos].isLetter() || line[pos] == '_') { 107 | // 标识符或关键字 108 | QString identifier; 109 | while (pos < len && (line[pos].isDigit() || line[pos].isLetter() || line[pos] == '_')) identifier += line[pos++]; 110 | 111 | // 判断是否为关键词 112 | if (hash.contains(identifier) && hash[identifier] == "keyword") { 113 | // 关键词 114 | tokenList.append(qMakePair(identifier, LexerInfo(4, index, pos - identifier.size()))); 115 | } else { 116 | // 标识符 117 | tokenList.append(qMakePair(identifier, LexerInfo(3, index, pos - identifier.size()))); 118 | } 119 | 120 | } else if (line[pos] == '{') { 121 | // 注释 122 | int indexCnt = index, posCnt = pos; 123 | while (indexCnt < lines.size()) { 124 | 125 | // 查找注释结束位置 126 | int endCom = lines[indexCnt].indexOf('}', pos); 127 | if (endCom != -1) { 128 | tokenList.append(qMakePair(lines[indexCnt].mid(posCnt, endCom - posCnt + 1), LexerInfo(6, indexCnt, posCnt))); 129 | posCnt = endCom + 1; 130 | break; 131 | } 132 | 133 | // 没找到就找下一行 134 | tokenList.append(qMakePair(lines[indexCnt].right(lines[indexCnt].size() - posCnt), LexerInfo(6, indexCnt, posCnt))); 135 | posCnt = 0; 136 | indexCnt++; 137 | 138 | } 139 | index = indexCnt - 1; 140 | cachePos = posCnt; 141 | finishCom = true; 142 | break; 143 | 144 | } else { 145 | // 运算符 146 | if (pos < len - 1 && hash.contains(line.mid(pos, 2)) && hash[line.mid(pos, 2)] == "operator") { 147 | // 双字符运算符 148 | tokenList.append(qMakePair(line.mid(pos, 2), LexerInfo(5, index, pos))); 149 | pos += 2; 150 | } else if (hash.contains(line[pos]) && hash[line[pos]] == "operator") { 151 | // 单字符运算符 152 | tokenList.append(qMakePair(line[pos], LexerInfo(5, index, pos))); 153 | pos++; 154 | } else { 155 | // 其他 156 | pos++; 157 | } 158 | } 159 | 160 | } 161 | } 162 | 163 | // for (const auto &token : tokenList) { 164 | // qDebug() << token.first << ' ' << token.second.lexerType; 165 | // } 166 | 167 | return tokenList; 168 | } 169 | 170 | QString getTypeString(int type) 171 | { 172 | switch (type) { 173 | case 0: 174 | return "分隔符"; 175 | case 1: 176 | return "字符"; 177 | case 2: 178 | return "数字"; 179 | case 3: 180 | return "标识符"; 181 | case 4: 182 | return "关键字"; 183 | case 5: 184 | return "运算符"; 185 | case 6: 186 | return "注释"; 187 | default: 188 | return ""; 189 | } 190 | } 191 | -------------------------------------------------------------------------------- /第三次实验/lab3/编译原理实验三/源代码文件夹/tinySyntaxTree/utils.h: -------------------------------------------------------------------------------- 1 | #ifndef UTILS_H 2 | #define UTILS_H 3 | 4 | #include 5 | #include 6 | 7 | /** 8 | * @brief The LexerInfo struct 9 | * 记录分词信息 10 | * 类型: 11 | * 0:分隔符号 12 | * 1:字符 13 | * 2:数字 14 | * 3:标识符 15 | * 4:关键字 16 | * 5: 运算符 17 | * 6:注释 18 | */ 19 | struct LexerInfo { 20 | int lexerType; // 分词类别 21 | int row; // 行 22 | int column; // 列 23 | LexerInfo(int type, int r, int c): lexerType(type), row(r), column(c) {} 24 | LexerInfo(): LexerInfo(0, 0, 0) {} 25 | }; 26 | 27 | struct ErrorInfo { 28 | QString info; 29 | int row, column; 30 | ErrorInfo(QString msg, int r, int c): info(msg), row(r), column(c) {} 31 | ErrorInfo(): ErrorInfo("", 0, 0) {} 32 | }; 33 | 34 | QVector> lexer(QString content); 35 | QString getTypeString(int type); 36 | 37 | #endif // UTILS_H 38 | -------------------------------------------------------------------------------- /第二次实验/build-regex2dfa-Desktop_Qt_5_12_12_MinGW_32_bit-Debug/.qmake.stash: -------------------------------------------------------------------------------- 1 | QMAKE_CXX.QT_COMPILER_STDCXX = 201402L 2 | QMAKE_CXX.QMAKE_GCC_MAJOR_VERSION = 7 3 | QMAKE_CXX.QMAKE_GCC_MINOR_VERSION = 3 4 | QMAKE_CXX.QMAKE_GCC_PATCH_VERSION = 0 5 | QMAKE_CXX.COMPILER_MACROS = \ 6 | QT_COMPILER_STDCXX \ 7 | QMAKE_GCC_MAJOR_VERSION \ 8 | QMAKE_GCC_MINOR_VERSION \ 9 | QMAKE_GCC_PATCH_VERSION 10 | QMAKE_CXX.INCDIRS = \ 11 | D:/qt_5.12.12_C++/Tools/mingw730_32/lib/gcc/i686-w64-mingw32/7.3.0/include/c++ \ 12 | D:/qt_5.12.12_C++/Tools/mingw730_32/lib/gcc/i686-w64-mingw32/7.3.0/include/c++/i686-w64-mingw32 \ 13 | D:/qt_5.12.12_C++/Tools/mingw730_32/lib/gcc/i686-w64-mingw32/7.3.0/include/c++/backward \ 14 | D:/qt_5.12.12_C++/Tools/mingw730_32/lib/gcc/i686-w64-mingw32/7.3.0/include \ 15 | D:/qt_5.12.12_C++/Tools/mingw730_32/lib/gcc/i686-w64-mingw32/7.3.0/include-fixed \ 16 | D:/qt_5.12.12_C++/Tools/mingw730_32/i686-w64-mingw32/include 17 | QMAKE_CXX.LIBDIRS = \ 18 | D:/qt_5.12.12_C++/Tools/mingw730_32/lib/gcc/i686-w64-mingw32/7.3.0 \ 19 | D:/qt_5.12.12_C++/Tools/mingw730_32/lib/gcc \ 20 | D:/qt_5.12.12_C++/Tools/mingw730_32/i686-w64-mingw32/lib \ 21 | D:/qt_5.12.12_C++/Tools/mingw730_32/lib 22 | -------------------------------------------------------------------------------- /第二次实验/build-regex2dfa-Desktop_Qt_5_12_12_MinGW_32_bit-Debug/debug/moc_codedialog.cpp: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | ** Meta object code from reading C++ file 'codedialog.h' 3 | ** 4 | ** Created by: The Qt Meta Object Compiler version 67 (Qt 5.12.12) 5 | ** 6 | ** WARNING! All changes made in this file will be lost! 7 | *****************************************************************************/ 8 | 9 | #include "../../regex2dfa/codedialog.h" 10 | #include 11 | #include 12 | #if !defined(Q_MOC_OUTPUT_REVISION) 13 | #error "The header file 'codedialog.h' doesn't include ." 14 | #elif Q_MOC_OUTPUT_REVISION != 67 15 | #error "This file was generated using the moc from 5.12.12. It" 16 | #error "cannot be used with the include files from this version of Qt." 17 | #error "(The moc has changed too much.)" 18 | #endif 19 | 20 | QT_BEGIN_MOC_NAMESPACE 21 | QT_WARNING_PUSH 22 | QT_WARNING_DISABLE_DEPRECATED 23 | struct qt_meta_stringdata_CodeDialog_t { 24 | QByteArrayData data[1]; 25 | char stringdata0[11]; 26 | }; 27 | #define QT_MOC_LITERAL(idx, ofs, len) \ 28 | Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(len, \ 29 | qptrdiff(offsetof(qt_meta_stringdata_CodeDialog_t, stringdata0) + ofs \ 30 | - idx * sizeof(QByteArrayData)) \ 31 | ) 32 | static const qt_meta_stringdata_CodeDialog_t qt_meta_stringdata_CodeDialog = { 33 | { 34 | QT_MOC_LITERAL(0, 0, 10) // "CodeDialog" 35 | 36 | }, 37 | "CodeDialog" 38 | }; 39 | #undef QT_MOC_LITERAL 40 | 41 | static const uint qt_meta_data_CodeDialog[] = { 42 | 43 | // content: 44 | 8, // revision 45 | 0, // classname 46 | 0, 0, // classinfo 47 | 0, 0, // methods 48 | 0, 0, // properties 49 | 0, 0, // enums/sets 50 | 0, 0, // constructors 51 | 0, // flags 52 | 0, // signalCount 53 | 54 | 0 // eod 55 | }; 56 | 57 | void CodeDialog::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a) 58 | { 59 | Q_UNUSED(_o); 60 | Q_UNUSED(_id); 61 | Q_UNUSED(_c); 62 | Q_UNUSED(_a); 63 | } 64 | 65 | QT_INIT_METAOBJECT const QMetaObject CodeDialog::staticMetaObject = { { 66 | &QDialog::staticMetaObject, 67 | qt_meta_stringdata_CodeDialog.data, 68 | qt_meta_data_CodeDialog, 69 | qt_static_metacall, 70 | nullptr, 71 | nullptr 72 | } }; 73 | 74 | 75 | const QMetaObject *CodeDialog::metaObject() const 76 | { 77 | return QObject::d_ptr->metaObject ? QObject::d_ptr->dynamicMetaObject() : &staticMetaObject; 78 | } 79 | 80 | void *CodeDialog::qt_metacast(const char *_clname) 81 | { 82 | if (!_clname) return nullptr; 83 | if (!strcmp(_clname, qt_meta_stringdata_CodeDialog.stringdata0)) 84 | return static_cast(this); 85 | return QDialog::qt_metacast(_clname); 86 | } 87 | 88 | int CodeDialog::qt_metacall(QMetaObject::Call _c, int _id, void **_a) 89 | { 90 | _id = QDialog::qt_metacall(_c, _id, _a); 91 | return _id; 92 | } 93 | QT_WARNING_POP 94 | QT_END_MOC_NAMESPACE 95 | -------------------------------------------------------------------------------- /第二次实验/build-regex2dfa-Desktop_Qt_5_12_12_MinGW_32_bit-Debug/debug/moc_mainwindow.cpp: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | ** Meta object code from reading C++ file 'mainwindow.h' 3 | ** 4 | ** Created by: The Qt Meta Object Compiler version 67 (Qt 5.12.12) 5 | ** 6 | ** WARNING! All changes made in this file will be lost! 7 | *****************************************************************************/ 8 | 9 | #include "../../regex2dfa/mainwindow.h" 10 | #include 11 | #include 12 | #if !defined(Q_MOC_OUTPUT_REVISION) 13 | #error "The header file 'mainwindow.h' doesn't include ." 14 | #elif Q_MOC_OUTPUT_REVISION != 67 15 | #error "This file was generated using the moc from 5.12.12. It" 16 | #error "cannot be used with the include files from this version of Qt." 17 | #error "(The moc has changed too much.)" 18 | #endif 19 | 20 | QT_BEGIN_MOC_NAMESPACE 21 | QT_WARNING_PUSH 22 | QT_WARNING_DISABLE_DEPRECATED 23 | struct qt_meta_stringdata_MainWindow_t { 24 | QByteArrayData data[1]; 25 | char stringdata0[11]; 26 | }; 27 | #define QT_MOC_LITERAL(idx, ofs, len) \ 28 | Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(len, \ 29 | qptrdiff(offsetof(qt_meta_stringdata_MainWindow_t, stringdata0) + ofs \ 30 | - idx * sizeof(QByteArrayData)) \ 31 | ) 32 | static const qt_meta_stringdata_MainWindow_t qt_meta_stringdata_MainWindow = { 33 | { 34 | QT_MOC_LITERAL(0, 0, 10) // "MainWindow" 35 | 36 | }, 37 | "MainWindow" 38 | }; 39 | #undef QT_MOC_LITERAL 40 | 41 | static const uint qt_meta_data_MainWindow[] = { 42 | 43 | // content: 44 | 8, // revision 45 | 0, // classname 46 | 0, 0, // classinfo 47 | 0, 0, // methods 48 | 0, 0, // properties 49 | 0, 0, // enums/sets 50 | 0, 0, // constructors 51 | 0, // flags 52 | 0, // signalCount 53 | 54 | 0 // eod 55 | }; 56 | 57 | void MainWindow::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a) 58 | { 59 | Q_UNUSED(_o); 60 | Q_UNUSED(_id); 61 | Q_UNUSED(_c); 62 | Q_UNUSED(_a); 63 | } 64 | 65 | QT_INIT_METAOBJECT const QMetaObject MainWindow::staticMetaObject = { { 66 | &QMainWindow::staticMetaObject, 67 | qt_meta_stringdata_MainWindow.data, 68 | qt_meta_data_MainWindow, 69 | qt_static_metacall, 70 | nullptr, 71 | nullptr 72 | } }; 73 | 74 | 75 | const QMetaObject *MainWindow::metaObject() const 76 | { 77 | return QObject::d_ptr->metaObject ? QObject::d_ptr->dynamicMetaObject() : &staticMetaObject; 78 | } 79 | 80 | void *MainWindow::qt_metacast(const char *_clname) 81 | { 82 | if (!_clname) return nullptr; 83 | if (!strcmp(_clname, qt_meta_stringdata_MainWindow.stringdata0)) 84 | return static_cast(this); 85 | return QMainWindow::qt_metacast(_clname); 86 | } 87 | 88 | int MainWindow::qt_metacall(QMetaObject::Call _c, int _id, void **_a) 89 | { 90 | _id = QMainWindow::qt_metacall(_c, _id, _a); 91 | return _id; 92 | } 93 | QT_WARNING_POP 94 | QT_END_MOC_NAMESPACE 95 | -------------------------------------------------------------------------------- /第二次实验/build-regex2dfa-Desktop_Qt_5_12_12_MinGW_32_bit-Debug/debug/moc_predefs.h: -------------------------------------------------------------------------------- 1 | #define __DBL_MIN_EXP__ (-1021) 2 | #define __FLT32X_MAX_EXP__ 1024 3 | #define __cpp_attributes 200809 4 | #define __pentiumpro__ 1 5 | #define __UINT_LEAST16_MAX__ 0xffff 6 | #define __ATOMIC_ACQUIRE 2 7 | #define __FLT128_MAX_10_EXP__ 4932 8 | #define __FLT_MIN__ 1.17549435082228750796873653722224568e-38F 9 | #define __GCC_IEC_559_COMPLEX 2 10 | #define __UINT_LEAST8_TYPE__ unsigned char 11 | #define __SIZEOF_FLOAT80__ 12 12 | #define _WIN32 1 13 | #define __INTMAX_C(c) c ## LL 14 | #define __CHAR_BIT__ 8 15 | #define __UINT8_MAX__ 0xff 16 | #define __WINT_MAX__ 0xffff 17 | #define __FLT32_MIN_EXP__ (-125) 18 | #define __cpp_static_assert 200410 19 | #define __ORDER_LITTLE_ENDIAN__ 1234 20 | #define __SIZE_MAX__ 0xffffffffU 21 | #define __WCHAR_MAX__ 0xffff 22 | #define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_1 1 23 | #define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_2 1 24 | #define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4 1 25 | #define __DBL_DENORM_MIN__ double(4.94065645841246544176568792868221372e-324L) 26 | #define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_8 1 27 | #define __GCC_ATOMIC_CHAR_LOCK_FREE 2 28 | #define __GCC_IEC_559 2 29 | #define __FLT32X_DECIMAL_DIG__ 17 30 | #define __FLT_EVAL_METHOD__ 2 31 | #define __cpp_binary_literals 201304 32 | #define __FLT64_DECIMAL_DIG__ 17 33 | #define __GCC_ATOMIC_CHAR32_T_LOCK_FREE 2 34 | #define __cpp_variadic_templates 200704 35 | #define __UINT_FAST64_MAX__ 0xffffffffffffffffULL 36 | #define __SIG_ATOMIC_TYPE__ int 37 | #define __DBL_MIN_10_EXP__ (-307) 38 | #define __FINITE_MATH_ONLY__ 0 39 | #define __GNUC_PATCHLEVEL__ 0 40 | #define __FLT32_HAS_DENORM__ 1 41 | #define __UINT_FAST8_MAX__ 0xff 42 | #define __has_include(STR) __has_include__(STR) 43 | #define _stdcall __attribute__((__stdcall__)) 44 | #define __DEC64_MAX_EXP__ 385 45 | #define __INT8_C(c) c 46 | #define __INT_LEAST8_WIDTH__ 8 47 | #define __UINT_LEAST64_MAX__ 0xffffffffffffffffULL 48 | #define __SHRT_MAX__ 0x7fff 49 | #define __LDBL_MAX__ 1.18973149535723176502126385303097021e+4932L 50 | #define __FLT64X_MAX_10_EXP__ 4932 51 | #define __UINT_LEAST8_MAX__ 0xff 52 | #define __GCC_ATOMIC_BOOL_LOCK_FREE 2 53 | #define __FLT128_DENORM_MIN__ 6.47517511943802511092443895822764655e-4966F128 54 | #define __UINTMAX_TYPE__ long long unsigned int 55 | #define __DEC32_EPSILON__ 1E-6DF 56 | #define __FLT_EVAL_METHOD_TS_18661_3__ 2 57 | #define __UINT32_MAX__ 0xffffffffU 58 | #define __GXX_EXPERIMENTAL_CXX0X__ 1 59 | #define __LDBL_MAX_EXP__ 16384 60 | #define __FLT128_MIN_EXP__ (-16381) 61 | #define __WINT_MIN__ 0 62 | #define __FLT128_MIN_10_EXP__ (-4931) 63 | #define __INT_LEAST16_WIDTH__ 16 64 | #define __SCHAR_MAX__ 0x7f 65 | #define __FLT128_MANT_DIG__ 113 66 | #define __WCHAR_MIN__ 0 67 | #define __INT64_C(c) c ## LL 68 | #define __DBL_DIG__ 15 69 | #define __GCC_ATOMIC_POINTER_LOCK_FREE 2 70 | #define __FLT64X_MANT_DIG__ 64 71 | #define __SIZEOF_INT__ 4 72 | #define __SIZEOF_POINTER__ 4 73 | #define __GCC_ATOMIC_CHAR16_T_LOCK_FREE 2 74 | #define __USER_LABEL_PREFIX__ _ 75 | #define __FLT64X_EPSILON__ 1.08420217248550443400745280086994171e-19F64x 76 | #define __STDC_HOSTED__ 1 77 | #define __WIN32 1 78 | #define __LDBL_HAS_INFINITY__ 1 79 | #define __FLT32_DIG__ 6 80 | #define __FLT_EPSILON__ 1.19209289550781250000000000000000000e-7F 81 | #define __GXX_WEAK__ 1 82 | #define __SHRT_WIDTH__ 16 83 | #define __LDBL_MIN__ 3.36210314311209350626267781732175260e-4932L 84 | #define __DEC32_MAX__ 9.999999E96DF 85 | #define __cpp_threadsafe_static_init 200806 86 | #define __FLT64X_DENORM_MIN__ 3.64519953188247460252840593361941982e-4951F64x 87 | #define __MINGW32__ 1 88 | #define __FLT32X_HAS_INFINITY__ 1 89 | #define __INT32_MAX__ 0x7fffffff 90 | #define __INT_WIDTH__ 32 91 | #define __SIZEOF_LONG__ 4 92 | #define __UINT16_C(c) c 93 | #define __PTRDIFF_WIDTH__ 32 94 | #define __DECIMAL_DIG__ 21 95 | #define __FLT64_EPSILON__ 2.22044604925031308084726333618164062e-16F64 96 | #define __INTMAX_WIDTH__ 64 97 | #define __FLT64_MIN_EXP__ (-1021) 98 | #define __has_include_next(STR) __has_include_next__(STR) 99 | #define __FLT64X_MIN_10_EXP__ (-4931) 100 | #define __LDBL_HAS_QUIET_NAN__ 1 101 | #define __FLT64_MANT_DIG__ 53 102 | #define _REENTRANT 1 103 | #define __GNUC__ 7 104 | #define _cdecl __attribute__((__cdecl__)) 105 | #define __GXX_RTTI 1 106 | #define __cpp_delegating_constructors 200604 107 | #define __FLT_HAS_DENORM__ 1 108 | #define __SIZEOF_LONG_DOUBLE__ 12 109 | #define __BIGGEST_ALIGNMENT__ 16 110 | #define __STDC_UTF_16__ 1 111 | #define __FLT64_MAX_10_EXP__ 308 112 | #define __i686 1 113 | #define __FLT32_HAS_INFINITY__ 1 114 | #define __DBL_MAX__ double(1.79769313486231570814527423731704357e+308L) 115 | #define _thiscall __attribute__((__thiscall__)) 116 | #define __cpp_raw_strings 200710 117 | #define __INT_FAST32_MAX__ 0x7fffffff 118 | #define __WINNT 1 119 | #define __DBL_HAS_INFINITY__ 1 120 | #define __INT64_MAX__ 0x7fffffffffffffffLL 121 | #define __WINNT__ 1 122 | #define __DEC32_MIN_EXP__ (-94) 123 | #define __INTPTR_WIDTH__ 32 124 | #define __FLT32X_HAS_DENORM__ 1 125 | #define __INT_FAST16_TYPE__ short int 126 | #define _fastcall __attribute__((__fastcall__)) 127 | #define __LDBL_HAS_DENORM__ 1 128 | #define __cplusplus 201103L 129 | #define __cpp_ref_qualifiers 200710 130 | #define __DEC128_MAX__ 9.999999999999999999999999999999999E6144DL 131 | #define __INT_LEAST32_MAX__ 0x7fffffff 132 | #define __DEC32_MIN__ 1E-95DF 133 | #define __DEPRECATED 1 134 | #define __cpp_rvalue_references 200610 135 | #define __DBL_MAX_EXP__ 1024 136 | #define __WCHAR_WIDTH__ 16 137 | #define __FLT32_MAX__ 3.40282346638528859811704183484516925e+38F32 138 | #define __DEC128_EPSILON__ 1E-33DL 139 | #define __ATOMIC_HLE_RELEASE 131072 140 | #define __WIN32__ 1 141 | #define __PTRDIFF_MAX__ 0x7fffffff 142 | #define __ATOMIC_HLE_ACQUIRE 65536 143 | #define __FLT32_HAS_QUIET_NAN__ 1 144 | #define __GNUG__ 7 145 | #define __LONG_LONG_MAX__ 0x7fffffffffffffffLL 146 | #define __SIZEOF_SIZE_T__ 4 147 | #define __cpp_rvalue_reference 200610 148 | #define __cpp_nsdmi 200809 149 | #define __FLT64X_MIN_EXP__ (-16381) 150 | #define __SIZEOF_WINT_T__ 2 151 | #define __LONG_LONG_WIDTH__ 64 152 | #define __cpp_initializer_lists 200806 153 | #define __FLT32_MAX_EXP__ 128 154 | #define __cpp_hex_float 201603 155 | #define __GCC_HAVE_DWARF2_CFI_ASM 1 156 | #define __GXX_ABI_VERSION 1011 157 | #define __FLT128_HAS_INFINITY__ 1 158 | #define __FLT_MIN_EXP__ (-125) 159 | #define __i686__ 1 160 | #define __cpp_lambdas 200907 161 | #define __FLT64X_HAS_QUIET_NAN__ 1 162 | #define __INT_FAST64_TYPE__ long long int 163 | #define __FLT64_DENORM_MIN__ 4.94065645841246544176568792868221372e-324F64 164 | #define __DBL_MIN__ double(2.22507385850720138309023271733240406e-308L) 165 | #define __FLT32X_EPSILON__ 2.22044604925031308084726333618164062e-16F32x 166 | #define __DECIMAL_BID_FORMAT__ 1 167 | #define __GXX_TYPEINFO_EQUALITY_INLINE 0 168 | #define __FLT64_MIN_10_EXP__ (-307) 169 | #define __FLT64X_DECIMAL_DIG__ 21 170 | #define __DEC128_MIN__ 1E-6143DL 171 | #define __REGISTER_PREFIX__ 172 | #define __UINT16_MAX__ 0xffff 173 | #define __DBL_HAS_DENORM__ 1 174 | #define __cdecl __attribute__((__cdecl__)) 175 | #define __FLT32_MIN__ 1.17549435082228750796873653722224568e-38F32 176 | #define __UINT8_TYPE__ unsigned char 177 | #define __NO_INLINE__ 1 178 | #define __i386 1 179 | #define __FLT_MANT_DIG__ 24 180 | #define __LDBL_DECIMAL_DIG__ 21 181 | #define __VERSION__ "7.3.0" 182 | #define __UINT64_C(c) c ## ULL 183 | #define __cpp_unicode_characters 200704 184 | #define __GCC_ATOMIC_INT_LOCK_FREE 2 185 | #define __FLT128_MAX_EXP__ 16384 186 | #define __FLT32_MANT_DIG__ 24 187 | #define _X86_ 1 188 | #define __FLOAT_WORD_ORDER__ __ORDER_LITTLE_ENDIAN__ 189 | #define __FLT128_HAS_DENORM__ 1 190 | #define __FLT128_DIG__ 33 191 | #define __SCHAR_WIDTH__ 8 192 | #define __INT32_C(c) c 193 | #define __DEC64_EPSILON__ 1E-15DD 194 | #define __ORDER_PDP_ENDIAN__ 3412 195 | #define __DEC128_MIN_EXP__ (-6142) 196 | #define __code_model_32__ 1 197 | #define __FLT32_MAX_10_EXP__ 38 198 | #define __INT_FAST32_TYPE__ int 199 | #define __UINT_LEAST16_TYPE__ short unsigned int 200 | #define __FLT64X_HAS_INFINITY__ 1 201 | #define __INT16_MAX__ 0x7fff 202 | #define __i386__ 1 203 | #define __cpp_rtti 199711 204 | #define __SIZE_TYPE__ unsigned int 205 | #define __UINT64_MAX__ 0xffffffffffffffffULL 206 | #define __FLT64X_DIG__ 18 207 | #define __INT8_TYPE__ signed char 208 | #define __GCC_ASM_FLAG_OUTPUTS__ 1 209 | #define __FLT_RADIX__ 2 210 | #define __INT_LEAST16_TYPE__ short int 211 | #define __LDBL_EPSILON__ 1.08420217248550443400745280086994171e-19L 212 | #define __UINTMAX_C(c) c ## ULL 213 | #define __SIG_ATOMIC_MAX__ 0x7fffffff 214 | #define __GCC_ATOMIC_WCHAR_T_LOCK_FREE 2 215 | #define __SIZEOF_PTRDIFF_T__ 4 216 | #define __FLT32X_MANT_DIG__ 53 217 | #define __FLT32X_MIN_EXP__ (-1021) 218 | #define __DEC32_SUBNORMAL_MIN__ 0.000001E-95DF 219 | #define __pentiumpro 1 220 | #define __MSVCRT__ 1 221 | #define __INT_FAST16_MAX__ 0x7fff 222 | #define __FLT64_DIG__ 15 223 | #define __UINT_FAST32_MAX__ 0xffffffffU 224 | #define __UINT_LEAST64_TYPE__ long long unsigned int 225 | #define __FLT_HAS_QUIET_NAN__ 1 226 | #define __FLT_MAX_10_EXP__ 38 227 | #define __LONG_MAX__ 0x7fffffffL 228 | #define __FLT64X_HAS_DENORM__ 1 229 | #define __DEC128_SUBNORMAL_MIN__ 0.000000000000000000000000000000001E-6143DL 230 | #define __FLT_HAS_INFINITY__ 1 231 | #define __cpp_unicode_literals 200710 232 | #define __UINT_FAST16_TYPE__ short unsigned int 233 | #define __DEC64_MAX__ 9.999999999999999E384DD 234 | #define __INT_FAST32_WIDTH__ 32 235 | #define __CHAR16_TYPE__ short unsigned int 236 | #define __PRAGMA_REDEFINE_EXTNAME 1 237 | #define __SIZE_WIDTH__ 32 238 | #define __SEG_FS 1 239 | #define __INT_LEAST16_MAX__ 0x7fff 240 | #define __DEC64_MANT_DIG__ 16 241 | #define __UINT_LEAST32_MAX__ 0xffffffffU 242 | #define __SEG_GS 1 243 | #define __FLT32_DENORM_MIN__ 1.40129846432481707092372958328991613e-45F32 244 | #define __GCC_ATOMIC_LONG_LOCK_FREE 2 245 | #define __SIG_ATOMIC_WIDTH__ 32 246 | #define __INT_LEAST64_TYPE__ long long int 247 | #define __INT16_TYPE__ short int 248 | #define __INT_LEAST8_TYPE__ signed char 249 | #define __DEC32_MAX_EXP__ 97 250 | #define __INT_FAST8_MAX__ 0x7f 251 | #define __FLT128_MAX__ 1.18973149535723176508575932662800702e+4932F128 252 | #define __INTPTR_MAX__ 0x7fffffff 253 | #define __GXX_MERGED_TYPEINFO_NAMES 0 254 | #define __cpp_range_based_for 200907 255 | #define __FLT64_HAS_QUIET_NAN__ 1 256 | #define __stdcall __attribute__((__stdcall__)) 257 | #define __FLT32_MIN_10_EXP__ (-37) 258 | #define __EXCEPTIONS 1 259 | #define __LDBL_MANT_DIG__ 64 260 | #define __DBL_HAS_QUIET_NAN__ 1 261 | #define __FLT64_HAS_INFINITY__ 1 262 | #define __FLT64X_MAX__ 1.18973149535723176502126385303097021e+4932F64x 263 | #define __SIG_ATOMIC_MIN__ (-__SIG_ATOMIC_MAX__ - 1) 264 | #define __INTPTR_TYPE__ int 265 | #define __UINT16_TYPE__ short unsigned int 266 | #define __WCHAR_TYPE__ short unsigned int 267 | #define __SIZEOF_FLOAT__ 4 268 | #define __UINTPTR_MAX__ 0xffffffffU 269 | #define __INT_FAST64_WIDTH__ 64 270 | #define __DEC64_MIN_EXP__ (-382) 271 | #define __cpp_decltype 200707 272 | #define __FLT32_DECIMAL_DIG__ 9 273 | #define __INT_FAST64_MAX__ 0x7fffffffffffffffLL 274 | #define __GCC_ATOMIC_TEST_AND_SET_TRUEVAL 1 275 | #define __FLT_DIG__ 6 276 | #define __FLT64X_MAX_EXP__ 16384 277 | #define __UINT_FAST64_TYPE__ long long unsigned int 278 | #define __INT_MAX__ 0x7fffffff 279 | #define WIN32 1 280 | #define __INT64_TYPE__ long long int 281 | #define __FLT_MAX_EXP__ 128 282 | #define __DBL_MANT_DIG__ 53 283 | #define __cpp_inheriting_constructors 201511 284 | #define __SIZEOF_FLOAT128__ 16 285 | #define __INT_LEAST64_MAX__ 0x7fffffffffffffffLL 286 | #define __DEC64_MIN__ 1E-383DD 287 | #define __WINT_TYPE__ short unsigned int 288 | #define __UINT_LEAST32_TYPE__ unsigned int 289 | #define __SIZEOF_SHORT__ 2 290 | #define __LDBL_MIN_EXP__ (-16381) 291 | #define __FLT64_MAX__ 1.79769313486231570814527423731704357e+308F64 292 | #define __WINT_WIDTH__ 16 293 | #define __INT_LEAST8_MAX__ 0x7f 294 | #define __FLT32X_MAX_10_EXP__ 308 295 | #define __WCHAR_UNSIGNED__ 1 296 | #define __LDBL_MAX_10_EXP__ 4932 297 | #define __ATOMIC_RELAXED 0 298 | #define __DBL_EPSILON__ double(2.22044604925031308084726333618164062e-16L) 299 | #define __thiscall __attribute__((__thiscall__)) 300 | #define __FLT128_MIN__ 3.36210314311209350626267781732175260e-4932F128 301 | #define __UINT8_C(c) c 302 | #define __FLT64_MAX_EXP__ 1024 303 | #define __INT_LEAST32_TYPE__ int 304 | #define __SIZEOF_WCHAR_T__ 2 305 | #define __FLT128_HAS_QUIET_NAN__ 1 306 | #define __INT_FAST8_TYPE__ signed char 307 | #define __fastcall __attribute__((__fastcall__)) 308 | #define __FLT64X_MIN__ 3.36210314311209350626267781732175260e-4932F64x 309 | #define __GNUC_STDC_INLINE__ 1 310 | #define __FLT64_HAS_DENORM__ 1 311 | #define __FLT32_EPSILON__ 1.19209289550781250000000000000000000e-7F32 312 | #define __DBL_DECIMAL_DIG__ 17 313 | #define __STDC_UTF_32__ 1 314 | #define __INT_FAST8_WIDTH__ 8 315 | #define __DEC_EVAL_METHOD__ 2 316 | #define __FLT32X_MAX__ 1.79769313486231570814527423731704357e+308F32x 317 | #define __ORDER_BIG_ENDIAN__ 4321 318 | #define __cpp_runtime_arrays 198712 319 | #define __UINT64_TYPE__ long long unsigned int 320 | #define __UINT32_C(c) c ## U 321 | #define __INTMAX_MAX__ 0x7fffffffffffffffLL 322 | #define __cpp_alias_templates 200704 323 | #define __BYTE_ORDER__ __ORDER_LITTLE_ENDIAN__ 324 | #define WINNT 1 325 | #define __FLT_DENORM_MIN__ 1.40129846432481707092372958328991613e-45F 326 | #define __INT8_MAX__ 0x7f 327 | #define __LONG_WIDTH__ 32 328 | #define __UINT_FAST32_TYPE__ unsigned int 329 | #define __CHAR32_TYPE__ unsigned int 330 | #define __FLT_MAX__ 3.40282346638528859811704183484516925e+38F 331 | #define __cpp_constexpr 200704 332 | #define __INT32_TYPE__ int 333 | #define __SIZEOF_DOUBLE__ 8 334 | #define __cpp_exceptions 199711 335 | #define __FLT_MIN_10_EXP__ (-37) 336 | #define __FLT64_MIN__ 2.22507385850720138309023271733240406e-308F64 337 | #define __INT_LEAST32_WIDTH__ 32 338 | #define __INTMAX_TYPE__ long long int 339 | #define i386 1 340 | #define _INTEGRAL_MAX_BITS 64 341 | #define __DEC128_MAX_EXP__ 6145 342 | #define __FLT32X_HAS_QUIET_NAN__ 1 343 | #define __ATOMIC_CONSUME 1 344 | #define __GNUC_MINOR__ 3 345 | #define __INT_FAST16_WIDTH__ 16 346 | #define __UINTMAX_MAX__ 0xffffffffffffffffULL 347 | #define __DEC32_MANT_DIG__ 7 348 | #define __FLT32X_DENORM_MIN__ 4.94065645841246544176568792868221372e-324F32x 349 | #define __DBL_MAX_10_EXP__ 308 350 | #define __LDBL_DENORM_MIN__ 3.64519953188247460252840593361941982e-4951L 351 | #define __INT16_C(c) c 352 | #define __STDC__ 1 353 | #define __FLT32X_DIG__ 15 354 | #define __PTRDIFF_TYPE__ int 355 | #define __ATOMIC_SEQ_CST 5 356 | #define __UINT32_TYPE__ unsigned int 357 | #define __FLT32X_MIN_10_EXP__ (-307) 358 | #define __UINTPTR_TYPE__ unsigned int 359 | #define __DEC64_SUBNORMAL_MIN__ 0.000000000000001E-383DD 360 | #define __DEC128_MANT_DIG__ 34 361 | #define __LDBL_MIN_10_EXP__ (-4931) 362 | #define __FLT128_EPSILON__ 1.92592994438723585305597794258492732e-34F128 363 | #define __SIZEOF_LONG_LONG__ 8 364 | #define __cpp_user_defined_literals 200809 365 | #define __FLT128_DECIMAL_DIG__ 36 366 | #define __GCC_ATOMIC_LLONG_LOCK_FREE 2 367 | #define __FLT32X_MIN__ 2.22507385850720138309023271733240406e-308F32x 368 | #define __LDBL_DIG__ 18 369 | #define __FLT_DECIMAL_DIG__ 9 370 | #define __UINT_FAST16_MAX__ 0xffff 371 | #define __GCC_ATOMIC_SHORT_LOCK_FREE 2 372 | #define __INT_LEAST64_WIDTH__ 64 373 | #define __UINT_FAST8_TYPE__ unsigned char 374 | #define __ATOMIC_ACQ_REL 4 375 | #define __ATOMIC_RELEASE 3 376 | #define __declspec(x) __attribute__((x)) 377 | -------------------------------------------------------------------------------- /第二次实验/build-regex2dfa-Desktop_Qt_5_12_12_MinGW_32_bit-Debug/ui_codedialog.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************** 2 | ** Form generated from reading UI file 'codedialog.ui' 3 | ** 4 | ** Created by: Qt User Interface Compiler version 5.12.12 5 | ** 6 | ** WARNING! All changes made in this file will be lost when recompiling UI file! 7 | ********************************************************************************/ 8 | 9 | #ifndef UI_CODEDIALOG_H 10 | #define UI_CODEDIALOG_H 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | QT_BEGIN_NAMESPACE 19 | 20 | class Ui_CodeDialog 21 | { 22 | public: 23 | QHBoxLayout *horizontalLayout; 24 | QTextBrowser *codeBrowser; 25 | 26 | void setupUi(QDialog *CodeDialog) 27 | { 28 | if (CodeDialog->objectName().isEmpty()) 29 | CodeDialog->setObjectName(QString::fromUtf8("CodeDialog")); 30 | CodeDialog->resize(648, 496); 31 | horizontalLayout = new QHBoxLayout(CodeDialog); 32 | horizontalLayout->setObjectName(QString::fromUtf8("horizontalLayout")); 33 | codeBrowser = new QTextBrowser(CodeDialog); 34 | codeBrowser->setObjectName(QString::fromUtf8("codeBrowser")); 35 | 36 | horizontalLayout->addWidget(codeBrowser); 37 | 38 | 39 | retranslateUi(CodeDialog); 40 | 41 | QMetaObject::connectSlotsByName(CodeDialog); 42 | } // setupUi 43 | 44 | void retranslateUi(QDialog *CodeDialog) 45 | { 46 | CodeDialog->setWindowTitle(QApplication::translate("CodeDialog", "Dialog", nullptr)); 47 | } // retranslateUi 48 | 49 | }; 50 | 51 | namespace Ui { 52 | class CodeDialog: public Ui_CodeDialog {}; 53 | } // namespace Ui 54 | 55 | QT_END_NAMESPACE 56 | 57 | #endif // UI_CODEDIALOG_H 58 | -------------------------------------------------------------------------------- /第二次实验/build-regex2dfa-Desktop_Qt_5_12_12_MinGW_32_bit-Debug/ui_mainwindow.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************** 2 | ** Form generated from reading UI file 'mainwindow.ui' 3 | ** 4 | ** Created by: Qt User Interface Compiler version 5.12.12 5 | ** 6 | ** WARNING! All changes made in this file will be lost when recompiling UI file! 7 | ********************************************************************************/ 8 | 9 | #ifndef UI_MAINWINDOW_H 10 | #define UI_MAINWINDOW_H 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | QT_BEGIN_NAMESPACE 28 | 29 | class Ui_MainWindow 30 | { 31 | public: 32 | QWidget *centralwidget; 33 | QGridLayout *gridLayout; 34 | QWidget *browserWidget; 35 | QVBoxLayout *verticalLayout_5; 36 | QTextBrowser *textBrowser; 37 | QWidget *titleWidget; 38 | QVBoxLayout *verticalLayout_4; 39 | QLabel *title; 40 | QWidget *buttonWidget; 41 | QVBoxLayout *verticalLayout_2; 42 | QPushButton *analysisPushButton; 43 | QPushButton *nfaPushButton; 44 | QPushButton *dfaPushButton; 45 | QPushButton *minimumDfaPushButton; 46 | QPushButton *codePushButton; 47 | QPushButton *resetPushButton; 48 | QWidget *textWidget; 49 | QVBoxLayout *verticalLayout; 50 | QLabel *label; 51 | QTextEdit *textEdit; 52 | QWidget *mainWidget; 53 | QVBoxLayout *verticalLayout_3; 54 | QLabel *labelOfTable; 55 | QTableWidget *tableWidget; 56 | QMenuBar *menubar; 57 | QStatusBar *statusbar; 58 | 59 | void setupUi(QMainWindow *MainWindow) 60 | { 61 | if (MainWindow->objectName().isEmpty()) 62 | MainWindow->setObjectName(QString::fromUtf8("MainWindow")); 63 | MainWindow->resize(800, 600); 64 | centralwidget = new QWidget(MainWindow); 65 | centralwidget->setObjectName(QString::fromUtf8("centralwidget")); 66 | gridLayout = new QGridLayout(centralwidget); 67 | gridLayout->setObjectName(QString::fromUtf8("gridLayout")); 68 | browserWidget = new QWidget(centralwidget); 69 | browserWidget->setObjectName(QString::fromUtf8("browserWidget")); 70 | verticalLayout_5 = new QVBoxLayout(browserWidget); 71 | verticalLayout_5->setObjectName(QString::fromUtf8("verticalLayout_5")); 72 | textBrowser = new QTextBrowser(browserWidget); 73 | textBrowser->setObjectName(QString::fromUtf8("textBrowser")); 74 | QFont font; 75 | font.setFamily(QString::fromUtf8("\345\256\213\344\275\223")); 76 | font.setPointSize(10); 77 | textBrowser->setFont(font); 78 | textBrowser->setLineWrapColumnOrWidth(1); 79 | 80 | verticalLayout_5->addWidget(textBrowser); 81 | 82 | 83 | gridLayout->addWidget(browserWidget, 2, 1, 1, 1); 84 | 85 | titleWidget = new QWidget(centralwidget); 86 | titleWidget->setObjectName(QString::fromUtf8("titleWidget")); 87 | verticalLayout_4 = new QVBoxLayout(titleWidget); 88 | verticalLayout_4->setObjectName(QString::fromUtf8("verticalLayout_4")); 89 | title = new QLabel(titleWidget); 90 | title->setObjectName(QString::fromUtf8("title")); 91 | QSizePolicy sizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); 92 | sizePolicy.setHorizontalStretch(0); 93 | sizePolicy.setVerticalStretch(0); 94 | sizePolicy.setHeightForWidth(title->sizePolicy().hasHeightForWidth()); 95 | title->setSizePolicy(sizePolicy); 96 | QFont font1; 97 | font1.setFamily(QString::fromUtf8("Times New Roman")); 98 | font1.setPointSize(18); 99 | title->setFont(font1); 100 | title->setAlignment(Qt::AlignCenter); 101 | 102 | verticalLayout_4->addWidget(title); 103 | 104 | buttonWidget = new QWidget(titleWidget); 105 | buttonWidget->setObjectName(QString::fromUtf8("buttonWidget")); 106 | buttonWidget->setMaximumSize(QSize(16777215, 16777215)); 107 | verticalLayout_2 = new QVBoxLayout(buttonWidget); 108 | verticalLayout_2->setObjectName(QString::fromUtf8("verticalLayout_2")); 109 | analysisPushButton = new QPushButton(buttonWidget); 110 | analysisPushButton->setObjectName(QString::fromUtf8("analysisPushButton")); 111 | 112 | verticalLayout_2->addWidget(analysisPushButton); 113 | 114 | nfaPushButton = new QPushButton(buttonWidget); 115 | nfaPushButton->setObjectName(QString::fromUtf8("nfaPushButton")); 116 | 117 | verticalLayout_2->addWidget(nfaPushButton); 118 | 119 | dfaPushButton = new QPushButton(buttonWidget); 120 | dfaPushButton->setObjectName(QString::fromUtf8("dfaPushButton")); 121 | 122 | verticalLayout_2->addWidget(dfaPushButton); 123 | 124 | minimumDfaPushButton = new QPushButton(buttonWidget); 125 | minimumDfaPushButton->setObjectName(QString::fromUtf8("minimumDfaPushButton")); 126 | 127 | verticalLayout_2->addWidget(minimumDfaPushButton); 128 | 129 | codePushButton = new QPushButton(buttonWidget); 130 | codePushButton->setObjectName(QString::fromUtf8("codePushButton")); 131 | 132 | verticalLayout_2->addWidget(codePushButton); 133 | 134 | resetPushButton = new QPushButton(buttonWidget); 135 | resetPushButton->setObjectName(QString::fromUtf8("resetPushButton")); 136 | 137 | verticalLayout_2->addWidget(resetPushButton); 138 | 139 | 140 | verticalLayout_4->addWidget(buttonWidget); 141 | 142 | 143 | gridLayout->addWidget(titleWidget, 0, 0, 1, 1); 144 | 145 | textWidget = new QWidget(centralwidget); 146 | textWidget->setObjectName(QString::fromUtf8("textWidget")); 147 | textWidget->setMinimumSize(QSize(0, 0)); 148 | verticalLayout = new QVBoxLayout(textWidget); 149 | verticalLayout->setObjectName(QString::fromUtf8("verticalLayout")); 150 | label = new QLabel(textWidget); 151 | label->setObjectName(QString::fromUtf8("label")); 152 | label->setAlignment(Qt::AlignCenter); 153 | 154 | verticalLayout->addWidget(label); 155 | 156 | textEdit = new QTextEdit(textWidget); 157 | textEdit->setObjectName(QString::fromUtf8("textEdit")); 158 | 159 | verticalLayout->addWidget(textEdit); 160 | 161 | 162 | gridLayout->addWidget(textWidget, 2, 0, 1, 1); 163 | 164 | mainWidget = new QWidget(centralwidget); 165 | mainWidget->setObjectName(QString::fromUtf8("mainWidget")); 166 | mainWidget->setMinimumSize(QSize(0, 0)); 167 | mainWidget->setMaximumSize(QSize(16777215, 16777215)); 168 | verticalLayout_3 = new QVBoxLayout(mainWidget); 169 | verticalLayout_3->setObjectName(QString::fromUtf8("verticalLayout_3")); 170 | labelOfTable = new QLabel(mainWidget); 171 | labelOfTable->setObjectName(QString::fromUtf8("labelOfTable")); 172 | labelOfTable->setAlignment(Qt::AlignCenter); 173 | 174 | verticalLayout_3->addWidget(labelOfTable); 175 | 176 | tableWidget = new QTableWidget(mainWidget); 177 | tableWidget->setObjectName(QString::fromUtf8("tableWidget")); 178 | 179 | verticalLayout_3->addWidget(tableWidget); 180 | 181 | 182 | gridLayout->addWidget(mainWidget, 0, 1, 1, 1); 183 | 184 | MainWindow->setCentralWidget(centralwidget); 185 | menubar = new QMenuBar(MainWindow); 186 | menubar->setObjectName(QString::fromUtf8("menubar")); 187 | menubar->setGeometry(QRect(0, 0, 800, 21)); 188 | MainWindow->setMenuBar(menubar); 189 | statusbar = new QStatusBar(MainWindow); 190 | statusbar->setObjectName(QString::fromUtf8("statusbar")); 191 | MainWindow->setStatusBar(statusbar); 192 | 193 | retranslateUi(MainWindow); 194 | 195 | QMetaObject::connectSlotsByName(MainWindow); 196 | } // setupUi 197 | 198 | void retranslateUi(QMainWindow *MainWindow) 199 | { 200 | MainWindow->setWindowTitle(QApplication::translate("MainWindow", "MainWindow", nullptr)); 201 | textBrowser->setHtml(QApplication::translate("MainWindow", "\n" 202 | "\n" 205 | "

Regex2DFA\346\230\257\351\200\232\350\277\207\350\276\223\345\205\245\346\255\243\345\210\231\350\241\250\350\276\276\345\274\217\347\273\204\357\274\214\345\260\206\344\273\245"_"\345\274\200\345\244\264\347\232\204\345\217\230\351\207\217\346\211\200\344\273\243\350\241\250\347\232\204\346\255\243\345\210\231\350\241\250\350\276\276\345\274\217\350\275\254\346\215\242\344\270\272NFA\343\200\201DFA\343\200" 206 | "\201\346\234\200\345\260\217\345\214\226DFA\347\232\204\350\275\257\344\273\266\343\200\202

\n" 207 | "

\357\274\210\344\273\245\347\273\277\350\211\262\346\240\207\350\256\260\345\247\213\346\200\201\357\274\214\344\273\245\347\272\242\350\211\262\346\240\207\350\256\260\347\273\210\346\200\201\357\274\211

\n" 208 | "


\n" 209 | "

\345\205\266\344\270\255\357\274\214\350\275\257\344\273\266\345\256\236\347\216\260\344\272\206\357\274\232

\n" 211 | "

1. \345\210\206\346\236\220\357\274\210\345\267\246\344\276\247\347\254\254\344\270\200\344\270\252\346\214\211\351\222\256\357\274\214\346\214\211\344\270\213\350\257\245\346\214\211\351\222\256\345\220\216\345\217\257\344\273\245\351\200\232\350\277\207\347\202\271\345\207\273\345\267\246\344\276\2472\343\200\2013\343\200\2014\346\214\211\351\222\256\346\230\276\347\244\272\344\270\215\345\220\214\345\206\205\345\256\271\357\274\211

\n" 212 | "" 213 | "

2. \346\255\243\345\210\231\350\241\250\350\276\276\345\274\217\350\275\254\344\270\272NFA\357\274\210\345\267\246\344\276\247\347\254\254\344\272\214\344\270\252\346\214\211\351\222\256\357\274\211

\n" 214 | "

3. NFA\350\275\254\344\270\272DFA\357\274\210\345\267\246\344\276\247\347\254\254\344\270\211\344\270\252\346\214\211\351\222\256\357\274\211

\n" 215 | "

4. DFA\346\234\200\345\260\217\345\214\226\357\274\210\345\267\246\344\276\247\347\254\254\345\233\233\344\270\252\346\214\211\351\222\256\357\274\211

\n" 217 | "

5. \351\207\215\347\275\256\357\274\210\345\217\257\344\273\245\351\207\215\346\226\260\350\276\223\345\205\245\346\255\243\345\210\231\350\241\250\350\276\276\345\274\217\357\274\211

\n" 218 | "

\347\202\271\345\207\273\345\210\206\346\236\220\346\214\211\351\222\256\357\274\214\345\256\236\347\216\260\346\255\243\345\210\231\350\241\250\350\276\276\345\274\217->NFA->DFA->\346\234\200\345\260\217\345\214\226DFA

\n" 220 | "


\n" 221 | "

\346\263\250\357\274\232
1. \350\276\223\345\205\245\345\217\252\350\203\275\345\214\205\345\220\253\344\270\200\344\270\252\344\273\245"_"\345\274\200\345\244\264\347\232\204\346\255\243\345\210\231\350\241\250\350\276\276\345\274\217\357\274\214\345\220\246\345" 222 | "\210\231\350\275\257\344\273\266\345\217\257\350\203\275\344\274\232\345\207\272\347\216\260\350\257\257\350\247\243\357\274\214\344\272\247\347\224\237\344\270\215\346\255\243\347\241\256\347\232\204NFA\343\200\201DFA\347\255\211\357\274\233
2. \347\255\211\345\217\267\345\267\246\344\276\247\347\232\204\346\240\207\350\257\206\347\254\246\344\273\205\345\214\205\345\220\253\345\255\227\346\257\215\343\200\201\346\225\260\345\255\227\344\270\216\344\270\213\345\210\222\347\272\277

\n" 223 | "

3. \350\275\257\344\273\266\344\273\245#\345\255\227\347\254\246\344\275\234\344\270\272NFA\350\275\254\346\215\242\347\232\204epsilon\346\240\207\350\257\206\357\274\214\345\233\240\346\255\244\357\274\214\345\270\214\346\234\233\350\276\223\345\205\245#\345\255\227\347\254\246\357\274\214\345\272\224\345\275\223\344\275\277\347\224\250\350" 224 | "\275\254\344\271\211\347\254\246\345\217\267\357\274\214\350\276\223\345\205\245\\#\346\211\215\345\217\257\344\273\245\350\257\206\345\210\253\343\200\202

\n" 225 | "


\n" 226 | "

\350\276\203\351\225\277\347\232\204\346\255\243\345\210\231\350\241\250\350\276\276\345\274\217\345\217\257\350\203\275\344\274\232\345\210\206\346\236\220\350\276\203\344\271\205\357\274\214\350\257\267\346\202\250\350\200\220\345\277\203\347\255\211\345\276\205\357\274\214\350\260\242\350\260\242\343\200\202

", nullptr)); 227 | title->setText(QApplication::translate("MainWindow", "Regex2DFA", nullptr)); 228 | analysisPushButton->setText(QApplication::translate("MainWindow", "\345\210\206\346\236\220", nullptr)); 229 | nfaPushButton->setText(QApplication::translate("MainWindow", "\346\230\276\347\244\272NFA", nullptr)); 230 | dfaPushButton->setText(QApplication::translate("MainWindow", "\346\230\276\347\244\272DFA", nullptr)); 231 | minimumDfaPushButton->setText(QApplication::translate("MainWindow", "\346\234\200\345\260\217\345\214\226DFA", nullptr)); 232 | codePushButton->setText(QApplication::translate("MainWindow", "\347\224\237\346\210\220\345\214\271\351\205\215\344\273\243\347\240\201", nullptr)); 233 | resetPushButton->setText(QApplication::translate("MainWindow", "\351\207\215\347\275\256\347\250\213\345\272\217", nullptr)); 234 | label->setText(QApplication::translate("MainWindow", "\350\257\267\345\234\250\344\270\213\346\226\271\346\241\206\344\270\255\345\206\231\345\205\245\346\255\243\345\210\231\350\241\250\350\276\276\345\274\217", nullptr)); 235 | labelOfTable->setText(QApplication::translate("MainWindow", "NFA\343\200\201DFA\345\261\225\347\244\272\350\241\250", nullptr)); 236 | } // retranslateUi 237 | 238 | }; 239 | 240 | namespace Ui { 241 | class MainWindow: public Ui_MainWindow {}; 242 | } // namespace Ui 243 | 244 | QT_END_NAMESPACE 245 | 246 | #endif // UI_MAINWINDOW_H 247 | -------------------------------------------------------------------------------- /第二次实验/regex2dfa/codedialog.cpp: -------------------------------------------------------------------------------- 1 | #include "codedialog.h" 2 | #include "ui_codedialog.h" 3 | 4 | #include 5 | #include 6 | 7 | CodeDialog::CodeDialog(QWidget *parent, QString code) : 8 | QDialog(parent), 9 | ui(new Ui::CodeDialog) 10 | { 11 | ui->setupUi(this); 12 | ui->codeBrowser->setText(code); 13 | 14 | this->setWindowTitle("匹配代码"); 15 | QScreen *screen = QGuiApplication::primaryScreen(); 16 | QRect screenGeometry = screen->geometry(); 17 | int screenWidth = screenGeometry.width(); 18 | int screenHeight = screenGeometry.height(); 19 | int newWidth = screenWidth * 0.6; 20 | int newHeight = screenHeight * 0.6; 21 | this->resize(newWidth, newHeight); 22 | } 23 | 24 | CodeDialog::~CodeDialog() 25 | { 26 | delete ui; 27 | } 28 | -------------------------------------------------------------------------------- /第二次实验/regex2dfa/codedialog.h: -------------------------------------------------------------------------------- 1 | #ifndef CODEDIALOG_H 2 | #define CODEDIALOG_H 3 | 4 | #include 5 | 6 | namespace Ui { 7 | class CodeDialog; 8 | } 9 | 10 | class CodeDialog : public QDialog 11 | { 12 | Q_OBJECT 13 | 14 | public: 15 | explicit CodeDialog(QWidget *parent = nullptr, QString code = ""); 16 | ~CodeDialog(); 17 | 18 | private: 19 | Ui::CodeDialog *ui; 20 | }; 21 | 22 | #endif // CODEDIALOG_H 23 | -------------------------------------------------------------------------------- /第二次实验/regex2dfa/codedialog.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | CodeDialog 4 | 5 | 6 | 7 | 0 8 | 0 9 | 648 10 | 496 11 | 12 | 13 | 14 | Dialog 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /第二次实验/regex2dfa/dfa.cpp: -------------------------------------------------------------------------------- 1 | #include "dfa.h" 2 | 3 | #include 4 | #include 5 | 6 | DFA::DFA() 7 | { 8 | 9 | } 10 | 11 | void DFA::fromNFA(NFA nfa) 12 | { 13 | QHash, int> revMapping; 14 | // 获取始态 15 | QSet startSet; 16 | startSet.insert(nfa.startState); 17 | startSet = nfa.epsilonClosure(startSet); 18 | mapping[startState] = startSet; 19 | revMapping[startSet] = startState; 20 | if (startSet.contains(nfa.endState)) { 21 | endStates.insert(startState); 22 | } 23 | stateNum++; 24 | 25 | QSet> vis; // 判断某个状态是否被找到 26 | QQueue q; // 循环队列 27 | q.push_back(startState); 28 | while (!q.empty()) { 29 | 30 | // 取出队头 31 | int stateItem = q.front(); 32 | q.pop_front(); 33 | QSet nfaStateSet = mapping[stateItem]; 34 | 35 | // 未曾出现过的状态集合才需要查找 36 | if (!vis.contains(nfaStateSet)) { 37 | 38 | // 查询当前状态集合的转移 39 | for (QString changeItem: nfa.stateSet) { 40 | if (changeItem != "epsilon") { 41 | 42 | // 获取对应转移到的epsilon闭包 43 | QSet changeClosure = nfa.valueClosure(nfaStateSet, changeItem); 44 | QSet changeEpsilon = nfa.epsilonClosure(changeClosure); 45 | 46 | // 找不到集合 47 | if (changeEpsilon.empty()) continue; 48 | 49 | // 之前找到过这个状态 50 | if (revMapping.contains(changeEpsilon)) { 51 | int nextItem = revMapping[changeEpsilon]; 52 | 53 | G[stateItem][changeItem] = nextItem; 54 | if (changeEpsilon.contains(nfa.endState)) { 55 | endStates.insert(nextItem); 56 | } 57 | 58 | if (!vis.contains(changeEpsilon)) { 59 | q.push_back(nextItem); 60 | } 61 | } else { 62 | int nextItem = stateNum; 63 | mapping[nextItem] = changeEpsilon; 64 | revMapping[changeEpsilon] = nextItem; 65 | 66 | G[stateItem][changeItem] = nextItem; 67 | if (changeEpsilon.contains(nfa.endState)) { 68 | endStates.insert(nextItem); 69 | } 70 | stateNum++; 71 | 72 | if (!vis.contains(changeEpsilon)) { 73 | q.push_back(nextItem); 74 | } 75 | } 76 | } 77 | } 78 | vis.insert(nfaStateSet); 79 | } 80 | } 81 | } 82 | 83 | void DFA::fromDFA(DFA dfa) 84 | { 85 | QSet notEndStates; 86 | for (int i = 0; i < dfa.stateNum; i++) { 87 | if (!dfa.endStates.contains(i)) { 88 | notEndStates.insert(i); 89 | } 90 | } 91 | 92 | // 找到原始DFA的转移类型 93 | QSet stateSet; 94 | for (int i = 0; i < dfa.stateNum; i++) { 95 | for (QString changeItem: dfa.G[i].keys()) { 96 | stateSet.insert(changeItem); 97 | } 98 | } 99 | 100 | QQueue> q; 101 | if (!notEndStates.empty()) q.push_back(notEndStates); 102 | if (!dfa.endStates.empty()) q.push_back(dfa.endStates); 103 | 104 | int lastQueLen = 0, cnt = 0; 105 | if (!notEndStates.empty()) lastQueLen++; 106 | if (!dfa.endStates.empty()) lastQueLen++; 107 | 108 | while (true) { 109 | 110 | QSet stateItem = q.front(); 111 | 112 | // 划分集合 113 | bool flag = true; 114 | for (QString changeItem: stateSet) { 115 | QSet> vis; 116 | QHash, QSet> setHash; // 当前选出 117 | for (int beginItem: stateItem) { 118 | if (!dfa.G.contains(beginItem)) continue; 119 | if (!dfa.G[beginItem].contains(changeItem)) { 120 | vis.insert(QSet()); 121 | setHash[QSet()].insert(beginItem); 122 | continue; 123 | } 124 | for (QSet queueItem: q) { 125 | if (queueItem.contains(dfa.G[beginItem][changeItem])){ 126 | vis.insert(queueItem); 127 | setHash[queueItem].insert(beginItem); 128 | break; 129 | } 130 | } 131 | } 132 | if (vis.size() <= 1) { 133 | continue; 134 | } else { 135 | for (QSet visItem: vis) { 136 | q.push_back(setHash[visItem]); 137 | } 138 | flag = false; 139 | break; 140 | } 141 | } 142 | 143 | q.pop_front(); 144 | if (flag) q.push_back(stateItem); 145 | 146 | // 判断“上一个”队列是否全被扫过一次 147 | cnt++; 148 | if (lastQueLen == cnt) { 149 | if (lastQueLen == q.size()) { 150 | break; 151 | } 152 | lastQueLen = q.size(); 153 | cnt = 0; 154 | } 155 | } 156 | 157 | int idx = 0; 158 | // 设置新编号 159 | QHash, int> revMapping; 160 | for (QSet queueItem: q) { 161 | if (queueItem.empty()) continue; 162 | mapping[idx] = queueItem; 163 | revMapping[queueItem] = idx; 164 | idx++; 165 | } 166 | stateNum = idx; 167 | 168 | // 找到始态和终态 169 | for (QSet queueItem: q) { 170 | if (queueItem.empty()) continue; 171 | // 找始态 172 | if (queueItem.contains(dfa.startState)) { 173 | startState = revMapping[queueItem]; 174 | } 175 | // 找终态 176 | for (int endState: dfa.endStates) { 177 | if (queueItem.contains(endState)) { 178 | endStates.insert(revMapping[queueItem]); 179 | break; 180 | } 181 | } 182 | } 183 | 184 | // 构建新的G 185 | for (QSet queueItem: q) { 186 | if (queueItem.empty()) continue; 187 | int stateItem = *queueItem.begin(); 188 | for (QString changeItem: stateSet) { 189 | if (!dfa.G[stateItem].contains(changeItem)) continue; 190 | int endItem = dfa.G[stateItem][changeItem]; 191 | for (QSet endQueueItem: q) { 192 | if (endQueueItem.contains(endItem)) { 193 | G[revMapping[queueItem]][changeItem] = revMapping[endQueueItem]; 194 | break; 195 | } 196 | } 197 | } 198 | } 199 | } 200 | 201 | void DFA::clear() 202 | { 203 | mapping.clear(); 204 | G.clear(); 205 | endStates.clear(); 206 | stateNum = 0; 207 | startState = 0; 208 | } 209 | 210 | QString DFA::toCode() 211 | { 212 | QString code = "bool matchFunction(string s) {\n"; 213 | code += "\tint idx = 0, state = "; 214 | code += QString::number(startState) + ";\n"; 215 | code += "\twhile (state < " + QString::number(stateNum) + " && idx < s.size()) {\n"; 216 | code += "\t\tswitch (state) {\n"; 217 | for (int i = 0; i < stateNum; i++) { 218 | if (G[i].keys().empty()) continue; 219 | code += "\t\tcase " + QString::number(i) + ":\n"; 220 | code += "\t\t\tswitch (s[idx]) {\n"; 221 | for (QString changeItem: G[i].keys()) { 222 | code += "\t\t\tcase \'" + changeItem + "\':\n"; 223 | code += "\t\t\t\tstate = " + QString::number(G[i][changeItem]) + ";\n"; 224 | code += "\t\t\t\tbreak;\n"; 225 | } 226 | code += "\t\t\tdefault:\n"; 227 | code += "\t\t\t\tstate = " + QString::number(stateNum) + ";\n"; 228 | code += "\t\t\t\tbreak;\n"; 229 | code += "\t\t\t}\n"; 230 | code += "\t\t\tbreak;\n"; 231 | } 232 | code += "\t\tdefault:\n"; 233 | code += "\t\t\tstate = " + QString::number(stateNum) + ";\n"; 234 | code += "\t\t\tbreak;\n"; 235 | code += "\t\t}\n"; 236 | code += "\t\tidx++\n"; 237 | code += "\t}\n"; 238 | code += "\tif ("; 239 | int cnt = 0; 240 | for (int i: endStates) { 241 | code += "state == " + QString::number(i); 242 | cnt++; 243 | if (cnt != endStates.size()) code += "||"; 244 | } 245 | code += ") return true;\n"; 246 | code += "\telse return false;\n"; 247 | code += "}"; 248 | return code; 249 | } 250 | -------------------------------------------------------------------------------- /第二次实验/regex2dfa/dfa.h: -------------------------------------------------------------------------------- 1 | #ifndef DFA_H 2 | #define DFA_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "nfa.h" 10 | 11 | class DFA 12 | { 13 | public: 14 | DFA(); 15 | void fromNFA(NFA nfa); 16 | void fromDFA(DFA dfa); 17 | void clear(); 18 | QString toCode(); 19 | 20 | QHash> mapping; 21 | QHash> G; 22 | int startState; 23 | QSet endStates; 24 | int stateNum; // 表示状态数量 25 | 26 | }; 27 | 28 | #endif // DFA_H 29 | -------------------------------------------------------------------------------- /第二次实验/regex2dfa/main.cpp: -------------------------------------------------------------------------------- 1 | #include "mainwindow.h" 2 | 3 | #include 4 | 5 | int main(int argc, char *argv[]) 6 | { 7 | QApplication a(argc, argv); 8 | MainWindow w; 9 | w.show(); 10 | return a.exec(); 11 | } 12 | -------------------------------------------------------------------------------- /第二次实验/regex2dfa/mainwindow.cpp: -------------------------------------------------------------------------------- 1 | #include "mainwindow.h" 2 | #include "ui_mainwindow.h" 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include "utils.h" 15 | #include "nfa.h" 16 | #include "dfa.h" 17 | #include "codedialog.h" 18 | 19 | MainWindow::MainWindow(QWidget *parent) 20 | : QMainWindow(parent) 21 | , ui(new Ui::MainWindow) 22 | , nfa() 23 | { 24 | ui->setupUi(this); 25 | 26 | // 页面基本布局 27 | this->setWindowTitle("编译原理实验二:正则表达式转NFA、DFA"); 28 | QScreen *screen = QGuiApplication::primaryScreen(); 29 | QRect screenGeometry = screen->geometry(); 30 | int screenWidth = screenGeometry.width(); 31 | int screenHeight = screenGeometry.height(); 32 | int newWidth = screenWidth * 0.9; 33 | int newHeight = screenHeight * 0.9; 34 | this->resize(newWidth, newHeight); 35 | 36 | // 分析并产生NFA、DFA、最小化DFA 37 | connect(ui->analysisPushButton, &QPushButton::clicked, this, [=]() { 38 | this->nfa.clear(); 39 | this->dfa.clear(); 40 | this->miniDFA.clear(); 41 | this->code = ""; 42 | tableRemoveAll(); 43 | 44 | QString allText = ui->textEdit->toPlainText(); 45 | if (allText != "") { 46 | 47 | QStringList lines = allText.split('\n', QString::SkipEmptyParts); 48 | 49 | // 预处理正则表达式组 50 | QString mainRegex = regexListPreprocessing(lines); 51 | 52 | // 正则表达式转后缀表达式 53 | QString postFixRegex = regexToPostFix(mainRegex); 54 | 55 | // 后缀表达式转NFA 56 | this->nfa.fromRegex(postFixRegex); 57 | 58 | // NFA转DFA 59 | this->dfa.fromNFA(this->nfa); 60 | 61 | // DFA最小化 62 | this->miniDFA.fromDFA(this->dfa); 63 | 64 | // 转换为代码 65 | this->code = this->miniDFA.toCode(); 66 | } 67 | 68 | }); 69 | 70 | // 显示NFA 71 | connect(ui->nfaPushButton, &QPushButton::clicked, this, [=]() { 72 | // 清空原来的表格 73 | tableRemoveAll(); 74 | 75 | ui->tableWidget->setRowCount(nfa.stateNum); 76 | ui->tableWidget->setColumnCount(nfa.stateSet.size()); 77 | QStringList strListColumnHander; 78 | for (QString item : nfa.stateSet) { 79 | strListColumnHander << tr(item.toStdString().c_str()); 80 | } 81 | ui->tableWidget->setHorizontalHeaderLabels(strListColumnHander); 82 | QStringList strListRowHander; 83 | for (int i = 0; i < nfa.stateNum; i++) { 84 | strListRowHander << tr(QString::number(i).toStdString().c_str()); 85 | } 86 | ui->tableWidget->setVerticalHeaderLabels(strListRowHander); 87 | for (int i = 0; i < nfa.stateNum; i++) { 88 | int j = 0; 89 | for (QString stateChange: nfa.stateSet) { 90 | QString itemString = ""; 91 | for (int k = 0; k < nfa.stateNum; k++) { 92 | if (nfa.G[i][k] == stateChange) { 93 | itemString += QString::number(k); 94 | itemString += ","; 95 | } 96 | } 97 | ui->tableWidget->setItem(i, j, new QTableWidgetItem(itemString.left(itemString.size() - 1))); 98 | j++; 99 | } 100 | } 101 | 102 | // 添加始态、终态颜色 103 | QTableWidgetItem *beginItem = ui->tableWidget->verticalHeaderItem(nfa.startState); 104 | QTableWidgetItem *endItem = ui->tableWidget->verticalHeaderItem(nfa.endState); 105 | beginItem->setTextColor(QColor(0, 255, 0)); 106 | endItem->setTextColor(QColor(255, 0, 0)); 107 | }); 108 | 109 | // 显示DFA 110 | connect(ui->dfaPushButton, &QPushButton::clicked, this, [=]() { 111 | // 清空原来的表格 112 | tableRemoveAll(); 113 | 114 | ui->tableWidget->setRowCount(dfa.stateNum); 115 | ui->tableWidget->setColumnCount(nfa.stateSet.size() - (nfa.stateSet.contains("epsilon") ? 1 : 0)); 116 | 117 | QStringList strListColumnHander; 118 | for (QString item : nfa.stateSet) { 119 | if (item == "epsilon") continue; 120 | strListColumnHander << tr(item.toStdString().c_str()); 121 | } 122 | ui->tableWidget->setHorizontalHeaderLabels(strListColumnHander); 123 | 124 | QStringList strListRowHander; 125 | for (int i = 0; i < dfa.stateNum; i++) { 126 | strListRowHander << tr(QString::number(i).toStdString().c_str()); 127 | } 128 | ui->tableWidget->setVerticalHeaderLabels(strListRowHander); 129 | 130 | for (int i = 0; i < dfa.stateNum; i++) { 131 | if (!dfa.G.contains(i)) continue; 132 | int j = 0; 133 | for (QString stateChange: nfa.stateSet) { 134 | if (stateChange == "epsilon") continue; 135 | if (dfa.G[i].contains(stateChange)) { 136 | 137 | int k = dfa.G[i][stateChange]; 138 | QString titleTr = QString::number(k) + ":{"; 139 | for (int item: dfa.mapping[k]) { 140 | titleTr += QString::number(item); 141 | titleTr += ","; 142 | } 143 | titleTr = titleTr.left(titleTr.size() - 1); 144 | titleTr += "}"; 145 | 146 | ui->tableWidget->setItem(i, j, new QTableWidgetItem(titleTr)); 147 | } 148 | j++; 149 | } 150 | } 151 | 152 | // 添加始态、终态颜色 153 | QTableWidgetItem *beginItem = ui->tableWidget->verticalHeaderItem(dfa.startState); 154 | beginItem->setTextColor(QColor(0, 255, 0)); 155 | for (int endState: dfa.endStates) { 156 | QTableWidgetItem *endItem = ui->tableWidget->verticalHeaderItem(endState); 157 | endItem->setTextColor(QColor(255, 0, 0)); 158 | } 159 | 160 | }); 161 | 162 | // 显示最小化的DFA 163 | connect(ui->minimumDfaPushButton, &QPushButton::clicked, this, [=]() { 164 | // 清空原来的表格 165 | tableRemoveAll(); 166 | 167 | ui->tableWidget->setRowCount(miniDFA.stateNum); 168 | ui->tableWidget->setColumnCount(nfa.stateSet.size() - (nfa.stateSet.contains("epsilon") ? 1 : 0)); 169 | 170 | QStringList strListColumnHander; 171 | for (QString item : nfa.stateSet) { 172 | if (item == "epsilon") continue; 173 | strListColumnHander << tr(item.toStdString().c_str()); 174 | } 175 | ui->tableWidget->setHorizontalHeaderLabels(strListColumnHander); 176 | 177 | QStringList strListRowHander; 178 | for (int i = 0; i < miniDFA.stateNum; i++) { 179 | strListRowHander << tr(QString::number(i).toStdString().c_str()); 180 | } 181 | ui->tableWidget->setVerticalHeaderLabels(strListRowHander); 182 | 183 | for (int i = 0; i < miniDFA.stateNum; i++) { 184 | if (!miniDFA.G.contains(i)) continue; 185 | int j = 0; 186 | for (QString stateChange: nfa.stateSet) { 187 | if (stateChange == "epsilon") continue; 188 | if (miniDFA.G[i].contains(stateChange)) { 189 | 190 | int k = miniDFA.G[i][stateChange]; 191 | QString titleTr = QString::number(k) + ":{"; 192 | for (int item: miniDFA.mapping[k]) { 193 | titleTr += QString::number(item); 194 | titleTr += ","; 195 | } 196 | titleTr = titleTr.left(titleTr.size() - 1); 197 | titleTr += "}"; 198 | 199 | ui->tableWidget->setItem(i, j, new QTableWidgetItem(titleTr)); 200 | } 201 | j++; 202 | } 203 | } 204 | 205 | // 添加始态、终态颜色 206 | QTableWidgetItem *beginItem = ui->tableWidget->verticalHeaderItem(miniDFA.startState); 207 | beginItem->setTextColor(QColor(0, 255, 0)); 208 | for (int endState: miniDFA.endStates) { 209 | QTableWidgetItem *endItem = ui->tableWidget->verticalHeaderItem(endState); 210 | endItem->setTextColor(QColor(255, 0, 0)); 211 | } 212 | }); 213 | 214 | // 生成匹配代码 215 | connect(ui->codePushButton, &QPushButton::clicked, this, [=]() { 216 | CodeDialog* codeDialog = new CodeDialog(this, code); 217 | codeDialog->exec(); 218 | }); 219 | 220 | // 重置程序 221 | connect(ui->resetPushButton, &QPushButton::clicked, this, [=]() { 222 | this->nfa.clear(); 223 | this->dfa.clear(); 224 | this->miniDFA.clear(); 225 | this->code = ""; 226 | tableRemoveAll(); 227 | }); 228 | 229 | } 230 | 231 | MainWindow::~MainWindow() 232 | { 233 | delete ui; 234 | } 235 | 236 | QString MainWindow::regexListPreprocessing(QStringList regexList) { 237 | int lineSize = regexList.size(); 238 | 239 | // 去除所有空格 240 | for (int i = 0; i < lineSize; i++) { 241 | regexList[i].replace(" ", ""); 242 | } 243 | 244 | // 替换[] 245 | for (int i = 0; i < lineSize; i++) { 246 | int leftBracket = -1; // 左右括号位置 247 | for (int j = 0; j < regexList[i].size(); j++) { 248 | if (regexList[i][j] == '\\') { // 转义字符 249 | j++; 250 | } else if (regexList[i][j] == '[') { // 匹配左括号 251 | leftBracket = j; 252 | } else if (regexList[i][j] == ']') { 253 | if (leftBracket == -1) { // 出现了右括号,但没有出现左括号 254 | continue; 255 | } else { 256 | if (leftBracket == j - 1) continue; // 特判一下 257 | QString bracketString = regexList[i].mid(leftBracket + 1, j - leftBracket - 1); 258 | QString newBracketString = ""; 259 | int bracketLen = bracketString.size(); 260 | int groupNum = bracketLen / 3; 261 | for (int k = 0; k < groupNum; k++) { 262 | int beginIndex = 3 * k; 263 | int endIndex = 3 * k + 2; 264 | for (char l = bracketString[beginIndex].unicode(); l <= bracketString[endIndex].unicode(); l++) { 265 | newBracketString.append(l); 266 | newBracketString.append('|'); 267 | } 268 | } 269 | if (groupNum != 0) { 270 | // 替换字符串 271 | int newBracketStringLen = newBracketString.size(); 272 | newBracketString = newBracketString.mid(0, newBracketStringLen - 1); 273 | regexList[i] = regexList[i].left(leftBracket) + "(" + newBracketString + ")" + regexList[i].right(regexList[i].size() - j - 1); 274 | j = leftBracket + newBracketString.size() + 2 - 1; 275 | } 276 | leftBracket = -1; // 后续需要重新匹配中括号 277 | } 278 | } 279 | } 280 | } 281 | 282 | // 替换正闭包+ 283 | for (int i = 0; i < lineSize; i++) { 284 | int leftBracket = -1; 285 | for (int j = 0; j < regexList[i].size(); j++) { 286 | if (regexList[i][j] == '\\') { // 转义字符 287 | j++; 288 | } else if (regexList[i][j] == '(') { // 匹配左括号 289 | leftBracket = j; 290 | } else if (regexList[i][j] == '+') { // 遇到加号 291 | if (j > 0) { 292 | regexList[i][j] = '*'; 293 | if (regexList[i][j - 1] == ')') { 294 | regexList[i].insert(leftBracket, regexList[i].mid(leftBracket, j - leftBracket)); 295 | j += j - leftBracket; 296 | } else { 297 | regexList[i].insert(j - 1, regexList[i][j - 1]); 298 | j += 1; 299 | } 300 | } 301 | } 302 | } 303 | } 304 | 305 | // 替换可选? 306 | for (int i = 0; i < lineSize; i++) { 307 | int leftBracket = -1; 308 | for (int j = 0; j < regexList[i].size(); j++) { 309 | if (regexList[i][j] == '\\') { // 转义字符 310 | j++; 311 | } else if (regexList[i][j] == '(') { // 匹配左括号 312 | leftBracket = j; 313 | } else if (regexList[i][j] == '?') { // 遇到加号 314 | if (j > 0) { 315 | regexList[i][j] = '|'; 316 | if (regexList[i][j - 1] == ')') { 317 | regexList[i].insert(leftBracket, '('); 318 | regexList[i].insert(j + 2, "#)"); 319 | j += 3; 320 | } else { 321 | regexList[i].insert(j - 1, '('); 322 | regexList[i].insert(j + 2, "#)"); 323 | j += 3; 324 | } 325 | } 326 | } 327 | } 328 | } 329 | 330 | // 获取要转换成为NFA的主正则表达式 331 | QString mainRegex; 332 | QHash regexHash; 333 | for (int i = 0; i < lineSize; i++) { 334 | QString regexItem = regexList[i]; 335 | if (regexItem[0] == '_') { // 主正则表达式 (仅考虑有一个主正则表达式的情况) 336 | mainRegex = regexItem; 337 | regexList.removeAt(i); 338 | } else { // 非主正则表达式,获取其等号左侧的标识符 339 | int regexLen = regexItem.size(); 340 | for (int j = 0; j < regexLen; j++) { 341 | if (regexItem[j] == '=') { 342 | QString identifier = regexItem.left(j); 343 | QString regexBody = regexItem.right(regexLen - j - 1); 344 | regexHash.insert(identifier, regexBody); 345 | break; // 只捕获第一个等号(等号前的转义符不考虑) 346 | } 347 | } 348 | } 349 | } 350 | 351 | // 合并正则表达式 352 | for (auto key: regexHash.keys()) { 353 | QString replaceString = regexHash[key]; 354 | if (replaceString[0] != '(' || replaceString[replaceString.size() - 1] != ')') { 355 | replaceString = "(" + replaceString + ")"; 356 | } 357 | for (auto& value: regexHash.values()) { 358 | value.replace(key, replaceString); 359 | } 360 | mainRegex.replace(key, replaceString); 361 | } 362 | 363 | // 主正则表达式添加连接符 364 | mainRegex = mainRegex.right(mainRegex.size() - mainRegex.indexOf('=') - 1); 365 | for (int i = 0; i < mainRegex.size() - 1; i++) { 366 | if (mainRegex[i] == '\\') { 367 | i++; 368 | if (i < mainRegex.size() - 1) { 369 | if (mainRegex[i + 1] == '(' || !isOperator(mainRegex[i + 1].unicode())) { 370 | mainRegex.insert(i + 1, '.'); 371 | i++; 372 | } 373 | } 374 | } else if (isOperator(mainRegex[i].unicode())) { 375 | if (mainRegex[i] == ')' || mainRegex[i] == '*') { 376 | if (!isOperator(mainRegex[i + 1].unicode()) || mainRegex[i + 1] == '(') { 377 | mainRegex.insert(i + 1, '.'); 378 | i++; 379 | } 380 | } 381 | } else { 382 | if (!isOperator(mainRegex[i + 1].unicode()) || mainRegex[i + 1] == '(') { 383 | mainRegex.insert(i + 1, '.'); 384 | i++; 385 | } 386 | } 387 | } 388 | 389 | return mainRegex; 390 | } 391 | 392 | QString MainWindow::regexToPostFix(QString re) 393 | { 394 | QStack s1; 395 | QStack s2; 396 | for (int i = 0; i < re.size(); i++) { 397 | if (re[i] == '\\') { 398 | if (i < re.size() - 1) { 399 | s2.push(re.mid(i, 2)); 400 | } 401 | i++; 402 | } 403 | else if (isOperator(re[i].unicode())) { 404 | if (re[i] == '(') { 405 | s1.push(re[i]); // 左括号直接放入符号栈 406 | } else if (re[i] == ')') { 407 | while (!s1.empty() && s1.top() != '(') { // 右括号不断拿出符号栈内容,放入结果栈,直到遇到结果栈 408 | s2.push(s1.top()); 409 | s1.pop(); 410 | } 411 | if (!s1.empty() && s1.top() == '(') s1.pop(); 412 | } else { 413 | int nowPriority = getPriority(re[i].unicode()); 414 | while (!s1.empty() && getPriority(s1.top().unicode()) >= nowPriority) { 415 | s2.push(s1.top()); 416 | s1.pop(); 417 | } 418 | if (s1.empty() || getPriority(s1.top().unicode()) < nowPriority) { 419 | s1.push(re[i]); 420 | } 421 | } 422 | } else { 423 | s2.push(re.mid(i, 1)); 424 | } 425 | } 426 | while (!s1.empty()) { 427 | s2.push(s1.top()); 428 | s1.pop(); 429 | } 430 | QStack s3; 431 | QString postFixRegex = ""; 432 | while (!s2.empty()) { 433 | s3.push(s2.top()); 434 | s2.pop(); 435 | } 436 | while (!s3.empty()) { 437 | postFixRegex += s3.top(); 438 | s3.pop(); 439 | } 440 | return postFixRegex; 441 | } 442 | 443 | void MainWindow::tableRemoveAll() 444 | { 445 | ui->tableWidget->clear(); 446 | ui->tableWidget->setHorizontalHeaderLabels(QStringList()); 447 | ui->tableWidget->setRowCount(0); 448 | ui->tableWidget->setColumnCount(0); 449 | } 450 | 451 | -------------------------------------------------------------------------------- /第二次实验/regex2dfa/mainwindow.h: -------------------------------------------------------------------------------- 1 | #ifndef MAINWINDOW_H 2 | #define MAINWINDOW_H 3 | 4 | #include 5 | #include 6 | 7 | #include "nfa.h" 8 | #include "dfa.h" 9 | 10 | QT_BEGIN_NAMESPACE 11 | namespace Ui { class MainWindow; } 12 | QT_END_NAMESPACE 13 | 14 | class MainWindow : public QMainWindow 15 | { 16 | Q_OBJECT 17 | 18 | public: 19 | MainWindow(QWidget *parent = nullptr); 20 | ~MainWindow(); 21 | 22 | private: 23 | Ui::MainWindow *ui; 24 | 25 | NFA nfa; 26 | DFA dfa; 27 | DFA miniDFA; 28 | QString code; 29 | 30 | static QString regexListPreprocessing(QStringList allRegex); 31 | static QString regexToPostFix(QString re); 32 | 33 | void tableRemoveAll(void); 34 | }; 35 | #endif // MAINWINDOW_H 36 | -------------------------------------------------------------------------------- /第二次实验/regex2dfa/mainwindow.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | MainWindow 4 | 5 | 6 | 7 | 0 8 | 0 9 | 800 10 | 600 11 | 12 | 13 | 14 | MainWindow 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 宋体 26 | 10 27 | 28 | 29 | 30 | 1 31 | 32 | 33 | <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> 34 | <html><head><meta name="qrichtext" content="1" /><style type="text/css"> 35 | p, li { white-space: pre-wrap; } 36 | </style></head><body style=" font-family:'宋体'; font-size:10pt; font-weight:400; font-style:normal;"> 37 | <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'SimSun'; font-size:11pt; font-weight:600;">Regex2DFA</span><span style=" font-family:'SimSun'; font-size:11pt;">是通过输入正则表达式组,将以&quot;_&quot;开头的变量所代表的正则表达式转换为NFA、DFA、最小化DFA的软件。</span></p> 38 | <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'SimSun'; font-size:11pt;">(以</span><span style=" font-family:'SimSun'; font-size:11pt; color:#00ff00;">绿色</span><span style=" font-family:'SimSun'; font-size:11pt;">标记始态,以</span><span style=" font-family:'SimSun'; font-size:11pt; color:#ff0000;">红色</span><span style=" font-family:'SimSun'; font-size:11pt;">标记终态)</span></p> 39 | <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'SimSun'; font-size:11pt;"><br /></p> 40 | <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'SimSun'; font-size:11pt;">其中,软件实现了:</span></p> 41 | <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'SimSun'; font-size:11pt;">1. </span><span style=" font-family:'SimSun'; font-size:11pt; font-weight:600;">分析</span><span style=" font-family:'SimSun'; font-size:11pt;">(左侧第一个按钮,按下该按钮后可以通过点击左侧2、3、4按钮显示不同内容)</span></p> 42 | <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'SimSun'; font-size:11pt;">2. </span><span style=" font-family:'SimSun'; font-size:11pt; font-weight:600;">正则表达式转为NFA</span><span style=" font-family:'SimSun'; font-size:11pt;">(左侧第二个按钮)</span></p> 43 | <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'SimSun'; font-size:11pt;">3. </span><span style=" font-family:'SimSun'; font-size:11pt; font-weight:600;">NFA转为DFA</span><span style=" font-family:'SimSun'; font-size:11pt;">(左侧第三个按钮)</span></p> 44 | <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'SimSun'; font-size:11pt;">4. </span><span style=" font-family:'SimSun'; font-size:11pt; font-weight:600;">DFA最小化</span><span style=" font-family:'SimSun'; font-size:11pt;">(左侧第四个按钮)</span></p> 45 | <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'SimSun'; font-size:11pt;">5. </span><span style=" font-family:'SimSun'; font-size:11pt; font-weight:600;">重置</span><span style=" font-family:'SimSun'; font-size:11pt;">(可以重新输入正则表达式)</span></p> 46 | <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'SimSun'; font-size:11pt;">点击分析按钮,实现正则表达式-&gt;NFA-&gt;DFA-&gt;最小化DFA</span></p> 47 | <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'SimSun'; font-size:11pt;"><br /></p> 48 | <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'SimSun'; font-size:11pt;">注:<br />1. 输入只能包含一个以&quot;_&quot;开头的正则表达式,否则软件可能会出现误解,产生不正确的NFA、DFA等;<br />2. 等号左侧的标识符仅包含字母、数字与下划线</span></p> 49 | <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'SimSun'; font-size:11pt;">3. 软件以#字符作为NFA转换的epsilon标识,因此,希望输入#字符,应当使用转义符号,输入\#才可以识别。</span></p> 50 | <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'SimSun'; font-size:11pt;"><br /></p> 51 | <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'SimSun'; font-size:11pt; color:#aa0000;">较长的正则表达式可能会分析较久,请您耐心等待,谢谢。</span></p></body></html> 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 0 66 | 0 67 | 68 | 69 | 70 | 71 | Times New Roman 72 | 18 73 | 74 | 75 | 76 | Regex2DFA 77 | 78 | 79 | Qt::AlignCenter 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 16777215 88 | 16777215 89 | 90 | 91 | 92 | 93 | 94 | 95 | 分析 96 | 97 | 98 | 99 | 100 | 101 | 102 | 显示NFA 103 | 104 | 105 | 106 | 107 | 108 | 109 | 显示DFA 110 | 111 | 112 | 113 | 114 | 115 | 116 | 最小化DFA 117 | 118 | 119 | 120 | 121 | 122 | 123 | 生成匹配代码 124 | 125 | 126 | 127 | 128 | 129 | 130 | 重置程序 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 0 145 | 0 146 | 147 | 148 | 149 | 150 | 151 | 152 | 请在下方框中写入正则表达式 153 | 154 | 155 | Qt::AlignCenter 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 0 170 | 0 171 | 172 | 173 | 174 | 175 | 16777215 176 | 16777215 177 | 178 | 179 | 180 | 181 | 182 | 183 | NFA、DFA展示表 184 | 185 | 186 | Qt::AlignCenter 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 0 202 | 0 203 | 800 204 | 21 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | -------------------------------------------------------------------------------- /第二次实验/regex2dfa/nfa.cpp: -------------------------------------------------------------------------------- 1 | #include "nfa.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "utils.h" 10 | 11 | NFA::NFA(int begin, int end): startState(begin), endState(end), stateNum(0), maxStateNum(100) { 12 | G.resize(maxStateNum); 13 | for (int i = 0; i < maxStateNum; i++) { 14 | G[i].resize(maxStateNum); 15 | } 16 | } 17 | 18 | void NFA::clear() 19 | { 20 | // 清空nfa 21 | for (int i = 0; i < maxStateNum; i++) { 22 | G[i].clear(); 23 | } 24 | G.clear(); 25 | maxStateNum = 100; 26 | stateNum = 0; 27 | startState = -1; 28 | endState = -1; 29 | G.resize(maxStateNum); 30 | for (int i = 0; i < maxStateNum; i++) { 31 | G[i].resize(maxStateNum); 32 | } 33 | stateSet.clear(); 34 | } 35 | 36 | void NFA::fromRegex(QString re) // 后缀表达式转NFA 37 | { 38 | QStack> s; 39 | for (int i = 0; i < re.size(); i++) { 40 | if (re[i] == '\\') { // 转义字符 41 | if (i < re.size() - 1) { 42 | allocateMemory(2); 43 | G[stateNum][stateNum + 1] = re[i + 1]; // 转义符不再出现 44 | s.append({stateNum, stateNum + 1}); // 入栈 45 | stateNum += 2; // 状态数量 + 2 46 | stateSet.insert(QString(re[i + 1])); 47 | } 48 | i++; 49 | } else if (re[i] == '*' || re[i] == '|' || re[i] == '.') { // 运算符 50 | if (re[i] == '.') { 51 | if (s.size() >= 2) { // 取出两个元素相连重新入栈 52 | QPair tail = s.top(); 53 | s.pop(); 54 | QPair head = s.top(); 55 | s.pop(); 56 | G[head.second][tail.first] = "epsilon"; // 连接操作 57 | s.append({head.first, tail.second}); // 重新入栈 58 | stateSet.insert("epsilon"); 59 | } 60 | } else if (re[i] == '|') { 61 | allocateMemory(2); 62 | if (s.size() >= 2) { // 取出两个元素相连重新入栈 63 | QPair left = s.top(); 64 | s.pop(); 65 | QPair right = s.top(); 66 | s.pop(); 67 | G[stateNum][left.first] = "epsilon"; 68 | G[stateNum][right.first] = "epsilon"; 69 | G[left.second][stateNum + 1] = "epsilon"; 70 | G[right.second][stateNum + 1] = "epsilon"; 71 | s.append({stateNum, stateNum + 1}); // 入栈 72 | stateNum += 2; // 状态数量 + 2 73 | stateSet.insert("epsilon"); 74 | } 75 | } else { 76 | allocateMemory(2); 77 | if (!s.empty()) { // 闭包为单元运算符,因此只需要取出一个元素 78 | QPair item = s.top(); 79 | s.pop(); 80 | G[stateNum][stateNum + 1] = "epsilon"; 81 | G[stateNum][item.first] = "epsilon"; 82 | G[item.second][stateNum + 1] = "epsilon"; 83 | G[item.second][item.first] = "epsilon"; 84 | s.append({stateNum, stateNum + 1}); // 入栈 85 | stateNum += 2; // 状态数量 + 2 86 | stateSet.insert("epsilon"); 87 | } 88 | } 89 | } else { 90 | if (re[i] == '#') { // epsilon 91 | allocateMemory(2); 92 | G[stateNum][stateNum + 1] = "epsilon"; 93 | s.append({stateNum, stateNum + 1}); // 入栈 94 | stateNum += 2; // 状态数量 + 2 95 | stateSet.insert("epsilon"); 96 | } else { // 其他非运算符 97 | allocateMemory(2); 98 | G[stateNum][stateNum + 1] = re[i]; 99 | s.append({stateNum, stateNum + 1}); // 入栈 100 | stateNum += 2; // 状态数量 + 2 101 | stateSet.insert(QString(re[i])); 102 | } 103 | } 104 | } 105 | if (!s.empty()){ 106 | QPair statePair = s.top(); 107 | startState = statePair.first; 108 | endState = statePair.second; 109 | } 110 | } 111 | 112 | void NFA::allocateMemory(int num) 113 | { 114 | // 当状态数即将超过最大状态时,分配更大的空间 115 | while (stateNum + num >= maxStateNum) { 116 | QVector> newG(2 * maxStateNum); 117 | for (int i = 0; i < 2 * maxStateNum; i++) { 118 | newG[i].resize(2 * maxStateNum); 119 | } 120 | for (int i = 0; i < maxStateNum; i++) { 121 | for (int j = 0; j < maxStateNum; j++) { 122 | newG[i][j] = G[i][j]; 123 | } 124 | } 125 | maxStateNum *= 2; 126 | G = newG; 127 | } 128 | } 129 | 130 | QSet NFA::epsilonClosure(QSet state) 131 | { 132 | while (true) { 133 | QSet tmpSet; 134 | for (int item: state) { 135 | for (int i = 0; i < maxStateNum; i++) { 136 | if (G[item][i] == "epsilon") { 137 | if (!state.contains(i)) { 138 | tmpSet.insert(i); 139 | } 140 | } 141 | } 142 | } 143 | if (tmpSet.empty()) break; 144 | state = state.unite(tmpSet); 145 | } 146 | return state; 147 | } 148 | 149 | QSet NFA::valueClosure(QSet state, QString value) 150 | { 151 | QSet result; 152 | for (int item: state) { 153 | for (int i = 0; i < maxStateNum; i++) { 154 | if (G[item][i] == value) { 155 | result.insert(i); 156 | } 157 | } 158 | } 159 | return result; 160 | } 161 | -------------------------------------------------------------------------------- /第二次实验/regex2dfa/nfa.h: -------------------------------------------------------------------------------- 1 | #ifndef NFA_H 2 | #define NFA_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | class NFA 9 | { 10 | public: 11 | // 构造函数 12 | NFA(int begin = -1, int end = -1); 13 | void clear(); // 清空NFA 14 | void fromRegex(QString re); // 从后缀表达式构造NFA 15 | void allocateMemory(int num); // 分配G内存的函数 16 | QSet epsilonClosure(QSet state); // 计算epsilon闭包 17 | QSet valueClosure(QSet state, QString value); // 计算某个集合状态能通过value转移到的状态集合 18 | 19 | // 成员变量 20 | QVector> G; // 邻接矩阵 21 | QSet stateSet; // 存储所有状态类型 22 | int startState; // 表示起始状态 23 | int endState; // 表示终止状态 24 | int stateNum; // 表示状态数量 25 | int maxStateNum; // 表示当前最多存储的状态数量 26 | }; 27 | 28 | #endif // NFA_H 29 | -------------------------------------------------------------------------------- /第二次实验/regex2dfa/regex2dfa.pro: -------------------------------------------------------------------------------- 1 | QT += core gui 2 | 3 | greaterThan(QT_MAJOR_VERSION, 4): QT += widgets 4 | 5 | CONFIG += c++11 6 | 7 | # You can make your code fail to compile if it uses deprecated APIs. 8 | # In order to do so, uncomment the following line. 9 | #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 10 | 11 | SOURCES += \ 12 | codedialog.cpp \ 13 | dfa.cpp \ 14 | main.cpp \ 15 | mainwindow.cpp \ 16 | nfa.cpp \ 17 | utils.cpp 18 | 19 | HEADERS += \ 20 | codedialog.h \ 21 | dfa.h \ 22 | mainwindow.h \ 23 | nfa.h \ 24 | utils.h 25 | 26 | FORMS += \ 27 | codedialog.ui \ 28 | mainwindow.ui 29 | 30 | # Default rules for deployment. 31 | qnx: target.path = /tmp/$${TARGET}/bin 32 | else: unix:!android: target.path = /opt/$${TARGET}/bin 33 | !isEmpty(target.path): INSTALLS += target 34 | -------------------------------------------------------------------------------- /第二次实验/regex2dfa/regex2dfa.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WA-automat/Compiler_Design_SCNU/0f3e92c521e9b785ae8af9784feade5078582a6f/第二次实验/regex2dfa/regex2dfa.zip -------------------------------------------------------------------------------- /第二次实验/regex2dfa/utils.cpp: -------------------------------------------------------------------------------- 1 | #include "utils.h" 2 | 3 | int getPriority(const char &op) // 返回运算符优先级 4 | { 5 | switch (op) { 6 | case '(': 7 | case ')': 8 | return 0; 9 | case '*': 10 | return 4; 11 | case '|': 12 | return 1; 13 | case '.': 14 | return 2; 15 | default: 16 | return -1; 17 | } 18 | } 19 | 20 | bool isOperator(const char &ch) 21 | { 22 | switch (ch) { 23 | case '(': 24 | case ')': 25 | case '*': 26 | case '|': 27 | case '.': 28 | return true; // 运算符返回true 29 | default: 30 | return false; // 非运算符返回false 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /第二次实验/regex2dfa/utils.h: -------------------------------------------------------------------------------- 1 | #ifndef UTILS_H 2 | #define UTILS_H 3 | 4 | int getPriority(const char &op); 5 | bool isOperator(const char &ch); 6 | 7 | #endif // UTILS_H 8 | -------------------------------------------------------------------------------- /第二次实验/编译原理实验二.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WA-automat/Compiler_Design_SCNU/0f3e92c521e9b785ae8af9784feade5078582a6f/第二次实验/编译原理实验二.zip -------------------------------------------------------------------------------- /第二次实验/编译原理实验二/文档文件夹/编译原理实验二.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WA-automat/Compiler_Design_SCNU/0f3e92c521e9b785ae8af9784feade5078582a6f/第二次实验/编译原理实验二/文档文件夹/编译原理实验二.pdf -------------------------------------------------------------------------------- /第二次实验/编译原理实验二/源代码文件夹/regex2dfa/codedialog.cpp: -------------------------------------------------------------------------------- 1 | #include "codedialog.h" 2 | #include "ui_codedialog.h" 3 | 4 | #include 5 | #include 6 | 7 | CodeDialog::CodeDialog(QWidget *parent, QString code) : 8 | QDialog(parent), 9 | ui(new Ui::CodeDialog) 10 | { 11 | ui->setupUi(this); 12 | ui->codeBrowser->setText(code); 13 | 14 | this->setWindowTitle("匹配代码"); 15 | QScreen *screen = QGuiApplication::primaryScreen(); 16 | QRect screenGeometry = screen->geometry(); 17 | int screenWidth = screenGeometry.width(); 18 | int screenHeight = screenGeometry.height(); 19 | int newWidth = screenWidth * 0.6; 20 | int newHeight = screenHeight * 0.6; 21 | this->resize(newWidth, newHeight); 22 | } 23 | 24 | CodeDialog::~CodeDialog() 25 | { 26 | delete ui; 27 | } 28 | -------------------------------------------------------------------------------- /第二次实验/编译原理实验二/源代码文件夹/regex2dfa/codedialog.h: -------------------------------------------------------------------------------- 1 | #ifndef CODEDIALOG_H 2 | #define CODEDIALOG_H 3 | 4 | #include 5 | 6 | namespace Ui { 7 | class CodeDialog; 8 | } 9 | 10 | class CodeDialog : public QDialog 11 | { 12 | Q_OBJECT 13 | 14 | public: 15 | explicit CodeDialog(QWidget *parent = nullptr, QString code = ""); 16 | ~CodeDialog(); 17 | 18 | private: 19 | Ui::CodeDialog *ui; 20 | }; 21 | 22 | #endif // CODEDIALOG_H 23 | -------------------------------------------------------------------------------- /第二次实验/编译原理实验二/源代码文件夹/regex2dfa/codedialog.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | CodeDialog 4 | 5 | 6 | 7 | 0 8 | 0 9 | 648 10 | 496 11 | 12 | 13 | 14 | Dialog 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /第二次实验/编译原理实验二/源代码文件夹/regex2dfa/dfa.cpp: -------------------------------------------------------------------------------- 1 | #include "dfa.h" 2 | 3 | #include 4 | #include 5 | 6 | DFA::DFA() 7 | { 8 | 9 | } 10 | 11 | void DFA::fromNFA(NFA nfa) 12 | { 13 | QHash, int> revMapping; 14 | // 获取始态 15 | QSet startSet; 16 | startSet.insert(nfa.startState); 17 | startSet = nfa.epsilonClosure(startSet); 18 | mapping[startState] = startSet; 19 | revMapping[startSet] = startState; 20 | if (startSet.contains(nfa.endState)) { 21 | endStates.insert(startState); 22 | } 23 | stateNum++; 24 | 25 | QSet> vis; // 判断某个状态是否被找到 26 | QQueue q; // 循环队列 27 | q.push_back(startState); 28 | while (!q.empty()) { 29 | 30 | // 取出队头 31 | int stateItem = q.front(); 32 | q.pop_front(); 33 | QSet nfaStateSet = mapping[stateItem]; 34 | 35 | // 未曾出现过的状态集合才需要查找 36 | if (!vis.contains(nfaStateSet)) { 37 | 38 | // 查询当前状态集合的转移 39 | for (QString changeItem: nfa.stateSet) { 40 | if (changeItem != "epsilon") { 41 | 42 | // 获取对应转移到的epsilon闭包 43 | QSet changeClosure = nfa.valueClosure(nfaStateSet, changeItem); 44 | QSet changeEpsilon = nfa.epsilonClosure(changeClosure); 45 | 46 | // 找不到集合 47 | if (changeEpsilon.empty()) continue; 48 | 49 | // 之前找到过这个状态 50 | if (revMapping.contains(changeEpsilon)) { 51 | int nextItem = revMapping[changeEpsilon]; 52 | 53 | G[stateItem][changeItem] = nextItem; 54 | if (changeEpsilon.contains(nfa.endState)) { 55 | endStates.insert(nextItem); 56 | } 57 | 58 | if (!vis.contains(changeEpsilon)) { 59 | q.push_back(nextItem); 60 | } 61 | } else { 62 | int nextItem = stateNum; 63 | mapping[nextItem] = changeEpsilon; 64 | revMapping[changeEpsilon] = nextItem; 65 | 66 | G[stateItem][changeItem] = nextItem; 67 | if (changeEpsilon.contains(nfa.endState)) { 68 | endStates.insert(nextItem); 69 | } 70 | stateNum++; 71 | 72 | if (!vis.contains(changeEpsilon)) { 73 | q.push_back(nextItem); 74 | } 75 | } 76 | } 77 | } 78 | vis.insert(nfaStateSet); 79 | } 80 | } 81 | } 82 | 83 | void DFA::fromDFA(DFA dfa) 84 | { 85 | QSet notEndStates; 86 | for (int i = 0; i < dfa.stateNum; i++) { 87 | if (!dfa.endStates.contains(i)) { 88 | notEndStates.insert(i); 89 | } 90 | } 91 | 92 | // 找到原始DFA的转移类型 93 | QSet stateSet; 94 | for (int i = 0; i < dfa.stateNum; i++) { 95 | for (QString changeItem: dfa.G[i].keys()) { 96 | stateSet.insert(changeItem); 97 | } 98 | } 99 | 100 | QQueue> q; 101 | if (!notEndStates.empty()) q.push_back(notEndStates); 102 | if (!dfa.endStates.empty()) q.push_back(dfa.endStates); 103 | 104 | int lastQueLen = 0, cnt = 0; 105 | if (!notEndStates.empty()) lastQueLen++; 106 | if (!dfa.endStates.empty()) lastQueLen++; 107 | 108 | while (true) { 109 | 110 | QSet stateItem = q.front(); 111 | 112 | // 划分集合 113 | bool flag = true; 114 | for (QString changeItem: stateSet) { 115 | QSet> vis; 116 | QHash, QSet> setHash; // 当前选出 117 | for (int beginItem: stateItem) { 118 | if (!dfa.G.contains(beginItem)) continue; 119 | if (!dfa.G[beginItem].contains(changeItem)) { 120 | vis.insert(QSet()); 121 | setHash[QSet()].insert(beginItem); 122 | continue; 123 | } 124 | for (QSet queueItem: q) { 125 | if (queueItem.contains(dfa.G[beginItem][changeItem])){ 126 | vis.insert(queueItem); 127 | setHash[queueItem].insert(beginItem); 128 | break; 129 | } 130 | } 131 | } 132 | if (vis.size() <= 1) { 133 | continue; 134 | } else { 135 | for (QSet visItem: vis) { 136 | q.push_back(setHash[visItem]); 137 | } 138 | flag = false; 139 | break; 140 | } 141 | } 142 | 143 | q.pop_front(); 144 | if (flag) q.push_back(stateItem); 145 | 146 | // 判断“上一个”队列是否全被扫过一次 147 | cnt++; 148 | if (lastQueLen == cnt) { 149 | if (lastQueLen == q.size()) { 150 | break; 151 | } 152 | lastQueLen = q.size(); 153 | cnt = 0; 154 | } 155 | } 156 | 157 | int idx = 0; 158 | // 设置新编号 159 | QHash, int> revMapping; 160 | for (QSet queueItem: q) { 161 | if (queueItem.empty()) continue; 162 | mapping[idx] = queueItem; 163 | revMapping[queueItem] = idx; 164 | idx++; 165 | } 166 | stateNum = idx; 167 | 168 | // 找到始态和终态 169 | for (QSet queueItem: q) { 170 | if (queueItem.empty()) continue; 171 | // 找始态 172 | if (queueItem.contains(dfa.startState)) { 173 | startState = revMapping[queueItem]; 174 | } 175 | // 找终态 176 | for (int endState: dfa.endStates) { 177 | if (queueItem.contains(endState)) { 178 | endStates.insert(revMapping[queueItem]); 179 | break; 180 | } 181 | } 182 | } 183 | 184 | // 构建新的G 185 | for (QSet queueItem: q) { 186 | if (queueItem.empty()) continue; 187 | int stateItem = *queueItem.begin(); 188 | for (QString changeItem: stateSet) { 189 | if (!dfa.G[stateItem].contains(changeItem)) continue; 190 | int endItem = dfa.G[stateItem][changeItem]; 191 | for (QSet endQueueItem: q) { 192 | if (endQueueItem.contains(endItem)) { 193 | G[revMapping[queueItem]][changeItem] = revMapping[endQueueItem]; 194 | break; 195 | } 196 | } 197 | } 198 | } 199 | } 200 | 201 | void DFA::clear() 202 | { 203 | mapping.clear(); 204 | G.clear(); 205 | endStates.clear(); 206 | stateNum = 0; 207 | startState = 0; 208 | } 209 | 210 | QString DFA::toCode() 211 | { 212 | QString code = "bool matchFunction(string s) {\n"; 213 | code += "\tint idx = 0, state = "; 214 | code += QString::number(startState) + ";\n"; 215 | code += "\twhile (state < " + QString::number(stateNum) + " && idx < s.size()) {\n"; 216 | code += "\t\tswitch (state) {\n"; 217 | for (int i = 0; i < stateNum; i++) { 218 | if (G[i].keys().empty()) continue; 219 | code += "\t\tcase " + QString::number(i) + ":\n"; 220 | code += "\t\t\tswitch (s[idx]) {\n"; 221 | for (QString changeItem: G[i].keys()) { 222 | code += "\t\t\tcase \'" + changeItem + "\':\n"; 223 | code += "\t\t\t\tstate = " + QString::number(G[i][changeItem]) + ";\n"; 224 | code += "\t\t\t\tbreak;\n"; 225 | } 226 | code += "\t\t\tdefault:\n"; 227 | code += "\t\t\t\tstate = " + QString::number(stateNum) + ";\n"; 228 | code += "\t\t\t\tbreak;\n"; 229 | code += "\t\t\t}\n"; 230 | code += "\t\t\tbreak;\n"; 231 | } 232 | code += "\t\tdefault:\n"; 233 | code += "\t\t\tstate = " + QString::number(stateNum) + ";\n"; 234 | code += "\t\t\tbreak;\n"; 235 | code += "\t\t}\n"; 236 | code += "\t\tidx++\n"; 237 | code += "\t}\n"; 238 | code += "\tif ("; 239 | int cnt = 0; 240 | for (int i: endStates) { 241 | code += "state == " + QString::number(i); 242 | cnt++; 243 | if (cnt != endStates.size()) code += "||"; 244 | } 245 | code += ") return true;\n"; 246 | code += "\telse return false;\n"; 247 | code += "}"; 248 | return code; 249 | } 250 | -------------------------------------------------------------------------------- /第二次实验/编译原理实验二/源代码文件夹/regex2dfa/dfa.h: -------------------------------------------------------------------------------- 1 | #ifndef DFA_H 2 | #define DFA_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "nfa.h" 10 | 11 | class DFA 12 | { 13 | public: 14 | DFA(); 15 | void fromNFA(NFA nfa); 16 | void fromDFA(DFA dfa); 17 | void clear(); 18 | QString toCode(); 19 | 20 | QHash> mapping; 21 | QHash> G; 22 | int startState; 23 | QSet endStates; 24 | int stateNum; // 表示状态数量 25 | 26 | }; 27 | 28 | #endif // DFA_H 29 | -------------------------------------------------------------------------------- /第二次实验/编译原理实验二/源代码文件夹/regex2dfa/main.cpp: -------------------------------------------------------------------------------- 1 | #include "mainwindow.h" 2 | 3 | #include 4 | 5 | int main(int argc, char *argv[]) 6 | { 7 | QApplication a(argc, argv); 8 | MainWindow w; 9 | w.show(); 10 | return a.exec(); 11 | } 12 | -------------------------------------------------------------------------------- /第二次实验/编译原理实验二/源代码文件夹/regex2dfa/mainwindow.cpp: -------------------------------------------------------------------------------- 1 | #include "mainwindow.h" 2 | #include "ui_mainwindow.h" 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include "utils.h" 15 | #include "nfa.h" 16 | #include "dfa.h" 17 | #include "codedialog.h" 18 | 19 | MainWindow::MainWindow(QWidget *parent) 20 | : QMainWindow(parent) 21 | , ui(new Ui::MainWindow) 22 | , nfa() 23 | { 24 | ui->setupUi(this); 25 | 26 | // 页面基本布局 27 | this->setWindowTitle("编译原理实验二:正则表达式转NFA、DFA"); 28 | QScreen *screen = QGuiApplication::primaryScreen(); 29 | QRect screenGeometry = screen->geometry(); 30 | int screenWidth = screenGeometry.width(); 31 | int screenHeight = screenGeometry.height(); 32 | int newWidth = screenWidth * 0.9; 33 | int newHeight = screenHeight * 0.9; 34 | this->resize(newWidth, newHeight); 35 | 36 | // 分析并产生NFA、DFA、最小化DFA 37 | connect(ui->analysisPushButton, &QPushButton::clicked, this, [=]() { 38 | this->nfa.clear(); 39 | this->dfa.clear(); 40 | this->miniDFA.clear(); 41 | this->code = ""; 42 | tableRemoveAll(); 43 | 44 | QString allText = ui->textEdit->toPlainText(); 45 | if (allText != "") { 46 | 47 | QStringList lines = allText.split('\n', QString::SkipEmptyParts); 48 | 49 | // 预处理正则表达式组 50 | QString mainRegex = regexListPreprocessing(lines); 51 | 52 | // 正则表达式转后缀表达式 53 | QString postFixRegex = regexToPostFix(mainRegex); 54 | 55 | // 后缀表达式转NFA 56 | this->nfa.fromRegex(postFixRegex); 57 | 58 | // NFA转DFA 59 | this->dfa.fromNFA(this->nfa); 60 | 61 | // DFA最小化 62 | this->miniDFA.fromDFA(this->dfa); 63 | 64 | // 转换为代码 65 | this->code = this->miniDFA.toCode(); 66 | } 67 | 68 | }); 69 | 70 | // 显示NFA 71 | connect(ui->nfaPushButton, &QPushButton::clicked, this, [=]() { 72 | // 清空原来的表格 73 | tableRemoveAll(); 74 | 75 | ui->tableWidget->setRowCount(nfa.stateNum); 76 | ui->tableWidget->setColumnCount(nfa.stateSet.size()); 77 | QStringList strListColumnHander; 78 | for (QString item : nfa.stateSet) { 79 | strListColumnHander << tr(item.toStdString().c_str()); 80 | } 81 | ui->tableWidget->setHorizontalHeaderLabels(strListColumnHander); 82 | QStringList strListRowHander; 83 | for (int i = 0; i < nfa.stateNum; i++) { 84 | strListRowHander << tr(QString::number(i).toStdString().c_str()); 85 | } 86 | ui->tableWidget->setVerticalHeaderLabels(strListRowHander); 87 | for (int i = 0; i < nfa.stateNum; i++) { 88 | int j = 0; 89 | for (QString stateChange: nfa.stateSet) { 90 | QString itemString = ""; 91 | for (int k = 0; k < nfa.stateNum; k++) { 92 | if (nfa.G[i][k] == stateChange) { 93 | itemString += QString::number(k); 94 | itemString += ","; 95 | } 96 | } 97 | ui->tableWidget->setItem(i, j, new QTableWidgetItem(itemString.left(itemString.size() - 1))); 98 | j++; 99 | } 100 | } 101 | 102 | // 添加始态、终态颜色 103 | QTableWidgetItem *beginItem = ui->tableWidget->verticalHeaderItem(nfa.startState); 104 | QTableWidgetItem *endItem = ui->tableWidget->verticalHeaderItem(nfa.endState); 105 | beginItem->setTextColor(QColor(0, 255, 0)); 106 | endItem->setTextColor(QColor(255, 0, 0)); 107 | }); 108 | 109 | // 显示DFA 110 | connect(ui->dfaPushButton, &QPushButton::clicked, this, [=]() { 111 | // 清空原来的表格 112 | tableRemoveAll(); 113 | 114 | ui->tableWidget->setRowCount(dfa.stateNum); 115 | ui->tableWidget->setColumnCount(nfa.stateSet.size() - (nfa.stateSet.contains("epsilon") ? 1 : 0)); 116 | 117 | QStringList strListColumnHander; 118 | for (QString item : nfa.stateSet) { 119 | if (item == "epsilon") continue; 120 | strListColumnHander << tr(item.toStdString().c_str()); 121 | } 122 | ui->tableWidget->setHorizontalHeaderLabels(strListColumnHander); 123 | 124 | QStringList strListRowHander; 125 | for (int i = 0; i < dfa.stateNum; i++) { 126 | strListRowHander << tr(QString::number(i).toStdString().c_str()); 127 | } 128 | ui->tableWidget->setVerticalHeaderLabels(strListRowHander); 129 | 130 | for (int i = 0; i < dfa.stateNum; i++) { 131 | if (!dfa.G.contains(i)) continue; 132 | int j = 0; 133 | for (QString stateChange: nfa.stateSet) { 134 | if (stateChange == "epsilon") continue; 135 | if (dfa.G[i].contains(stateChange)) { 136 | 137 | int k = dfa.G[i][stateChange]; 138 | QString titleTr = QString::number(k) + ":{"; 139 | for (int item: dfa.mapping[k]) { 140 | titleTr += QString::number(item); 141 | titleTr += ","; 142 | } 143 | titleTr = titleTr.left(titleTr.size() - 1); 144 | titleTr += "}"; 145 | 146 | ui->tableWidget->setItem(i, j, new QTableWidgetItem(titleTr)); 147 | } 148 | j++; 149 | } 150 | } 151 | 152 | // 添加始态、终态颜色 153 | QTableWidgetItem *beginItem = ui->tableWidget->verticalHeaderItem(dfa.startState); 154 | beginItem->setTextColor(QColor(0, 255, 0)); 155 | for (int endState: dfa.endStates) { 156 | QTableWidgetItem *endItem = ui->tableWidget->verticalHeaderItem(endState); 157 | endItem->setTextColor(QColor(255, 0, 0)); 158 | } 159 | 160 | }); 161 | 162 | // 显示最小化的DFA 163 | connect(ui->minimumDfaPushButton, &QPushButton::clicked, this, [=]() { 164 | // 清空原来的表格 165 | tableRemoveAll(); 166 | 167 | ui->tableWidget->setRowCount(miniDFA.stateNum); 168 | ui->tableWidget->setColumnCount(nfa.stateSet.size() - (nfa.stateSet.contains("epsilon") ? 1 : 0)); 169 | 170 | QStringList strListColumnHander; 171 | for (QString item : nfa.stateSet) { 172 | if (item == "epsilon") continue; 173 | strListColumnHander << tr(item.toStdString().c_str()); 174 | } 175 | ui->tableWidget->setHorizontalHeaderLabels(strListColumnHander); 176 | 177 | QStringList strListRowHander; 178 | for (int i = 0; i < miniDFA.stateNum; i++) { 179 | strListRowHander << tr(QString::number(i).toStdString().c_str()); 180 | } 181 | ui->tableWidget->setVerticalHeaderLabels(strListRowHander); 182 | 183 | for (int i = 0; i < miniDFA.stateNum; i++) { 184 | if (!miniDFA.G.contains(i)) continue; 185 | int j = 0; 186 | for (QString stateChange: nfa.stateSet) { 187 | if (stateChange == "epsilon") continue; 188 | if (miniDFA.G[i].contains(stateChange)) { 189 | 190 | int k = miniDFA.G[i][stateChange]; 191 | QString titleTr = QString::number(k) + ":{"; 192 | for (int item: miniDFA.mapping[k]) { 193 | titleTr += QString::number(item); 194 | titleTr += ","; 195 | } 196 | titleTr = titleTr.left(titleTr.size() - 1); 197 | titleTr += "}"; 198 | 199 | ui->tableWidget->setItem(i, j, new QTableWidgetItem(titleTr)); 200 | } 201 | j++; 202 | } 203 | } 204 | 205 | // 添加始态、终态颜色 206 | QTableWidgetItem *beginItem = ui->tableWidget->verticalHeaderItem(miniDFA.startState); 207 | beginItem->setTextColor(QColor(0, 255, 0)); 208 | for (int endState: miniDFA.endStates) { 209 | QTableWidgetItem *endItem = ui->tableWidget->verticalHeaderItem(endState); 210 | endItem->setTextColor(QColor(255, 0, 0)); 211 | } 212 | }); 213 | 214 | // 生成匹配代码 215 | connect(ui->codePushButton, &QPushButton::clicked, this, [=]() { 216 | CodeDialog* codeDialog = new CodeDialog(this, code); 217 | codeDialog->exec(); 218 | }); 219 | 220 | // 重置程序 221 | connect(ui->resetPushButton, &QPushButton::clicked, this, [=]() { 222 | this->nfa.clear(); 223 | this->dfa.clear(); 224 | this->miniDFA.clear(); 225 | this->code = ""; 226 | tableRemoveAll(); 227 | }); 228 | 229 | } 230 | 231 | MainWindow::~MainWindow() 232 | { 233 | delete ui; 234 | } 235 | 236 | QString MainWindow::regexListPreprocessing(QStringList regexList) { 237 | int lineSize = regexList.size(); 238 | 239 | // 去除所有空格 240 | for (int i = 0; i < lineSize; i++) { 241 | regexList[i].replace(" ", ""); 242 | } 243 | 244 | // 替换[] 245 | for (int i = 0; i < lineSize; i++) { 246 | int leftBracket = -1; // 左右括号位置 247 | for (int j = 0; j < regexList[i].size(); j++) { 248 | if (regexList[i][j] == '\\') { // 转义字符 249 | j++; 250 | } else if (regexList[i][j] == '[') { // 匹配左括号 251 | leftBracket = j; 252 | } else if (regexList[i][j] == ']') { 253 | if (leftBracket == -1) { // 出现了右括号,但没有出现左括号 254 | continue; 255 | } else { 256 | if (leftBracket == j - 1) continue; // 特判一下 257 | QString bracketString = regexList[i].mid(leftBracket + 1, j - leftBracket - 1); 258 | QString newBracketString = ""; 259 | int bracketLen = bracketString.size(); 260 | int groupNum = bracketLen / 3; 261 | for (int k = 0; k < groupNum; k++) { 262 | int beginIndex = 3 * k; 263 | int endIndex = 3 * k + 2; 264 | for (char l = bracketString[beginIndex].unicode(); l <= bracketString[endIndex].unicode(); l++) { 265 | newBracketString.append(l); 266 | newBracketString.append('|'); 267 | } 268 | } 269 | if (groupNum != 0) { 270 | // 替换字符串 271 | int newBracketStringLen = newBracketString.size(); 272 | newBracketString = newBracketString.mid(0, newBracketStringLen - 1); 273 | regexList[i] = regexList[i].left(leftBracket) + "(" + newBracketString + ")" + regexList[i].right(regexList[i].size() - j - 1); 274 | j = leftBracket + newBracketString.size() + 2 - 1; 275 | } 276 | leftBracket = -1; // 后续需要重新匹配中括号 277 | } 278 | } 279 | } 280 | } 281 | 282 | // 替换正闭包+ 283 | for (int i = 0; i < lineSize; i++) { 284 | int leftBracket = -1; 285 | for (int j = 0; j < regexList[i].size(); j++) { 286 | if (regexList[i][j] == '\\') { // 转义字符 287 | j++; 288 | } else if (regexList[i][j] == '(') { // 匹配左括号 289 | leftBracket = j; 290 | } else if (regexList[i][j] == '+') { // 遇到加号 291 | if (j > 0) { 292 | regexList[i][j] = '*'; 293 | if (regexList[i][j - 1] == ')') { 294 | regexList[i].insert(leftBracket, regexList[i].mid(leftBracket, j - leftBracket)); 295 | j += j - leftBracket; 296 | } else { 297 | regexList[i].insert(j - 1, regexList[i][j - 1]); 298 | j += 1; 299 | } 300 | } 301 | } 302 | } 303 | } 304 | 305 | // 替换可选? 306 | for (int i = 0; i < lineSize; i++) { 307 | int leftBracket = -1; 308 | for (int j = 0; j < regexList[i].size(); j++) { 309 | if (regexList[i][j] == '\\') { // 转义字符 310 | j++; 311 | } else if (regexList[i][j] == '(') { // 匹配左括号 312 | leftBracket = j; 313 | } else if (regexList[i][j] == '?') { // 遇到加号 314 | if (j > 0) { 315 | regexList[i][j] = '|'; 316 | if (regexList[i][j - 1] == ')') { 317 | regexList[i].insert(leftBracket, '('); 318 | regexList[i].insert(j + 2, "#)"); 319 | j += 3; 320 | } else { 321 | regexList[i].insert(j - 1, '('); 322 | regexList[i].insert(j + 2, "#)"); 323 | j += 3; 324 | } 325 | } 326 | } 327 | } 328 | } 329 | 330 | // 获取要转换成为NFA的主正则表达式 331 | QString mainRegex; 332 | QHash regexHash; 333 | for (int i = 0; i < lineSize; i++) { 334 | QString regexItem = regexList[i]; 335 | if (regexItem[0] == '_') { // 主正则表达式 (仅考虑有一个主正则表达式的情况) 336 | mainRegex = regexItem; 337 | regexList.removeAt(i); 338 | } else { // 非主正则表达式,获取其等号左侧的标识符 339 | int regexLen = regexItem.size(); 340 | for (int j = 0; j < regexLen; j++) { 341 | if (regexItem[j] == '=') { 342 | QString identifier = regexItem.left(j); 343 | QString regexBody = regexItem.right(regexLen - j - 1); 344 | regexHash.insert(identifier, regexBody); 345 | break; // 只捕获第一个等号(等号前的转义符不考虑) 346 | } 347 | } 348 | } 349 | } 350 | 351 | // 合并正则表达式 352 | for (auto key: regexHash.keys()) { 353 | QString replaceString = regexHash[key]; 354 | if (replaceString[0] != '(' || replaceString[replaceString.size() - 1] != ')') { 355 | replaceString = "(" + replaceString + ")"; 356 | } 357 | for (auto& value: regexHash.values()) { 358 | value.replace(key, replaceString); 359 | } 360 | mainRegex.replace(key, replaceString); 361 | } 362 | 363 | // 主正则表达式添加连接符 364 | mainRegex = mainRegex.right(mainRegex.size() - mainRegex.indexOf('=') - 1); 365 | for (int i = 0; i < mainRegex.size() - 1; i++) { 366 | if (mainRegex[i] == '\\') { 367 | i++; 368 | if (i < mainRegex.size() - 1) { 369 | if (mainRegex[i + 1] == '(' || !isOperator(mainRegex[i + 1].unicode())) { 370 | mainRegex.insert(i + 1, '.'); 371 | i++; 372 | } 373 | } 374 | } else if (isOperator(mainRegex[i].unicode())) { 375 | if (mainRegex[i] == ')' || mainRegex[i] == '*') { 376 | if (!isOperator(mainRegex[i + 1].unicode()) || mainRegex[i + 1] == '(') { 377 | mainRegex.insert(i + 1, '.'); 378 | i++; 379 | } 380 | } 381 | } else { 382 | if (!isOperator(mainRegex[i + 1].unicode()) || mainRegex[i + 1] == '(') { 383 | mainRegex.insert(i + 1, '.'); 384 | i++; 385 | } 386 | } 387 | } 388 | 389 | return mainRegex; 390 | } 391 | 392 | QString MainWindow::regexToPostFix(QString re) 393 | { 394 | QStack s1; 395 | QStack s2; 396 | for (int i = 0; i < re.size(); i++) { 397 | if (re[i] == '\\') { 398 | if (i < re.size() - 1) { 399 | s2.push(re.mid(i, 2)); 400 | } 401 | i++; 402 | } 403 | else if (isOperator(re[i].unicode())) { 404 | if (re[i] == '(') { 405 | s1.push(re[i]); // 左括号直接放入符号栈 406 | } else if (re[i] == ')') { 407 | while (!s1.empty() && s1.top() != '(') { // 右括号不断拿出符号栈内容,放入结果栈,直到遇到结果栈 408 | s2.push(s1.top()); 409 | s1.pop(); 410 | } 411 | if (!s1.empty() && s1.top() == '(') s1.pop(); 412 | } else { 413 | int nowPriority = getPriority(re[i].unicode()); 414 | while (!s1.empty() && getPriority(s1.top().unicode()) >= nowPriority) { 415 | s2.push(s1.top()); 416 | s1.pop(); 417 | } 418 | if (s1.empty() || getPriority(s1.top().unicode()) < nowPriority) { 419 | s1.push(re[i]); 420 | } 421 | } 422 | } else { 423 | s2.push(re.mid(i, 1)); 424 | } 425 | } 426 | while (!s1.empty()) { 427 | s2.push(s1.top()); 428 | s1.pop(); 429 | } 430 | QStack s3; 431 | QString postFixRegex = ""; 432 | while (!s2.empty()) { 433 | s3.push(s2.top()); 434 | s2.pop(); 435 | } 436 | while (!s3.empty()) { 437 | postFixRegex += s3.top(); 438 | s3.pop(); 439 | } 440 | return postFixRegex; 441 | } 442 | 443 | void MainWindow::tableRemoveAll() 444 | { 445 | ui->tableWidget->clear(); 446 | ui->tableWidget->setHorizontalHeaderLabels(QStringList()); 447 | ui->tableWidget->setRowCount(0); 448 | ui->tableWidget->setColumnCount(0); 449 | } 450 | 451 | -------------------------------------------------------------------------------- /第二次实验/编译原理实验二/源代码文件夹/regex2dfa/mainwindow.h: -------------------------------------------------------------------------------- 1 | #ifndef MAINWINDOW_H 2 | #define MAINWINDOW_H 3 | 4 | #include 5 | #include 6 | 7 | #include "nfa.h" 8 | #include "dfa.h" 9 | 10 | QT_BEGIN_NAMESPACE 11 | namespace Ui { class MainWindow; } 12 | QT_END_NAMESPACE 13 | 14 | class MainWindow : public QMainWindow 15 | { 16 | Q_OBJECT 17 | 18 | public: 19 | MainWindow(QWidget *parent = nullptr); 20 | ~MainWindow(); 21 | 22 | private: 23 | Ui::MainWindow *ui; 24 | 25 | NFA nfa; 26 | DFA dfa; 27 | DFA miniDFA; 28 | QString code; 29 | 30 | static QString regexListPreprocessing(QStringList allRegex); 31 | static QString regexToPostFix(QString re); 32 | 33 | void tableRemoveAll(void); 34 | }; 35 | #endif // MAINWINDOW_H 36 | -------------------------------------------------------------------------------- /第二次实验/编译原理实验二/源代码文件夹/regex2dfa/mainwindow.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | MainWindow 4 | 5 | 6 | 7 | 0 8 | 0 9 | 800 10 | 600 11 | 12 | 13 | 14 | MainWindow 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 宋体 26 | 10 27 | 28 | 29 | 30 | 1 31 | 32 | 33 | <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> 34 | <html><head><meta name="qrichtext" content="1" /><style type="text/css"> 35 | p, li { white-space: pre-wrap; } 36 | </style></head><body style=" font-family:'宋体'; font-size:10pt; font-weight:400; font-style:normal;"> 37 | <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'SimSun'; font-size:11pt; font-weight:600;">Regex2DFA</span><span style=" font-family:'SimSun'; font-size:11pt;">是通过输入正则表达式组,将以&quot;_&quot;开头的变量所代表的正则表达式转换为NFA、DFA、最小化DFA的软件。</span></p> 38 | <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'SimSun'; font-size:11pt;">(以</span><span style=" font-family:'SimSun'; font-size:11pt; color:#00ff00;">绿色</span><span style=" font-family:'SimSun'; font-size:11pt;">标记始态,以</span><span style=" font-family:'SimSun'; font-size:11pt; color:#ff0000;">红色</span><span style=" font-family:'SimSun'; font-size:11pt;">标记终态)</span></p> 39 | <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'SimSun'; font-size:11pt;"><br /></p> 40 | <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'SimSun'; font-size:11pt;">其中,软件实现了:</span></p> 41 | <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'SimSun'; font-size:11pt;">1. </span><span style=" font-family:'SimSun'; font-size:11pt; font-weight:600;">分析</span><span style=" font-family:'SimSun'; font-size:11pt;">(左侧第一个按钮,按下该按钮后可以通过点击左侧2、3、4按钮显示不同内容)</span></p> 42 | <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'SimSun'; font-size:11pt;">2. </span><span style=" font-family:'SimSun'; font-size:11pt; font-weight:600;">正则表达式转为NFA</span><span style=" font-family:'SimSun'; font-size:11pt;">(左侧第二个按钮)</span></p> 43 | <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'SimSun'; font-size:11pt;">3. </span><span style=" font-family:'SimSun'; font-size:11pt; font-weight:600;">NFA转为DFA</span><span style=" font-family:'SimSun'; font-size:11pt;">(左侧第三个按钮)</span></p> 44 | <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'SimSun'; font-size:11pt;">4. </span><span style=" font-family:'SimSun'; font-size:11pt; font-weight:600;">DFA最小化</span><span style=" font-family:'SimSun'; font-size:11pt;">(左侧第四个按钮)</span></p> 45 | <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'SimSun'; font-size:11pt;">5. </span><span style=" font-family:'SimSun'; font-size:11pt; font-weight:600;">重置</span><span style=" font-family:'SimSun'; font-size:11pt;">(可以重新输入正则表达式)</span></p> 46 | <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'SimSun'; font-size:11pt;">点击分析按钮,实现正则表达式-&gt;NFA-&gt;DFA-&gt;最小化DFA</span></p> 47 | <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'SimSun'; font-size:11pt;"><br /></p> 48 | <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'SimSun'; font-size:11pt;">注:<br />1. 输入只能包含一个以&quot;_&quot;开头的正则表达式,否则软件可能会出现误解,产生不正确的NFA、DFA等;<br />2. 等号左侧的标识符仅包含字母、数字与下划线</span></p> 49 | <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'SimSun'; font-size:11pt;">3. 软件以#字符作为NFA转换的epsilon标识,因此,希望输入#字符,应当使用转义符号,输入\#才可以识别。</span></p> 50 | <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'SimSun'; font-size:11pt;"><br /></p> 51 | <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'SimSun'; font-size:11pt; color:#aa0000;">较长的正则表达式可能会分析较久,请您耐心等待,谢谢。</span></p></body></html> 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 0 66 | 0 67 | 68 | 69 | 70 | 71 | Times New Roman 72 | 18 73 | 74 | 75 | 76 | Regex2DFA 77 | 78 | 79 | Qt::AlignCenter 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 16777215 88 | 16777215 89 | 90 | 91 | 92 | 93 | 94 | 95 | 分析 96 | 97 | 98 | 99 | 100 | 101 | 102 | 显示NFA 103 | 104 | 105 | 106 | 107 | 108 | 109 | 显示DFA 110 | 111 | 112 | 113 | 114 | 115 | 116 | 最小化DFA 117 | 118 | 119 | 120 | 121 | 122 | 123 | 生成匹配代码 124 | 125 | 126 | 127 | 128 | 129 | 130 | 重置程序 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 0 145 | 0 146 | 147 | 148 | 149 | 150 | 151 | 152 | 请在下方框中写入正则表达式 153 | 154 | 155 | Qt::AlignCenter 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 0 170 | 0 171 | 172 | 173 | 174 | 175 | 16777215 176 | 16777215 177 | 178 | 179 | 180 | 181 | 182 | 183 | NFA、DFA展示表 184 | 185 | 186 | Qt::AlignCenter 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 0 202 | 0 203 | 800 204 | 21 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | -------------------------------------------------------------------------------- /第二次实验/编译原理实验二/源代码文件夹/regex2dfa/nfa.cpp: -------------------------------------------------------------------------------- 1 | #include "nfa.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "utils.h" 10 | 11 | NFA::NFA(int begin, int end): startState(begin), endState(end), stateNum(0), maxStateNum(100) { 12 | G.resize(maxStateNum); 13 | for (int i = 0; i < maxStateNum; i++) { 14 | G[i].resize(maxStateNum); 15 | } 16 | } 17 | 18 | void NFA::clear() 19 | { 20 | // 清空nfa 21 | for (int i = 0; i < maxStateNum; i++) { 22 | G[i].clear(); 23 | } 24 | G.clear(); 25 | maxStateNum = 100; 26 | stateNum = 0; 27 | startState = -1; 28 | endState = -1; 29 | G.resize(maxStateNum); 30 | for (int i = 0; i < maxStateNum; i++) { 31 | G[i].resize(maxStateNum); 32 | } 33 | stateSet.clear(); 34 | } 35 | 36 | void NFA::fromRegex(QString re) // 后缀表达式转NFA 37 | { 38 | QStack> s; 39 | for (int i = 0; i < re.size(); i++) { 40 | if (re[i] == '\\') { // 转义字符 41 | if (i < re.size() - 1) { 42 | allocateMemory(2); 43 | G[stateNum][stateNum + 1] = re[i + 1]; // 转义符不再出现 44 | s.append({stateNum, stateNum + 1}); // 入栈 45 | stateNum += 2; // 状态数量 + 2 46 | stateSet.insert(QString(re[i + 1])); 47 | } 48 | i++; 49 | } else if (re[i] == '*' || re[i] == '|' || re[i] == '.') { // 运算符 50 | if (re[i] == '.') { 51 | if (s.size() >= 2) { // 取出两个元素相连重新入栈 52 | QPair tail = s.top(); 53 | s.pop(); 54 | QPair head = s.top(); 55 | s.pop(); 56 | G[head.second][tail.first] = "epsilon"; // 连接操作 57 | s.append({head.first, tail.second}); // 重新入栈 58 | stateSet.insert("epsilon"); 59 | } 60 | } else if (re[i] == '|') { 61 | allocateMemory(2); 62 | if (s.size() >= 2) { // 取出两个元素相连重新入栈 63 | QPair left = s.top(); 64 | s.pop(); 65 | QPair right = s.top(); 66 | s.pop(); 67 | G[stateNum][left.first] = "epsilon"; 68 | G[stateNum][right.first] = "epsilon"; 69 | G[left.second][stateNum + 1] = "epsilon"; 70 | G[right.second][stateNum + 1] = "epsilon"; 71 | s.append({stateNum, stateNum + 1}); // 入栈 72 | stateNum += 2; // 状态数量 + 2 73 | stateSet.insert("epsilon"); 74 | } 75 | } else { 76 | allocateMemory(2); 77 | if (!s.empty()) { // 闭包为单元运算符,因此只需要取出一个元素 78 | QPair item = s.top(); 79 | s.pop(); 80 | G[stateNum][stateNum + 1] = "epsilon"; 81 | G[stateNum][item.first] = "epsilon"; 82 | G[item.second][stateNum + 1] = "epsilon"; 83 | G[item.second][item.first] = "epsilon"; 84 | s.append({stateNum, stateNum + 1}); // 入栈 85 | stateNum += 2; // 状态数量 + 2 86 | stateSet.insert("epsilon"); 87 | } 88 | } 89 | } else { 90 | if (re[i] == '#') { // epsilon 91 | allocateMemory(2); 92 | G[stateNum][stateNum + 1] = "epsilon"; 93 | s.append({stateNum, stateNum + 1}); // 入栈 94 | stateNum += 2; // 状态数量 + 2 95 | stateSet.insert("epsilon"); 96 | } else { // 其他非运算符 97 | allocateMemory(2); 98 | G[stateNum][stateNum + 1] = re[i]; 99 | s.append({stateNum, stateNum + 1}); // 入栈 100 | stateNum += 2; // 状态数量 + 2 101 | stateSet.insert(QString(re[i])); 102 | } 103 | } 104 | } 105 | if (!s.empty()){ 106 | QPair statePair = s.top(); 107 | startState = statePair.first; 108 | endState = statePair.second; 109 | } 110 | } 111 | 112 | void NFA::allocateMemory(int num) 113 | { 114 | // 当状态数即将超过最大状态时,分配更大的空间 115 | while (stateNum + num >= maxStateNum) { 116 | QVector> newG(2 * maxStateNum); 117 | for (int i = 0; i < 2 * maxStateNum; i++) { 118 | newG[i].resize(2 * maxStateNum); 119 | } 120 | for (int i = 0; i < maxStateNum; i++) { 121 | for (int j = 0; j < maxStateNum; j++) { 122 | newG[i][j] = G[i][j]; 123 | } 124 | } 125 | maxStateNum *= 2; 126 | G = newG; 127 | } 128 | } 129 | 130 | QSet NFA::epsilonClosure(QSet state) 131 | { 132 | while (true) { 133 | QSet tmpSet; 134 | for (int item: state) { 135 | for (int i = 0; i < maxStateNum; i++) { 136 | if (G[item][i] == "epsilon") { 137 | if (!state.contains(i)) { 138 | tmpSet.insert(i); 139 | } 140 | } 141 | } 142 | } 143 | if (tmpSet.empty()) break; 144 | state = state.unite(tmpSet); 145 | } 146 | return state; 147 | } 148 | 149 | QSet NFA::valueClosure(QSet state, QString value) 150 | { 151 | QSet result; 152 | for (int item: state) { 153 | for (int i = 0; i < maxStateNum; i++) { 154 | if (G[item][i] == value) { 155 | result.insert(i); 156 | } 157 | } 158 | } 159 | return result; 160 | } 161 | -------------------------------------------------------------------------------- /第二次实验/编译原理实验二/源代码文件夹/regex2dfa/nfa.h: -------------------------------------------------------------------------------- 1 | #ifndef NFA_H 2 | #define NFA_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | class NFA 9 | { 10 | public: 11 | // 构造函数 12 | NFA(int begin = -1, int end = -1); 13 | void clear(); // 清空NFA 14 | void fromRegex(QString re); // 从后缀表达式构造NFA 15 | void allocateMemory(int num); // 分配G内存的函数 16 | QSet epsilonClosure(QSet state); // 计算epsilon闭包 17 | QSet valueClosure(QSet state, QString value); // 计算某个集合状态能通过value转移到的状态集合 18 | 19 | // 成员变量 20 | QVector> G; // 邻接矩阵 21 | QSet stateSet; // 存储所有状态类型 22 | int startState; // 表示起始状态 23 | int endState; // 表示终止状态 24 | int stateNum; // 表示状态数量 25 | int maxStateNum; // 表示当前最多存储的状态数量 26 | }; 27 | 28 | #endif // NFA_H 29 | -------------------------------------------------------------------------------- /第二次实验/编译原理实验二/源代码文件夹/regex2dfa/regex2dfa.pro: -------------------------------------------------------------------------------- 1 | QT += core gui 2 | 3 | greaterThan(QT_MAJOR_VERSION, 4): QT += widgets 4 | 5 | CONFIG += c++11 6 | 7 | # You can make your code fail to compile if it uses deprecated APIs. 8 | # In order to do so, uncomment the following line. 9 | #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 10 | 11 | SOURCES += \ 12 | codedialog.cpp \ 13 | dfa.cpp \ 14 | main.cpp \ 15 | mainwindow.cpp \ 16 | nfa.cpp \ 17 | utils.cpp 18 | 19 | HEADERS += \ 20 | codedialog.h \ 21 | dfa.h \ 22 | mainwindow.h \ 23 | nfa.h \ 24 | utils.h 25 | 26 | FORMS += \ 27 | codedialog.ui \ 28 | mainwindow.ui 29 | 30 | # Default rules for deployment. 31 | qnx: target.path = /tmp/$${TARGET}/bin 32 | else: unix:!android: target.path = /opt/$${TARGET}/bin 33 | !isEmpty(target.path): INSTALLS += target 34 | -------------------------------------------------------------------------------- /第二次实验/编译原理实验二/源代码文件夹/regex2dfa/utils.cpp: -------------------------------------------------------------------------------- 1 | #include "utils.h" 2 | 3 | int getPriority(const char &op) // 返回运算符优先级 4 | { 5 | switch (op) { 6 | case '(': 7 | case ')': 8 | return 0; 9 | case '*': 10 | return 4; 11 | case '|': 12 | return 1; 13 | case '.': 14 | return 2; 15 | default: 16 | return -1; 17 | } 18 | } 19 | 20 | bool isOperator(const char &ch) 21 | { 22 | switch (ch) { 23 | case '(': 24 | case ')': 25 | case '*': 26 | case '|': 27 | case '.': 28 | return true; // 运算符返回true 29 | default: 30 | return false; // 非运算符返回false 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /第二次实验/编译原理实验二/源代码文件夹/regex2dfa/utils.h: -------------------------------------------------------------------------------- 1 | #ifndef UTILS_H 2 | #define UTILS_H 3 | 4 | int getPriority(const char &op); 5 | bool isOperator(const char &ch); 6 | 7 | #endif // UTILS_H 8 | -------------------------------------------------------------------------------- /第四次实验/编译原理实验四/文档文件夹/编译原理实验四.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WA-automat/Compiler_Design_SCNU/0f3e92c521e9b785ae8af9784feade5078582a6f/第四次实验/编译原理实验四/文档文件夹/编译原理实验四.pdf -------------------------------------------------------------------------------- /第四次实验/编译原理实验四/源程序文件夹/LALR.pro: -------------------------------------------------------------------------------- 1 | QT += core gui 2 | 3 | greaterThan(QT_MAJOR_VERSION, 4): QT += widgets 4 | 5 | CONFIG += c++11 6 | 7 | # You can make your code fail to compile if it uses deprecated APIs. 8 | # In order to do so, uncomment the following line. 9 | #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 10 | 11 | SOURCES += \ 12 | lalr.cpp \ 13 | main.cpp \ 14 | mainwindow.cpp 15 | 16 | HEADERS += \ 17 | lalr.h \ 18 | mainwindow.h 19 | 20 | FORMS += \ 21 | mainwindow.ui 22 | 23 | # Default rules for deployment. 24 | qnx: target.path = /tmp/$${TARGET}/bin 25 | else: unix:!android: target.path = /opt/$${TARGET}/bin 26 | !isEmpty(target.path): INSTALLS += target 27 | -------------------------------------------------------------------------------- /第四次实验/编译原理实验四/源程序文件夹/lalr.cpp: -------------------------------------------------------------------------------- 1 | #include "lalr.h" 2 | 3 | #include 4 | 5 | LALR::LALR(): size(0) 6 | { 7 | 8 | } 9 | 10 | void LALR::buildLR1(State faState, QHash> grammars, QVector nonFinalizers, 11 | QHash > firstSet, QHash > followSet) 12 | { 13 | int faStateId = stateHash[faState]; 14 | 15 | // 找到可能的转移方法 16 | QStringList changeMethods; 17 | for (auto faItem: faState.st) { 18 | if (faItem.pos < faItem.rule.size()) { 19 | changeMethods.append(faItem.rule[faItem.pos]); 20 | } 21 | } 22 | 23 | // 深搜每个转移 24 | for (QString changeMethod: changeMethods) { 25 | State sonState = State::change(faState, changeMethod, grammars, nonFinalizers, firstSet); 26 | if (sonState.st.empty()) continue; 27 | if (stateHash.contains(sonState)) { 28 | // 该状态已经存在 29 | int sonStateId = stateHash[sonState]; 30 | changeHash[faStateId].insert(changeMethod, sonStateId); 31 | } else { 32 | // 该状态不存在 33 | stateHash[sonState] = size++; 34 | changeHash[faStateId].insert(changeMethod, stateHash[sonState]); 35 | buildLR1(sonState, grammars, nonFinalizers, firstSet, followSet); 36 | } 37 | 38 | qDebug() << faStateId << ' ' << changeMethod << ' ' << stateHash[sonState]; 39 | } 40 | 41 | } 42 | 43 | void LALR::buildLALR1(LALR lr1) 44 | { 45 | // 并查集(合并同心项) 46 | int* p = new int[lr1.size]; 47 | for (int i = 0; i < lr1.size; i++) { 48 | p[i] = i; 49 | } 50 | std::function find = [&](int x) { 51 | if (p[x] != x) p[x] = find(p[x]); 52 | return p[x]; 53 | }; 54 | QHash revlr1StateHash; 55 | for (auto state: lr1.stateHash.keys()) { 56 | revlr1StateHash[lr1.stateHash[state]] = state; 57 | } 58 | 59 | // 状态合并 60 | for (int i = 0; i < lr1.size - 1; i++) { 61 | for (int j = i + 1; j < lr1.size; j++) { 62 | if (State::haveSameCore(revlr1StateHash[i], revlr1StateHash[j])) { 63 | p[find(j)] = find(i); 64 | } 65 | } 66 | } 67 | 68 | // LR1到LALR1状态映射 69 | QHash cntChangeSet; 70 | int idx = 0; 71 | for (int i = 0; i < lr1.size; i++) { 72 | if (!cntChangeSet.contains(find(i))) { 73 | cntChangeSet[find(i)] = idx++; 74 | } 75 | } 76 | size = cntChangeSet.size(); 77 | 78 | // 建立LALR状态集 79 | QHash revlalr1StateHash; 80 | for (int i = 0; i < lr1.size; i++) { 81 | if (!revlalr1StateHash.contains(cntChangeSet[find(i)])) { 82 | revlalr1StateHash[cntChangeSet[find(i)]] = revlr1StateHash[i]; 83 | } else { 84 | for (auto item: revlr1StateHash[i].st) { 85 | for (auto lalrItem: revlalr1StateHash[cntChangeSet[find(i)]].st) { 86 | auto tmpItem = lalrItem; 87 | if (Item::haveSameCore(item, lalrItem)) { 88 | lalrItem.next.unite(item.next); 89 | } 90 | revlalr1StateHash[cntChangeSet[find(i)]].st.remove(tmpItem); 91 | revlalr1StateHash[cntChangeSet[find(i)]].st.insert(lalrItem); 92 | } 93 | } 94 | } 95 | } 96 | // for (auto state: revlalr1StateHash) { 97 | // for (auto item: state.st) { 98 | // qDebug() << item.name << ' ' << item.rule << ' ' << item.next << ' ' << item.pos; 99 | // } 100 | // qDebug(); 101 | // } 102 | for (auto idx: revlalr1StateHash.keys()) { 103 | stateHash[revlalr1StateHash[idx]] = idx; 104 | } 105 | 106 | // 建立LALR转移集 107 | for (int i = 0; i < lr1.size; i++) { 108 | for (auto changeMethod: lr1.changeHash[i].keys()) { 109 | if (lr1.changeHash[i].contains(changeMethod)) { 110 | changeHash[cntChangeSet[find(i)]].insert(changeMethod, cntChangeSet[find(lr1.changeHash[i][changeMethod])]); 111 | } 112 | } 113 | } 114 | } 115 | 116 | State State::closure(State I, QHash > grammars, QVector nonFinalizers, QHash> firstSet) 117 | { 118 | State J = I; 119 | while (true) { 120 | for (Item item: J.st) { 121 | qDebug() << item.name << ' ' << item.rule << ' ' << item.next << ' ' << item.pos; 122 | // 下一个字符是非终结符 123 | if (item.pos < item.rule.size() && nonFinalizers.contains(item.rule[item.pos])) { 124 | for (auto grammar: grammars[item.rule[item.pos]]) { 125 | qDebug() << grammar; 126 | 127 | for (auto nextItem: item.next) { 128 | qDebug() << nextItem; 129 | 130 | QStringList betaRule = item.rule.mid(item.pos + 1); 131 | qDebug() << betaRule; 132 | 133 | if (nextItem != "@") betaRule.push_back(nextItem); 134 | 135 | // 计算first集合 136 | int k = 0; 137 | QSet tmpSet; 138 | while (k < betaRule.size()) { 139 | bool sign = false; 140 | if (firstSet[betaRule[k]].contains("@")) sign = true; 141 | tmpSet.unite(firstSet[betaRule[k]].subtract(QSet({"@"}))); 142 | if (sign) firstSet[betaRule[k]].insert("@"); 143 | else break; 144 | k++; 145 | } 146 | if (k == betaRule.size()) tmpSet.insert("@"); 147 | 148 | qDebug() << k << ' ' << tmpSet; 149 | 150 | // 遍历first集合中的每个元素 151 | for (auto b: tmpSet) { 152 | 153 | Item newItem; 154 | newItem.name = item.rule[item.pos]; 155 | newItem.rule = grammar; 156 | newItem.next.insert(b); 157 | newItem.pos = 0; 158 | 159 | if (!J.st.contains(newItem)) { 160 | bool mark = true; 161 | for (auto it: J.st) { 162 | if (Item::haveSameCore(it, newItem)) { 163 | J.st.remove(it); 164 | it.next.unite(newItem.next); 165 | J.st.insert(it); 166 | mark = false; 167 | break; 168 | } 169 | } 170 | if (mark) { 171 | J.st.insert(newItem); 172 | } 173 | } 174 | } 175 | 176 | } 177 | 178 | } 179 | } 180 | } 181 | if (I == J) break; 182 | I = J; 183 | } 184 | qDebug(); 185 | for (auto item: J.st) { 186 | qDebug() << item.name << ' ' << item.rule << ' ' << item.next << ' ' << item.pos; 187 | } 188 | return J; 189 | } 190 | 191 | State State::change(State I, QString X, QHash > grammars, QVector nonFinalizers, QHash> firstSet) 192 | { 193 | State I_new; 194 | for (auto item: I.st) { 195 | if (item.pos >= item.rule.size() || item.rule[item.pos] != X) continue; 196 | 197 | Item newItem; 198 | newItem.name = item.name; 199 | newItem.rule = item.rule; 200 | newItem.next = item.next; 201 | newItem.pos = item.pos + 1; 202 | 203 | // 判断I_new中是否已经出现了newItem 204 | if (!I_new.st.contains(newItem)) { 205 | bool mark = true; 206 | for (auto it: I_new.st) { 207 | if (Item::haveSameCore(it, newItem)) { 208 | I_new.st.remove(it); 209 | it.next.unite(newItem.next); 210 | I_new.st.insert(it); 211 | mark = false; 212 | break; 213 | } 214 | } 215 | if (mark) { 216 | I_new.st.insert(newItem); 217 | } 218 | } 219 | } 220 | if (I_new.st.empty()) return I_new; 221 | else return closure(I_new, grammars, nonFinalizers, firstSet); 222 | } 223 | 224 | bool State::haveSameCore(State i, State j) 225 | { 226 | if (i.st.size() != j.st.size()) return false; 227 | auto iList = i.st.toList(); 228 | auto jList = j.st.toList(); 229 | qSort(iList.begin(), iList.end()); 230 | qSort(jList.begin(), jList.end()); 231 | for (int cnt = 0; cnt < i.st.size(); cnt++) { 232 | if (!Item::haveSameCore(iList[cnt], jList[cnt])) { 233 | return false; 234 | } 235 | } 236 | return true; 237 | } 238 | 239 | bool Item::haveSameCore(Item i, Item j) 240 | { 241 | if (i.name == j.name && i.rule == j.rule && i.pos == j.pos) return true; 242 | else return false; 243 | } 244 | 245 | uint qHash(const Item& key) 246 | { 247 | return qHash(key.name) + qHash(key.rule) + qHash(key.next) + qHash(key.pos); 248 | } 249 | 250 | uint qHash(const State &key) 251 | { 252 | return qHash(key.st); 253 | } 254 | -------------------------------------------------------------------------------- /第四次实验/编译原理实验四/源程序文件夹/lalr.h: -------------------------------------------------------------------------------- 1 | #ifndef LALR_H 2 | #define LALR_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | // 单条规则 11 | typedef struct Item { 12 | QString name; 13 | QStringList rule; 14 | QSet next; 15 | int pos; 16 | 17 | static bool haveSameCore(Item i, Item j); 18 | 19 | friend bool operator==(const Item a, const Item b) { 20 | return a.name == b.name && a.rule == b.rule && a.next == b.next && a.pos == b.pos; 21 | } 22 | 23 | friend bool operator<(const Item a, const Item b) { 24 | if (a.name == b.name) { 25 | if (a.rule == b.rule) { 26 | if (a.pos == b.pos) { 27 | return a.pos < b.pos; 28 | } 29 | return a.pos < b.pos; 30 | } 31 | return a.rule < b.rule; 32 | } 33 | return a.name < b.name; 34 | } 35 | }Item; 36 | 37 | uint qHash(const Item& key); 38 | 39 | // 单个状态 40 | typedef struct State { 41 | QSet st; 42 | static State closure(State I, QHash> grammars, QVector nonFinalizers, QHash> firstSet); 43 | static State change(State I, QString X, QHash> grammars, QVector nonFinalizers, QHash> firstSet); 44 | 45 | static bool haveSameCore(State i, State j); 46 | 47 | friend bool operator==(const State a, const State b) { 48 | return a.st == b.st; 49 | } 50 | 51 | }State; 52 | 53 | uint qHash(const State& key); 54 | 55 | // 分析表结点 56 | typedef struct LALR1TableItem { 57 | int kind; // 1 表示移进、2 表示规约、3 表示非终结符移进、4 表示接受 58 | int idx; 59 | }LALR1TableItem; 60 | 61 | typedef struct AnalysisItem { 62 | int kind; 63 | int state; 64 | QString ch; 65 | }AnalysisItem; 66 | 67 | // LALR结构 68 | class LALR 69 | { 70 | public: 71 | LALR(); 72 | 73 | // 成员变量 74 | int size; 75 | QHash stateHash; 76 | QHash> changeHash; 77 | 78 | // 构建LR1 79 | void buildLR1(State faState, QHash> grammars, QVector nonFinalizers, 80 | QHash> firstSet, QHash> followSet); 81 | 82 | // 构建LALR1 83 | void buildLALR1(LALR lr1); 84 | 85 | }; 86 | 87 | #endif // LALR_H 88 | -------------------------------------------------------------------------------- /第四次实验/编译原理实验四/源程序文件夹/main.cpp: -------------------------------------------------------------------------------- 1 | #include "mainwindow.h" 2 | 3 | #include 4 | 5 | int main(int argc, char *argv[]) 6 | { 7 | QApplication a(argc, argv); 8 | MainWindow w; 9 | w.show(); 10 | return a.exec(); 11 | } 12 | -------------------------------------------------------------------------------- /第四次实验/编译原理实验四/源程序文件夹/mainwindow.h: -------------------------------------------------------------------------------- 1 | #ifndef MAINWINDOW_H 2 | #define MAINWINDOW_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "lalr.h" 10 | 11 | QT_BEGIN_NAMESPACE 12 | namespace Ui { class MainWindow; } 13 | QT_END_NAMESPACE 14 | 15 | class MainWindow : public QMainWindow 16 | { 17 | Q_OBJECT 18 | 19 | public: 20 | MainWindow(QWidget *parent = nullptr); 21 | ~MainWindow(); 22 | 23 | private: 24 | Ui::MainWindow *ui; 25 | 26 | // 起始符 27 | QString startString; 28 | 29 | // 存储非终结符 30 | QVector nonFinalizers; 31 | 32 | // 存储文法规则 33 | QHash> grammars; 34 | 35 | // first集合与follow集合 36 | QHash> firstSet; 37 | QHash> followSet; 38 | 39 | // 规约规则存储 40 | QVector recursion; 41 | 42 | // LALR1_table 43 | QHash> LALR1_table; 44 | 45 | }; 46 | #endif // MAINWINDOW_H 47 | -------------------------------------------------------------------------------- /第四次实验/编译原理实验四/源程序文件夹/mainwindow.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | MainWindow 4 | 5 | 6 | 7 | 0 8 | 0 9 | 1619 10 | 687 11 | 12 | 13 | 14 | MainWindow 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 宋体 26 | 12 27 | 28 | 29 | 30 | 文法规则: 31 | 32 | 33 | Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter 34 | 35 | 36 | 0 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 12 51 | 52 | 53 | 54 | 待分析句子: 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 打开文法文件 71 | 72 | 73 | 74 | 75 | 76 | 77 | 保存文法文件 78 | 79 | 80 | 81 | 82 | 83 | 84 | 文法分析 85 | 86 | 87 | 88 | 89 | 90 | 91 | 分析句子 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> 102 | <html><head><meta name="qrichtext" content="1" /><style type="text/css"> 103 | p, li { white-space: pre-wrap; } 104 | </style></head><body style=" font-family:'SimSun'; font-size:9pt; font-weight:400; font-style:normal;"> 105 | <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">LALR(1)分析生成器:</span></p> 106 | <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">1. 通过输入文法规则:<span style=" color:#ff0000;">符号之间需要使用空格隔开,并且要求左侧的非终结符只能包含一个单词,单词之后有空格与-&gt;</span></p> 107 | <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">(如:E -&gt; T + T; F -&gt; ( E ) | n 等)</p> 108 | <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">生成对应的First集合、Follow集合、LR(1)的DFA表、LALR(1)的DFA表、LALR1分析表。</p> 109 | <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> 110 | <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">2. 通过文法分析后输入待分析句子,并点击分析句子按钮,可以实现使用LALR(1)分析表进行句子的分析。</p> 111 | <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> 112 | <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">注意:</span><span style=" color:#ff0000;">LALR(1)DFA表格与LALR(1)分析表中的状态编号并不一定相同,各自的初态已经用红色标出。</span></p></body></html> 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 4 123 | 124 | 125 | 126 | first与follow集合 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 12 137 | 138 | 139 | 140 | Qt::LeftToRight 141 | 142 | 143 | First集合 144 | 145 | 146 | Qt::AlignCenter 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 12 164 | 165 | 166 | 167 | Qt::LeftToRight 168 | 169 | 170 | follow集合 171 | 172 | 173 | Qt::AlignCenter 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | LR(1)DFA表格 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 12 198 | 199 | 200 | 201 | LR(1)DFA表格 202 | 203 | 204 | Qt::AlignCenter 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | LALR(1)DFA表格 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 12 229 | 230 | 231 | 232 | LALR(1)DFA表格 233 | 234 | 235 | Qt::AlignCenter 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | LALR(1)分析表 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 12 260 | 261 | 262 | 263 | LALR(1)分析表 264 | 265 | 266 | Qt::AlignCenter 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 句子分析过程表 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 12 291 | 292 | 293 | 294 | 句子分析过程表 295 | 296 | 297 | Qt::AlignCenter 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 0 317 | 0 318 | 1619 319 | 21 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | --------------------------------------------------------------------------------