编译原理--词法分析器(python语言实现)

article/2025/11/1 10:17:05

词法分析器

最近在学习编译原理。由于实验要求有词法分析器,这里我就先记录一下词法分析器实现过程以及具体思路。

目标语言

此处我选择的目标语言是c语言的子集来进行词法分析。

实现语言

此处我选用的语言是python,主要还是考虑到python的数据结构比较强大而且包容性强。并且我pyqt用的比较熟练,很容易设计出GUI界面。关于pyqt的相关内容网上资料比较少对初学者不是很友好,我下面会出一些关于pyqt的教程,还望持续关注!

词法分析器主要工作

  • 从源程序文件中读入字符
  • 统计行数和列数用于进行错误定位
  • 识别出单词并用(内码,属性)二元式表示
  • 识别出错误记录报告错误但不会终止扫描
  • 填写标识符表

设计思路

词法分析不必要设计成单独的一遍,我认为词法分析器应该设计成一个子程序,每当语法分析需要一个单词符号时,那么此时向词法分析器传递一个输入串,词法分析器便要能分析出这个输入串中的单词。

设计流程图

在这里插入图片描述

算法思路

对于单词的分析关键在于第一个字符的性质。第一个字符的性质决定了下面的单词分析进程。如果第一个字符是一个数字那么下面这个单词就要判断是否为常量。接下来读取的如果是字符除了是e或E其他字符都可以直接判断此单词非法为error。因此这里可以将其单独分离出一个函数,这里我取名为isDigit()函数。其他包括标识符的判定以及算术或逻辑运算符的判定也可以按照此思路分离出相应的函数。
函数表
在这里插入图片描述

源程序代码

一些初始设定

self.reserveWord = ["auto", "break", "case", "char", "const", "continue","default", "do", "double", "else", "enum", "extern","float", "for", "goto", "if", "int", "long","register", "return", "short", "signed", "sizeof", "static","struct", "switch", "typedef", "union", "unsigned", "void","volatile", "while"]  # c++中的关键字self.operatorOrDelimiter = ["+", "-", "*", "/", "<", "<=", ">", ">=", "=", "==","!=", ";", "(", ")", "^", ",", "\"", "\'", "#", "&","&&", "|", "||", "%", "~", "<<", ">>", "[", "]", "{","}", "\\", ".", ":", "!"]  # c++中的一些符号self.Delimiter = [";", "(", ")", ",", "#", "[", "]", "{", "}", "\\"]self.RelationOperation = ["<", "<=", ">", ">=", "=", "==", "!=", "^", "&", "&&", "|", "||", "<<", ">>", "!"]self.Operator = ["+", "-", "*", "/", "%", "~", "+=", "*=", "/=", "-=","++", "--"]

处理开头以数字开头的字符串

这里分为四种情况
在这里插入图片描述

部分代码
// 判断数字代码def IsDigits(self, inString, pos):flag = Falsefor i in inString:pos += 1if i.isdigit():self.token += str(i)flag = Trueelif i == '.' and i not in self.token and 'e' not in self.token and 'E' not in self.token:self.token += str(i)elif i == 'e' or i == 'E' and i not in self.token:  # 处理含E或e的合法指数情况self.token += str(i)else:if i in self.operatorOrDelimiter or i == ' ' or i == '\n':flag = Trueelse:flag = Falsebreakreturn flag, pos
对应的scan()函数中处理数字开头的代码
        if inString[0].isdigit():judge, index = self.IsDigits(inString, 0)if judge:"""if '.' in self.token: # 此处是对常量的转化过程此处写成注释print("--------")print(float(self.token))print("--------")elif 'e' not in self.token and 'E' not in self.token:print("--------")print(int(self.token))print("--------")else:num1 = 0num2 = 0if 'E' in self.token:l = self.token.split('E')if '.' in l[0]:num1 = float(l[0])else:num1 = int(l[0])num2 = int(l[1])elif 'e' in self.token:l = self.token.split('e')if '.' in l[0]:num1 = float(l[0])else:num1 = int(l[0])num2 = int(l[1])for i in range(0, num2):num1 *= 10print("--------")print(num1)print("--------")"""self.result.append([self.token, "常数", (row, col)])else:self.result.append([self.token, "ERROR", (row, col)])if index - 1 < len(inString) and index - 1 > 0:if index == len(inString):print(inString[len(inString) - 1])self.scan(inString[len(inString) - 1], row, col)else:self.scan(inString[index - 1:], row, col)

处理以字母开头的字符串

此处以字母开头的字符串可能出现的情况为:
  • 标识符
  • 关键字
  • 非法字符串
对于这里的判断要注意几种情况:
  • 类似i++这种一个标识符后面跟着算术或逻辑运算符
  • i;后面跟着终结符这种比较好判断
  • 单独的一个标识符或关键字 如 int这种。
部分代码
     def isReserve(self, target):  # 判断是否为关键字if target in self.reserveWord:return Truereturn Falsedef isMark(self, inString, pos):flag = Falsefor i in inString:pos += 1if i.isalpha() or i.isdigit() or i == '_':self.token += str(i)flag = Trueelif i in self.operatorOrDelimiter:  # 遇到算术/逻辑/分隔符结束搜索flag = Truebreakelse:flag = Falsereturn flag, pos
对应scan()中以字母开头部分代码
                elif inString[0].isalpha():judge, index = self.isMark(inString, 0)if self.isReserve(self.token):self.result.append([self.token, "关键字", (row, col)])else:self.result.append([self.token, "标识符", (row, col)])if index <= len(inString) and not inString[index - 1].isalpha():self.scan(inString[index - 1:], row, col)elif inString[0] == '\'':judge, index = self.isChar(inString, 0)if judge:self.result.append([self.token, "字符常量", (row, col)])if index < len(inString) and index - 1 >= 0:self.scan(inString[index - 1:], row, col)elif inString[0] == '\"':judge, index = self.isString(inString, 0)index = index + 1  # 最后一个”不能算if judge:self.result.append([self.token, "字符串常量", (row, col)])if index < len(inString) and index - 1 >= 0:self.scan(inString[index - 1:], row, col)elif inString[0] in self.Operator or inString[0] in self.RelationOperation:index = self.IsOperator(inString, 0)if self.token in self.Operator:self.result.append([self.token, "算术运算符", (row, col)])elif self.token in self.RelationOperation:self.result.append([self.token, "关系运算符", (row, col)])else:self.result.append([self.token, "ERROR", (row, col)])if index <= len(inString) and index - 1 >= 0:self.scan(inString[index - 1:], row, col)

处理一些算术/逻辑运算符的情况

这里主要是考虑如下一些情况
  • 运算符在开头这里也是有可能的比如 ++i;这在c以及c++中均为合法语句,词法分析器应该能够识别出这一个串中的++、i单词
  • 运算符在内部,这也是有可能的比如a+b,词法分析器也要识别出a、+、b这几个单词
部分代码
          def IsOperator(self, inString, pos):if len(inString) == 1:self.token += str(inString[0])return posfor i in inString[0:]:pos += 1if i in self.operatorOrDelimiter:self.token += str(i)else:breakreturn pos
scan()函数部分代码
                 elif inString[0] in self.Operator or inString[0] in self.RelationOperation:index = self.IsOperator(inString, 0)if self.token in self.Operator:self.result.append([self.token, "算术运算符", (row, col)])elif self.token in self.RelationOperation:self.result.append([self.token, "关系运算符", (row, col)])else:self.result.append([self.token, "ERROR", (row, col)])if index <= len(inString) and index - 1 >= 0:self.scan(inString[index - 1:], row, col)

至此一些关键处理代码已经实现,并经过测试后是可以使用的,上面代码部分只是我的思路,我使用了递归调用,这会有一个缺点就是无法更好的得出当前处理的位置,仍需改进。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

运行测试图片

更新内容

我加入了GUI界面并对其进行了代码优化,优化的代码在上面已经进行了更新。下面贴出整体GUI部分代码

# -*- coding: utf-8 -*-# Form implementation generated from reading ui file 'analysis.ui'
#
# Created by: PyQt5 UI code generator 5.15.4
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again.  Do not edit this file unless you know what you are doing.from PyQt5 import QtCore, QtGui, QtWidgetsclass Ui_MainWindow(object):def setupUi(self, MainWindow):MainWindow.setObjectName("MainWindow")MainWindow.resize(961, 816)self.centralwidget = QtWidgets.QWidget(MainWindow)self.centralwidget.setObjectName("centralwidget")self.code = QtWidgets.QTextEdit(self.centralwidget)self.code.setGeometry(QtCore.QRect(10, 10, 781, 391))self.code.setObjectName("code")self.result = QtWidgets.QTextEdit(self.centralwidget)self.result.setGeometry(QtCore.QRect(0, 410, 951, 361))self.result.setObjectName("result")self.gridLayoutWidget = QtWidgets.QWidget(self.centralwidget)self.gridLayoutWidget.setGeometry(QtCore.QRect(800, 50, 161, 231))self.gridLayoutWidget.setObjectName("gridLayoutWidget")self.gridLayout = QtWidgets.QGridLayout(self.gridLayoutWidget)self.gridLayout.setContentsMargins(0, 0, 0, 0)self.gridLayout.setObjectName("gridLayout")self.pushButton = QtWidgets.QPushButton(self.gridLayoutWidget)self.pushButton.setObjectName("pushButton")self.gridLayout.addWidget(self.pushButton, 0, 0, 1, 1)self.pushButton_2 = QtWidgets.QPushButton(self.gridLayoutWidget)self.pushButton_2.setObjectName("pushButton_2")self.gridLayout.addWidget(self.pushButton_2, 1, 0, 1, 1)MainWindow.setCentralWidget(self.centralwidget)self.menubar = QtWidgets.QMenuBar(MainWindow)self.menubar.setGeometry(QtCore.QRect(0, 0, 961, 26))self.menubar.setObjectName("menubar")MainWindow.setMenuBar(self.menubar)self.statusbar = QtWidgets.QStatusBar(MainWindow)self.statusbar.setObjectName("statusbar")MainWindow.setStatusBar(self.statusbar)self.retranslateUi(MainWindow)QtCore.QMetaObject.connectSlotsByName(MainWindow)def retranslateUi(self, MainWindow):_translate = QtCore.QCoreApplication.translateMainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))self.pushButton.setText(_translate("MainWindow", "词法分析"))self.pushButton_2.setText(_translate("MainWindow", "重试"))

主控窗口

import sysfrom PyQt5 import QtWidgets, QtCore
from analysis import Analysis
from MainWindow import Ui_MainWindowclass My_Window(QtWidgets.QMainWindow, Ui_MainWindow):def __init__(self):super(My_Window, self).__init__()self.setupUi(self)@QtCore.pyqtSlot()def on_pushButton_clicked(self):deal = Analysis()string = self.code.toPlainText()j = 0results = []for i in string.split('\n'):if i != '':initial = i.split(' ')col = 1for s in initial:deal.scan(s, j + 1, col)col += 1for res in deal.result:results.append(res)deal.result = []j += 1title = "单词        二元序列        类 型        位置(行,列)\n          (单词种别,单词属性)\n"for result in results:title += '{:<10}{:<20}{:<20}{:<15}'.format(str(result[0]),'(' + str(deal.dic[result[1]]) + ',' + result[1] + ')', result[1], str(result[2])) + '\n'self.result.setText(title)if __name__ == '__main__':app = QtWidgets.QApplication(sys.argv)my_window = My_Window()my_window.show()sys.exit(app.exec())

给您的建议

各位看到这里应该对我的思路有了一定的认识,但我的水平比较低,而且表达能力不是很强,如果有哪些不懂得地方,欢迎与我联系。我希望各位能够亲自动手实现,其实并不是很难。我使用了递归来进行解析,其实并不是一定要使用,而且递归只会徒增程序得复杂性。我进行了许多边界测试,但仍不是很全。我看来,在设计时没必要考虑过多得边界问题,等我们程序大致框架搭起来了以后,通过运行测试边界,然后再进行更改调试效果会更好。我进行了更新,但关于具体类的实现我还是不能贴出来!如果有帮助还请点点赞

由于我们编译原理课程实验还未验收此处我就不把完整代码放出但我把截图放在下方,希望大家可以对照参考同时也欢迎私信我交流讨论。
如果您想要完整代码,欢迎私信我并说明用途,感谢您的支持!
在这里插入图片描述

我又重新更新完善了一下此处把代码贴出,欢迎大家进行测试,如果有什么需要改进的地方欢迎指出~~

import sysfrom PyQt5 import QtWidgets, QtCore
from analysis import Analysis
from MainWindow import Ui_MainWindowclass My_Window(QtWidgets.QMainWindow, Ui_MainWindow):def __init__(self):super(My_Window, self).__init__()self.setupUi(self)@QtCore.pyqtSlot()def on_pushButton_clicked(self):deal = Analysis()string = self.code.toPlainText()j = 0results = []deal.scan(string,1,1)for i in string.split('\n'):if i != '':initial = i.split(' ')col = 1for s in initial:deal.scan(s, j + 1, col)col += 1for res in deal.result:results.append(res)deal.result = []j += 1title = "单词        二元序列        类 型        位置(行,列)\n          (单词种别,单词属性)\n"for result in results:title += '{:<10}{:<20}{:<20}{:<15}'.format(str(result[0]),'(' + str(deal.dic[result[1]]) + ',' + result[1] + ')', result[1], str(result[2])) + '\n'self.result.setText(title)@QtCore.pyqtSlot()def on_pushButton_2_clicked(self):self.result.clear()self.code.clear()if __name__ == '__main__':app = QtWidgets.QApplication(sys.argv)my_window = My_Window()my_window.show()sys.exit(app.exec())
# -*- coding: utf-8 -*-# Form implementation generated from reading ui file 'analysis.ui'
#
# Created by: PyQt5 UI code generator 5.15.4
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again.  Do not edit this file unless you know what you are doing.from PyQt5 import QtCore, QtGui, QtWidgetsclass Ui_MainWindow(object):def setupUi(self, MainWindow):MainWindow.setObjectName("MainWindow")MainWindow.resize(961, 816)self.centralwidget = QtWidgets.QWidget(MainWindow)self.centralwidget.setObjectName("centralwidget")self.code = QtWidgets.QTextEdit(self.centralwidget)self.code.setGeometry(QtCore.QRect(10, 10, 781, 391))self.code.setObjectName("code")self.result = QtWidgets.QTextEdit(self.centralwidget)self.result.setGeometry(QtCore.QRect(0, 410, 951, 361))self.result.setObjectName("result")self.gridLayoutWidget = QtWidgets.QWidget(self.centralwidget)self.gridLayoutWidget.setGeometry(QtCore.QRect(800, 50, 161, 231))self.gridLayoutWidget.setObjectName("gridLayoutWidget")self.gridLayout = QtWidgets.QGridLayout(self.gridLayoutWidget)self.gridLayout.setContentsMargins(0, 0, 0, 0)self.gridLayout.setObjectName("gridLayout")self.pushButton = QtWidgets.QPushButton(self.gridLayoutWidget)self.pushButton.setObjectName("pushButton")self.gridLayout.addWidget(self.pushButton, 0, 0, 1, 1)self.pushButton_2 = QtWidgets.QPushButton(self.gridLayoutWidget)self.pushButton_2.setObjectName("pushButton_2")self.gridLayout.addWidget(self.pushButton_2, 1, 0, 1, 1)MainWindow.setCentralWidget(self.centralwidget)self.menubar = QtWidgets.QMenuBar(MainWindow)self.menubar.setGeometry(QtCore.QRect(0, 0, 961, 26))self.menubar.setObjectName("menubar")MainWindow.setMenuBar(self.menubar)self.statusbar = QtWidgets.QStatusBar(MainWindow)self.statusbar.setObjectName("statusbar")MainWindow.setStatusBar(self.statusbar)self.retranslateUi(MainWindow)QtCore.QMetaObject.connectSlotsByName(MainWindow)def retranslateUi(self, MainWindow):_translate = QtCore.QCoreApplication.translateMainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))self.pushButton.setText(_translate("MainWindow", "词法分析"))self.pushButton_2.setText(_translate("MainWindow", "重试"))
"""
词法分析器的实现
"""class Analysis:def __init__(self):self.reserveWord = ["auto", "break", "case", "char", "const", "continue","default", "do", "double", "else", "enum", "extern","float", "for", "goto", "if", "int", "long","register", "return", "short", "signed", "sizeof", "static","struct", "switch", "typedef", "union", "unsigned", "void","volatile", "while"]  # c++中的关键字self.operatorOrDelimiter = ["+", "-", "*", "/", "<", "<=", ">", ">=", "=", "==","!=", ";", "(", ")", "^", ",", "\"", "\'", "#", "&","&&", "|", "||", "%", "~", "<<", ">>", "[", "]", "{","}", "\\", ".", ":", "!"]  # c++中的一些符号self.Delimiter = [";", "(", ")", ",", "#", "[", "]", "{", "}", "\\"]self.RelationOperation = ["<", "<=", ">", ">=", "=", "==", "!=", "^", "&", "&&", "|", "||", "<<", ">>", "!"]self.Operator = ["+", "-", "*", "/", "%", "~", "+=", "*=", "/=", "-=","++", "--"]self.token = ""  # 得到的单词self.result = []  # 储存扫描得到的单词信息结果self.dic = {'标识符': 2, '关键字': 1, "常数": 3, "算术运算符": 4, "关系运算符": 5, "字符串常量": 6,"字符常量": 7, "分界符": 8,"ERROR":9}def isReserve(self, target):  # 判断是否为关键字if target in self.reserveWord:return Truereturn Falsedef isMark(self, inString, pos):flag = Falsefor i in inString:pos += 1if i.isalpha() or i.isdigit() or i == '_':self.token += str(i)flag = Trueelif i in self.operatorOrDelimiter:  # 遇到算术/逻辑/分隔符结束搜索flag = Truebreakelse:flag = Falsereturn flag, posdef IsDigits(self, inString, pos):flag = Falsefor i in inString:pos += 1if i.isdigit():self.token += str(i)flag = Trueelif i == '.' and i not in self.token and 'e' not in self.token and 'E' not in self.token:self.token += str(i)elif i == 'e' or i == 'E' and i not in self.token:  # 处理含E或e的合法指数情况self.token += str(i)else:if i in self.operatorOrDelimiter or i == ' ' or i == '\n':flag = Trueelse:flag = Falsebreakreturn flag, posdef isChar(self, inString, pos):flag = Falseself.token += str(inString[0])if len(inString) < 3:return False, pos + len(inString)else:if inString[1].isalpha() and inString[2] == "\'":self.token += str(inString[1])self.token += str(inString[2])if len(inString) > 3:if inString[3] in self.Delimiter or inString[3] in self.Operator:pos = 3return True, poselse:return True, 3else:return False, 3def isString(self, inString, pos):flag = Falseself.token += str(inString[0])for i in inString[1:]:pos = pos + 1if i == '\"':self.token += str(i)flag = Truebreakif i.isalpha():self.token += str(i)else:return False, posreturn flag, posdef IsOperator(self, inString, pos):if len(inString) == 1:self.token += str(inString[0])return posfor i in inString[0:]:pos += 1if i in self.operatorOrDelimiter:self.token += str(i)else:breakreturn posdef scan(self, inString, row, col):"""扫描字符串:param col: 储存当前扫描的列:param row: 储存当前扫描的行:type inString: 待处理的字符串:return: 对字符串的判断结果,类型为列表"""inString = str(inString).strip()  # 去除字符串两端可能含有的空格self.token = ""if inString[0].isdigit():judge, index = self.IsDigits(inString, 0)if judge:"""if '.' in self.token: # 此处是对常量的转化过程此处写成注释print("--------")print(float(self.token))print("--------")elif 'e' not in self.token and 'E' not in self.token:print("--------")print(int(self.token))print("--------")else:num1 = 0num2 = 0if 'E' in self.token:l = self.token.split('E')if '.' in l[0]:num1 = float(l[0])else:num1 = int(l[0])num2 = int(l[1])elif 'e' in self.token:l = self.token.split('e')if '.' in l[0]:num1 = float(l[0])else:num1 = int(l[0])num2 = int(l[1])for i in range(0, num2):num1 *= 10print("--------")print(num1)print("--------")"""self.result.append([self.token, "常数", (row, col)])else:print(index)self.result.append([self.token, "ERROR", (row, col)])if index < len(inString) and index - 1 > 0:if index == len(inString):self.scan(inString[len(inString) - 1], row, col)else:self.scan(inString[index - 1:], row, col)elif inString[0].isalpha():judge, index = self.isMark(inString, 0)if self.isReserve(self.token):self.result.append([self.token, "关键字", (row, col)])else:self.result.append([self.token, "标识符", (row, col)])if index <= len(inString) and not inString[index - 1].isalpha():self.scan(inString[index - 1:], row, col)elif inString[0] == '\'':judge, index = self.isChar(inString, 0)if judge:self.result.append([self.token, "字符常量", (row, col)])if len(inString) > index > 0:self.scan(inString[index:], row, col)elif inString[0] == '\"':judge, index = self.isString(inString, 0)index = index + 1  # 最后一个”不能算if judge:self.result.append([self.token, "字符串常量", (row, col)])if index < len(inString) and index - 1 >= 0:self.scan(inString[index - 1:], row, col)elif inString[0] in self.Operator or inString[0] in self.RelationOperation:index = self.IsOperator(inString, 0)if self.token in self.Operator:self.result.append([self.token, "算术运算符", (row, col)])elif self.token in self.RelationOperation:self.result.append([self.token, "关系运算符", (row, col)])else:self.result.append([self.token, "ERROR", (row, col)])if index <= len(inString) and index - 1 >= 0:self.scan(inString[index-1:], row, col)elif inString[0] in self.Delimiter:if len(inString) == 1:self.token += str(inString[0])self.result.append([self.token, "分界符", (row, col)])elif len(inString) > 1 and inString[1] in self.Delimiter:  # 分隔符为一个字符self.token += str(inString)self.result.append([self.token, "ERROR", (row, col)])elif len(inString) > 1 and inString[1] not in self.Delimiter:self.token += str(inString[0])self.result.append([self.token, "分界符", (row, col)])self.scan(inString[1:], row, col)"""elif inString[0] in self.operatorOrDelimiter:judge, index = self.IsOperation(inString, 0)self.result.append([self.token, "操作符或分隔符", (row, col)])if index < len(inString) and index - 1 >= 0:  # 主要是考虑当只有一个字符的情况,因为我在判断操作符时,当首先判断出其长度为一时会默认是操作符,并不再进行判断,导致会出现死循环self.scan(inString[index - 1:], row, col)"""if __name__ == "__main__":analysis = Analysis()initial = input("请输入代码:").split(' ')col = 1for s in initial:analysis.scan(s, 1, col)col += 1for res in analysis.result:print(res)

http://chatgpt.dhexx.cn/article/PxqmXE6H.shtml

相关文章

词法分析器--C实现

实验目的&#xff1a; 编制一个读单词过程&#xff0c;从输入的源程序中&#xff0c;识别出各个具有独立意义的单词&#xff0c;即基本保留字、标识符、常数、运算符、分隔符五大类(可自主添加类别)。并依次输出各个单词的内部编码及单词符号自身值。 程序及其子程序&#xff1…

c语言实现词法分析器

词法分析器的功能:输入源程序&#xff0c;输出单词字符。单词字符一般可以分为下面五种。 &#xff08;1&#xff09;关键字 是由程序语言定义的具有固定意义的标识符。有时称这些标识符为保留字或者基本字。例如c语言中的int,char,define,strcut,double,if,else.等等 &#xf…

词法分析器(分析C语言)

问题描述&#xff1a; 用C或C语言编写一个简单的词法分析程序&#xff0c;扫描C语言小子集的源程序&#xff0c;根据给定的词法规则&#xff0c;识别单词&#xff0c;填写相应的表。如果产生词法错误&#xff0c;则显示错误信息、位置&#xff0c;并试图从错误中恢复。简单的恢…

词法分析器(c++)

前景提示&#xff1a; 个人觉得单纯是用来完成实验报告的话还行&#xff0c;但仅做参考&#xff0c;因为本人的编程水平有限&#xff0c;怕误人子弟。 本次代码支持以下操作&#xff1a; 单行注释 多行注释 文件形式输入 种别码可以在文件中自由修改 单词字符串识别支持…

词法分析——词法分析器的作用

目录 综述 正文 1 词法分析与语法分析 2 词法单元、模式和词素 3 词法单元的属性 4 词法错误 综述 词法分析是编译的第一阶段。词法分析器的主要作用是读入源程序的输入字符、将它们组成词素&#xff0c;生成并输出一个词法单元序列&#xff0c;每个词法单元对应一个词素。…

词法分析器

词法分析&#xff08;Lexical Analysis&#xff09; 词法分析器在英文中一般叫做 Tokenizer。 有一个计算模型&#xff0c;叫做有限自动机&#xff08;Finite-state Automaton&#xff0c;FSA&#xff09;&#xff0c;或者叫做有限状态自动机&#xff08;Finite-state Machin…

编译原理——词法分析器

1 概述 设计、编制并调试一个简单的C语言词法分析程序&#xff0c;掌握利用状态转换图设计词法分析器的基本方法&#xff0c;利用该词法分析器完成对源程序字符串的词法分析。通过对该词法分析器的设计&#xff0c;加深对词法分析原理、状态转换图等编译原理知识的理解。 2 使…

编译原理词法分析器(C/C++)

前言&思路 词法分析器不用多说&#xff0c;一开始我还不知道是什么样的&#xff0c;看了下别人的博客&#xff0c;再看看书&#xff0c;原来是输出二元组&#xff0c;这不就是字符串操作嘛。然后细看几篇博客&#xff0c;发现大都是用暴力判断来写的。我对代码重复性比较高…

【编译原理】词法分析(C/C++源代码+实验报告)

文章目录 1 实验目的和内容1.1实验目的1.2实验内容 2 设计思想2.1单词种类及其正规式2.2 根据正规式构造NFA2.3根据NFA构造DFA2.3.1根据替换规则构造未化简的DFA2.3.2最小化DFA 3算法流程4源程序5调试数据5.1 测试样例一5.2 测试样例二5.3 测试样例三 6实验调试情况及体会6.1 实…

session 每次请求都会产生新的sessionID

问题描述&#xff1a; 最近在写一个项目时&#xff0c;在运行项目后每刷新一次都会产生一个新的Session ID&#xff0c;导致无法取值。 原因分析&#xff1a; 搞了很久发现是URL路径的问题&#xff0c;把http://localhost:8080//的双斜杠该为单斜杠就行了 解决方案&#xf…

JavaWeb - Cookie、Session、SessionId 详解

一、概述 会话&#xff08;Session&#xff09;跟踪是Web程序中常用的技术&#xff0c;用来跟踪用户的整个会话。常用的会话跟踪技术是Cookie与Session。Cookie通过在客户端记录信息确定用户身份&#xff0c;Session通过在服务器端记录信息确定用户身份。 本章将系统地讲述Co…

JSESSIONID和sessionid的区别

要保持登陆状态&#xff0c;但是sessionid 和 JSESSIONID的值不一致&#xff0c; 情况一&#xff1a;部署到测试机上&#xff0c;利用本机登陆网页&#xff0c;sessionid和jsessionid不一样。 情况二&#xff1a;部署在本机&#xff0c;本机登陆页面&#xff0c;sessionid和js…

关于两次访问接口的sessionid不一致问题

在测试验证邮箱、注册逻辑时&#xff0c;出现验证码错误的问题。验证码是存放在session内的&#xff0c;在排除了逻辑代码的问题后&#xff0c;检查出这两次访问接口的sessionid并不一致&#xff0c;而在swagger测试接口时是一致的。因此我比较了swagger与ajax请求/响应头的区别…

cookie、session、sessionid 与jsessionid

cookie、session、sessionid 与jsessionid&#xff0c;要想明白他们之间的关系&#xff0c;下面来看个有趣的场景来帮你理解。 我们都知道银行&#xff0c;银行的收柜台每天要接待客户存款/取款业务&#xff0c;可以有几种方案&#xff1a; 凭借柜台职员的记忆&#xff0c;由收…

如何根据sessionID获取session解决方案

点个赞&#xff0c;看一看&#xff0c;好习惯&#xff01;本文 GitHub https://github.com/OUYANGSIHAI/JavaInterview 已收录&#xff0c;这是我花了3个月总结的一线大厂Java面试总结&#xff0c;本人已拿腾讯等大厂offer。 另外&#xff0c;原创文章首发在我的个人博客&#…

sessionId的生成过程和过期时间

支持作者 最便宜的卫生纸 浏览器第一次请求服务器时&#xff0c;服务器会生成一个sessionId&#xff0c;并返回给浏览器&#xff0c;这个sessionId会被保存在浏览器的会话cookie中。如下图 在浏览器不关闭的情况下&#xff0c;之后的每次请求请求头都会携带这个sessionId到服务…

session,sessionid,cookie之间的关系解析

session&#xff0c;sessionid&#xff0c;cookie之间的关系解析 文章目录 session&#xff0c;sessionid&#xff0c;cookie之间的关系解析1.简介2.session和cookie定义&#xff0c;创建&#xff0c;周期和联系2.1cookie2.2session 3.如果禁用cookie后&#xff0c;如何解决账号…

dubbox拦截器配置

dubbo是一个被国内很多互联网公司广泛使用的开源分布式服务框架&#xff0c;即使从国际视野来看应该也是一个非常全面的SOA基础框架。作为一个重要的技术研究课题&#xff0c;在当当网我们根据自身的需求&#xff0c;为Dubbo实现了一些新的功能&#xff0c;并将其命名为Dubbox&…

Springboot+Dubbox 提供Rest服务实践

背景 在开发过程中&#xff0c;dubbo接口自测时&#xff0c;通过控制台的invoke方式调用dubbo服务不方便&#xff0c;主要体现在入参设置和入参保存上&#xff08;invoke方式调用dubbo服务请参考&#xff1a;命令行中调用dubbo服务及入参写法_Ypc_victor的专栏-CSDN博客&#…

Dubbo2

一、基础知识 1、分布式基础理论 1.1&#xff09;、什么是分布式系统&#xff1f; 《分布式系统原理与范型》定义&#xff1a; “分布式系统是若干独立计算机的集合&#xff0c;这些计算机对于用户来说就像单个相关系统” 分布式系统&#xff08;distributed system&#…