Python实现语法分析(词法分析改进)

该文主要介绍了如何使用递归下降分析法对算术表达式进行语法分析,包括文法的预处理、实验设计思想以及算法实现。通过实例展示了分析过程,同时提到了词法分析和错误处理机制,进一步讨论了预测分析和算符优先分析作为替代方法。
摘要由CSDN通过智能技术生成

实验二、语法分析

一、实验目的

根据某一文法编制调试递归下降分析程序,以便对任意输入的符号串进行分析。本次实验的目的主要是加深对递归下降分析法的理解。
注:也可以采用预测分析方法、算符优先分析方法来进行分析。具体参照课本上的说明,以下是递归下降分析法的介绍。

二、实验预习提示

1、递归下降分析法的功能

语法分析器的功能是利用函数之间的递归调用模拟语法树自上而下的构造过程。

2、递归下降分析法的前提

改造文法:消除二义性、消除左递归、提取左因子,判断是否为LL(1)文法。

3、递归下降分析法实验设计思想及算法

为G的每个非终结符号U构造一个递归过程,不妨命名为U。U的产生式的右边指出这个过程的代码结构:
(1)若是终结符号,则和向前看符号对照,若匹配则向前进一个符号;否则出错。
(2)若是非终结符号,则调用与此非终结符对应的过程。当A的右部有多个产生式时,可用选择结构实现, 具体为:(1)对于每个非终结符号U->u1|u2|…|un处理的方法如下
U( )
{
ch=当前符号;
if(ch可能是u1字的开头) 处理u1的程序部分;
else if(ch可能是u2字的开头)处理u2的程序部分;
……
else error();
}
(2)对于每个右部u1->x1x2…xn的处理架构如下:
处理x1的程序;
处理x2的程序;
……
处理xn的程序;
(3)如果非终结符U有空产生式:Uε ,则还需考虑ch属于Follow(U)的情况。

三、实验过程和指导

(一)准备:

1.阅读课本有关章节。
2.初步编制好程序。
3.准备好多组测试数据。

(二)上机:

(三)程序要求:

对算术表达式文法,用递归下降分析法(或预测分析方法、算符优先分析方法等)对任意输入的符号串进行分析,如合法给出相应信息,如果不合法,最好能给出在哪个产生式出现的问题。
算术表达式至少包含+、-、*、/、()。例如:i1 + i2 * ( 34 - i3 / 2 )

提示:先做词法分析,然后语法分析。

四、实验原理

本实验为给定文法:
E→E+T| E-T| T
T→T*F| T/F| F
F→(E)| i
对用户输入的算术表达式先进行词法分析,再用递归下降法进行语法分析,因为递归下降法的前提是给定文法是LL(1)文法,下面给出判断是否是LL(1)文法的分析过程:
在这里插入图片描述
通过以上分析可知所给文法满足梯度下降法的前提条件,可用梯度下降法进行分析。
梯度下降核心代码:

    def E(): # E->TE'
        if  T() and G():
            return True
        else:
            return False

    def T(): # T->FT'
        if F() and S():
            return True
        else:
            return False

    def G(): # E'->+TE'|-TE'|&
        global i
        if line[i]=='+' or line[i]=='-':
            i=i+1
            if T() and G():
                return True
            else:
                return False
        else:
            return True

    def S(): # T'->*FT|/FT|&
        global i
        if line[i]=='*' or line[i]=='/':
            i=i+1
            if F() and S():
                return True
            else:
                return False
        else:
            return True

    def F(): # F->(E)|i
        global i
        if line[i].isdigit():
            i=i+1
            return True
        if line[i]=='(':
            i=i+1
            if E() and line[i]==')':
                i=i+1
                return True
        return False

程序界面(效果图)

和实验一一样选择文件进行语法分析或手动输入算术表达式进行语法分析:
在这里插入图片描述

首先展示词法分析结果,在点击进行语法分析后对算数表达式进行语法分析:
在这里插入图片描述

如上图所示,当算数表达式是合法的时候,会显示算是表达式合法,并将结果算出来,当算式不合法时提示算术表达式不合法,并将算式中错误的位置打印出来,如下:
在这里插入图片描述

程序代码

main.py

from fastapi import FastAPI, Request, Form, File, UploadFile
from fastapi.templating import Jinja2Templates
import uvicorn
app = FastAPI()
templates = Jinja2Templates(directory="templates")
from fastapi import  Response

from pydantic import BaseModel




reserved_words = [
    'main','if','int','for','while','do','return','break','continue',
    '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语言词法分析器状态机
class LexerStateMachine:
    def __init__(self):
        self.current_state = 'start'
        self.current_token = ''
        self.tokens = []

    # 状态转移函数
    def transition(self, char):
        #首先在start状态时遇到各种字符应该怎么跳转
        if self.current_state == 'start':
            if char in ['#',' ','\t', '\n', '\r']:
                pass  # 空格、制表符、换行符和回车符不是单词的一部分,忽略它们
            elif char.isalpha() or char == '_':
                self.current_state = 'identifier'
                self.current_token += char
            elif char.isdigit():
                self.current_state = 'constant'
                self.current_token += char
            #小数浮点数
            elif char in ['.']:
                self.current_state = 'float'
                self.current_token += char

            elif char in ['~', '?', ':', ',', ';', '.', '(', ')', '[', ']', '{', '}']:
                self.tokens.append(('operator', char))
                self.current_state = 'start'
                self.current_token = ''
            #此后为对运算符的详细状态转换
            elif char == '+':
                self.current_state = '加'
                self.current_token += char
            elif char == '-':
                self.current_state = '减'
                self.current_token += char
            elif char == '*':
                self.current_state = '乘'
                self.current_token += char
            elif char == '/':
                self.current_state = '除'
                self.current_token += char
            elif char == '&':
                self.current_state = '&'
                self.current_token += char
            elif char == '|':
                self.current_state = '或'
                self.current_token += char
            elif char == '!':
                self.current_state = '非'
                self.current_token += char
            elif char == '^':
                self.current_state = '幂'
                self.current_token += char
            elif char == '<':
                self.current_state = '小于'
                self.current_token += char
            elif char == '>':
                self.current_state = '大于'
                self.current_token += char
            elif char == '%':
                self.current_state = '百分号'
                self.current_token += char
            elif char == '=':
                self.current_state = '等于'
                self.current_token += char
            #以上是对运算符的详细

            else:
                self.tokens.append(('error', char))
                self.current_state = 'start'
                self.current_token = ''

        #以下是对运算符的二次判断
        elif self.current_state == '加':
            if char =='+':
                self.current_token += char
                self.tokens.append(('operator', self.current_token))
                self.current_state = 'start'
                self.current_token = ''
            elif char =='=':
                self.current_token += char
                self.tokens.append(('operator', self.current_token))
                self.current_state = 'start'
                self.current_token = ''
            # elif char.isdigit():
            #     self.current_token += char
            #     self.current_state = 'constant'
            else:
                self.tokens.append(('operator', self.current_token))
                self.current_state = 'start'
                self.current_token = ''
                #处理一个空格防止前后连一起
                self.transition(' ')
                self.transition(char)  # 处理当前字符
        elif self.current_state == '减':
            if char =='-':
                self.current_token += char
                self.tokens.append(('operator', self.current_token))
                self.current_state = 'start'
                self.current_token = ''
            elif char =='=':
                self.current_token += char
                self.tokens.append(('operator', self.current_token))
                self.current_state = 'start'
                self.current_token = ''
            # elif char.isdigit():
            #     self.current_token += char
            #     self.current_state = 'constant'
            else:
                self.tokens.append(('operator', self.current_token))
                self.current_state = 'start'
                self.current_token = ''
                #处理一个空格防止前后连一起
                self.transition(' ')
                self.transition(char)  # 处理当前字符
        elif self.current_state == '乘':
            if char =='=':
                self.current_token += char
                self.tokens.append(('operator', self.current_token))
                self.current_state = 'start'
                self.current_token = ''
            else:
                self.tokens.append(('operator', self.current_token))
                self.current_state = 'start'
                self.current_token = ''
                #处理一个空格防止前后连一起
                self.transition(' ')
                self.transition(char)  # 处理当前字符
        elif self.current_state == '除':
            if char =='=':
                self.current_token += char
                self.tokens.append(('operator', self.current_token))
                self.current_state = 'start'
                self.current_token = ''
            elif char == '/':
                self.current_state = 'line_comment'
            elif char == '*':
                self.current_state = 'block_comment'
            else:
                self.tokens.append(('operator', self.current_token))
                self.current_state = 'start'
                self.current_token = ''
                #处理一个空格防止前后连一起
                self.transition(' ')
                self.transition(char)  # 处理当前字符
        elif self.current_state == '与':
            if char =='&':
                self.current_token += char
                self.tokens.append(('operator', self.current_token))
                self.current_state = 'start'
                self.current_token = ''
            else:
                self.tokens.append(('operator', self.current_token))
                self.current_state = 'start'
                self.current_token = ''
                #处理一个空格防止前后连一起
                self.transition(' ')
                self.transition(char)  # 处理当前字符
        elif self.current_state == '或':
            if char =='|':
                self.current_token += char
                self.tokens.append(('operator', self.current_token))
                self.current_state = 'start'
                self.current_token = ''
            else:
                self.tokens.append(('operator', self.current_token))
                self.current_state = 'start'
                self.current_token = ''
                #处理一个空格防止前后连一起
                self.transition(' ')
                self.transition(char)  # 处理当前字符
        elif self.current_state == '幂':
            if char =='=':
                self.current_token += char
                self.tokens.append(('operator', self.current_token))
                self.current_state = 'start'
                self.current_token = ''
            else:
                self.tokens.append(('operator', self.current_token))
                self.current_state = 'start'
                self.current_token = ''
                #处理一个空格防止前后连一起
                self.transition(' ')
                self.transition(char)  # 处理当前字符
        elif self.current_state == '非':
            if char =='=':
                self.current_token += char
                self.tokens.append(('operator', self.current_token))
                self.current_state = 'start'
                self.current_token = ''
            else:
                self.tokens.append(('operator', self.current_token))
                self.current_state = 'start'
                self.current_token = ''
                #处理一个空格防止前后连一起
                self.transition(' ')
                self.transition(char)  # 处理当前字符
        elif self.current_state == '百分号':
            if char =='=':
                self.current_token += char
                self.tokens.append(('operator', self.current_token))
                self.current_state = 'start'
                self.current_token = ''
            else:
                self.tokens.append(('operator', self.current_token))
                self.current_state = 'start'
                self.current_token = ''
                #处理一个空格防止前后连一起
                self.transition(' ')
                self.transition(char)  # 处理当前字符
        elif self.current_state == '小于':
            if char =='<':
                self.current_token += char
                self.tokens.append(('operator', self.current_token))
                self.current_state = 'start'
                self.current_token = ''
            elif char =='=':
                self.current_token += char
                self.tokens.append(('operator', self.current_token))
                self.current_state = 'start'
                self.current_token = ''
            else:
                self.tokens.append(('operator', self.current_token))
                self.current_state = 'start'
                self.current_token = ''
                #处理一个空格防止前后连一起
                self.transition(' ')
                self.transition(char)  # 处理当前字符
        elif self.current_state == '大于':
            if char =='>':
                self.current_token += char
                self.tokens.append(('operator', self.current_token))
                self.current_state = 'start'
                self.current_token = ''
            elif char =='=':
                self.current_token += char
                self.tokens.append(('operator', self.current_token))
                self.current_state = 'start'
                self.current_token = ''
            else:
                self.tokens.append(('operator', self.current_token))
                self.current_state = 'start'
                self.current_token = ''
                #处理一个空格防止前后连一起
                self.transition(' ')
                self.transition(char)  # 处理当前字符
        elif self.current_state == '等于':
            if char =='=':
                self.current_token += char
                self.tokens.append(('operator', self.current_token))
                self.current_state = 'start'
                self.current_token = ''
            else:
                self.tokens.append(('operator', self.current_token))
                self.current_state = 'start'
                self.current_token = ''
                #处理一个空格防止前后连一起
                self.transition(' ')
                self.transition(char)  # 处理当前字符

        #以上是对运算符的二次判断
        #当处于inentifier状态时转换
        elif self.current_state == 'identifier':
            if char.isalnum() or char == '_':
                self.current_token += char
            else:
                if self.current_token in reserved_words:
                    self.tokens.append(('reserved_words', self.current_token))
                    self.current_state = 'start'
                    self.current_token = ''
                    #处理一个空格防止前后连一起
                    self.transition(' ')
                    self.transition(char)  # 处理当前字符
                else:
                    self.tokens.append(('identifier', self.current_token))
                    self.current_state = 'start'
                    self.current_token = ''
                    #处理一个空格防止前后连一起
                    self.transition(' ')
                    self.transition(char)  # 处理当前字符

        #当处于constant状态时转换
        elif self.current_state == 'constant':
            if char.isdigit() or char in ['e', 'E']:
                self.current_token += char
            elif char in ['.']:
                self.current_state = 'float'
                self.current_token += char
            elif char in ['f', 'F', 'l', 'L', 'u', 'U']:
                self.current_token += char
                self.tokens.append(('constant', self.current_token))
                self.current_state = 'start'
                self.current_token = ''
            else:
                self.tokens.append(('constant', self.current_token))
                self.current_state = 'start'
                self.current_token = ''
                #处理一个空格防止前后连一起
                self.transition(' ')
                self.transition(char)  # 处理当前字符
        #浮点数
        elif self.current_state == 'float':
            if char.isdigit() or char in ['e', 'E', '+', '-']:
                self.current_token += char
            # elif char in ['.']:
            #     self.current_state = 'error'
            #     self.current_token += char
            else:
                self.tokens.append(('float', self.current_token))
                self.current_state = 'start'
                self.current_token = ''
                #处理一个空格防止前后连一起
                self.transition(' ')
                self.transition(char)  # 处理当前字符

        # #error
        # elif self.current_state == 'error':
        #     if char in [' ','\t', '\n', '\r']:
        #         self.tokens.append(('error', self.current_token))
        #         self.current_state = 'start'
        #         self.current_token = ''
        #     else:
        #         self.current_state = 'error'
        #         self.current_token += char
        elif self.current_state == 'line_comment':
            if char == '\n':
                self.current_state = 'start'
            else:
                self.current_state = 'line_comment'
        #块注释
        elif self.current_state == 'block_comment':
            if char == '*':
                self.current_state = 'block_comment_ending'
            else:
                self.current_state = 'block_comment'
        #
        elif self.current_state == 'block_comment_ending':
            if char == '/':
                self.current_state = 'start'
                self.current_token = ''
            else:
                self.current_state = 'block_comment'
                self.transition(char)  # 处理当前字符
        else:
            self.tokens.append(('error', self.current_token))
            self.current_state = 'start'
            self.current_token = ''
            self.transition(char)  # 处理当前字符

    # 分离单词
    def tokenize(self, code):
        for char in code:
            # print(char)
            self.transition(char)
        return self.tokens

def evaluate_expression(expression):
    tokens = tokenize2(expression)
    token_index = 0

    def parse_expression():
        nonlocal token_index
        left_operand = parse_term()

        while token_index < len(tokens):
            token = tokens[token_index]

            if token == '+':
                token_index += 1
                right_operand = parse_term()
                left_operand += right_operand
            elif token == '-':
                token_index += 1
                right_operand = parse_term()
                left_operand -= right_operand
            else:
                break

        return left_operand

    def parse_term():
        nonlocal token_index
        factor = parse_factor()

        while token_index < len(tokens):
            token = tokens[token_index]

            if token == '*':
                token_index += 1
                factor *= parse_factor()
            elif token == '/':
                token_index += 1
                divisor = parse_factor()
                if divisor == 0:
                    raise ValueError("Division by zero")
                factor /= divisor
            else:
                break

        return factor

    def parse_factor():
        nonlocal token_index
        token = tokens[token_index]
        token_index += 1

        if token == '(':
            result = parse_expression()
            if tokens[token_index] != ')':
                raise SyntaxError("Unbalanced parentheses")
            token_index += 1
            return result
        else:
            try:
                return float(token)
            except ValueError:
                raise ValueError("Invalid token: {}".format(token))

    try:
        return parse_expression()
    except (IndexError, ValueError, ZeroDivisionError, SyntaxError) as e:
        return str(e)


def tokenize2(expression):
    # 分割表达式为单个token
    tokens = []
    current_token = ""

    for char in expression:
        if char in "+-*/()":
            if current_token:
                tokens.append(current_token)
            tokens.append(char)
            current_token = ""
        else:
            current_token += char

    if current_token:
        tokens.append(current_token)

    return tokens




# 语法分析


# 语法分析

@app.get("/")
def index(request: Request):
    return templates.TemplateResponse("index.html", {"request": request})

@app.post("/lex")
async def analyze(request: Request,file: UploadFile = File(None)):
    # 文件类型数据
    contents = await file.read()
    text = contents.decode("utf-8")+" "
    lexer = LexerStateMachine()
    tokens = lexer.tokenize(text)
    # print(tokens)
    return templates.TemplateResponse("lex.html", {"request": request, "tokens": tokens,"text1":text,"file":file})


@app.post("/lex2")
async def analyze(request: Request,text: str = Form(None)):
    # 文本类型数据
    text1 = str(text)+"#"
    # print(type(text1))
    # print(text1)
    lexer = LexerStateMachine()
    tokens = lexer.tokenize(text1)
    # print(tokens)
    return templates.TemplateResponse("lex.html", {"request": request, "tokens": tokens,"text":text})

@app.post("/analyze")
async def analyze_syntax(request: Request):
    data = await request.json()
    text = data[0].get("value")  # 获取列表中第一个元素的"value"字段
    # print(text)
    # 进行语法分析的逻辑
    LEX=[x.get("value") for x in data]
    global i
    i=0
    line=[]

# """
# E→E+T| E-T| T
# T→T*F| T/F| F
# F→(E)| i
# """

# """
# G’[E]:
# E →  TE'
# E' → +TE'| -TE'|ε
# T  →  FT'
# T'→  *FT'|/FT'|ε
# F  → (E)| i
# """
    def E(): # E->TE'
        if  T() and G():
            return True
        else:
            return False

    def T(): # T->FT'
        if F() and S():
            return True
        else:
            return False

    def G(): # E'->+TE'|-TE'|&
        global i
        if line[i]=='+' or line[i]=='-':
            i=i+1
            if T() and G():
                return True
            else:
                return False
        else:
            return True

    def S(): # T'->*FT|/FT|&
        global i
        if line[i]=='*' or line[i]=='/':
            i=i+1
            if F() and S():
                return True
            else:
                return False
        else:
            return True

    def F(): # F->(E)|i
        global i
        if line[i].isdigit():
            i=i+1
            return True
        if line[i]=='(':
            i=i+1
            if E() and line[i]==')':
                i=i+1
                return True
        return False

    # print("递归下降分析程序")

    for x in LEX:
        line.append(x)
    # print(line)
    line.append("#")
    if E() and line[i]=='#':
        # print("true")
        del line[-1]
        result2 = evaluate_expression(line)
        # print(result2)
        result = ["分析结果:"+''.join(line)+" 为合法算式表达式","表达式计算结果为: "+str(result2)]
    else:
        del line[-1]
        result = ["分析结果:"+''.join(line)+" 为非法的算式表达式","出错字符位于第"+str(i+1)+"处, 该字符为 "+line[i]]
    return result

if __name__ == '__main__':
    uvicorn.run(app)

index.html

<!DOCTYPE html>
<html>
    <head>
        <title>C Lexer</title>
    </head>
    <style>
        body{
            width: 1000px;
            height:700px;
            border: rgb(216, 168, 184) 1px solid;
            margin: auto;
            background-color: #02B8B6;
            background-size: cover;
        }
        textarea {
            resize: both;
        }
    </style>
    <body>
        <h1>C Lexer</h1>
        <form action="/lex" method="post" enctype="multipart/form-data">
            <label for="file">Choose a file to upload:</label><br>
            <input type="file" id="file" name="file"><br><br>
            <button type="submit">Upload File</button>
        </form>
        <br>
        <form action="/lex2" method="post">
            <label for="text">Or enter some text:</label><br>
            <textarea id="text" name="text" rows="4" cols="50"></textarea><br><br>
            <button type="submit">Submit Text</button>
        </form>

    </body>
</html>


lex.html

<!DOCTYPE html>
<html>
<head>
    <title>C词法分析器</title>
    <style>
        .container {
            display: flex;
            flex-direction: row;
            height: 100vh;
        }

        .left {
            flex: 1;
            min-width: 300px;
            max-width: 33.33%;
            overflow-y: scroll;
            background-color: #608FB9;
            padding: 20px;
        }

        .middle {
            flex: 1;
            overflow-y: scroll;
            background-color: #608FB9;
            padding: 20px;
            display: flex;
            flex-direction: column;
        }

        .right {
            flex: 1;
            overflow-y: scroll;
            background-color: #608FB9;
            padding: 20px;
        }

        .splitter {
            position: relative;
            width: 10px;
            cursor: col-resize;
            background-color: #ddd;
            z-index: 1;
        }

        thead th {
            position: sticky;
            top: 0;
            background-color: #608FB9;
        }

        table {
            width: auto;
            min-width: 400px;
            table-layout: fixed;
        }

        td, th {
            text-align: left;
        }

        /* 定义表格内容容器样式 */
        .table-container {
            max-height: calc(100vh - 40px); /* 减去上下padding的高度 */
            overflow-y: scroll;
        }

        /* 定义按钮样式 */
        .my-button {
            background-color: #02B8B6; /* 设置背景颜色 */
            color: black; /* 设置文本颜色 */
            font-family: Arial, sans-serif; /* 设置字体 */
            padding: 10px 20px; /* 设置填充 */
            border-radius: 5px; /* 设置圆角 */
            text-decoration: none; /* 移除下划线 */
        }

        /* 鼠标悬停时更改样式 */
        .my-button:hover {
            background-color: #0F8FAA; /* 更改背景颜色 */
            color: white; /* 更改文本颜色 */
        }

        .result-container {
            margin-top: 20px;
        }

        .result-container div {
            margin-bottom: 10px;
            overflow-wrap: break-word;
        }
    </style>
</head>

<body>
<div class="container">
    <div class="left">
        <!-- 添加按钮 -->
        <a href="/" class="my-button">返回</a>
        <table>
            <tr>
                {% if file %}
                <h2>File uploaded: {{ file.filename }}</h2>
                <h3><pre>{{ text1 }}</pre></h3>
                {% endif %}
                {% if text %}
                <h2>Text submitted:</h2>
                <h3><pre>{{ text }}</pre></h3>
                {% endif %}
            </tr>
        </table>
    </div>
    <div class="splitter"></div>
    <div class="middle">
        <div class="table-container">
            <table>
                <thead>
                    <tr>
                        <th><h2>Type</h2></th>
                        <th><h2>Value</h2></th>
                    </tr>
                </thead>
                <tbody>
                    {% for token in tokens %}
                    <tr>
                        <td>{{ token[0] }}</td>
                        <td>{{ token[1] }}</td>
                    </tr>
                    {% endfor %}
                </tbody>
            </table>
        </div>
    </div>
    <div class="splitter"></div>
    <div class="right">
        <button id="analyzeButton" class="my-button">进行语法分析</button>
        <div class="result-container"></div>
    </div>
</div>

<script>
    const splitter = document.querySelectorAll('.splitter');
    const leftPanel = document.querySelector('.left');
    const middlePanel = document.querySelector('.middle');
    const rightPanel = document.querySelector('.right');
    const analyzeButton = document.getElementById('analyzeButton');

    let isResizing = false;

    splitter[0].addEventListener('mousedown', function (e) {
        isResizing = true;
    });

    splitter[1].addEventListener('mousedown', function (e) {
        isResizing = true;
    });

    document.addEventListener('mousemove', function (e) {
        if (!isResizing) {
            return;
        }

        const x = e.pageX;
        const leftWidth = x - leftPanel.getBoundingClientRect().left;
        const middleWidth = rightPanel.getBoundingClientRect().left - x;
        const rightWidth = rightPanel.getBoundingClientRect().right - x;

        leftPanel.style.flexBasis = `${leftWidth}px`;
        middlePanel.style.flexBasis = `${middleWidth}px`;
        rightPanel.style.flexBasis = `${rightWidth}px`;
    });

    document.addEventListener('mouseup', function (e) {
        isResizing = false;
    });

    analyzeButton.addEventListener('click', function () {
        const table = document.querySelector('.middle table');
        const rows = table.querySelectorAll('tbody tr');
        const data = [];

        for (let i = 0; i < rows.length; i++) {
            const columns = rows[i].querySelectorAll('td');
            const type = columns[0].innerText;
            const value = columns[1].innerText;
            data.push({ type, value });
        }

        fetch('/analyze', {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
            },
            body: JSON.stringify(data),
        })
            .then(response => response.json())
            .then(result => {
                const resultContainer = document.querySelector('.result-container');
                resultContainer.innerHTML = ''; // 清空容器

                let index = 0;
                const timer = setInterval(() => {
                    if (index >= result.length) {
                        clearInterval(timer);
                        return;
                    }

                    const item = result[index];
                    const listItem = document.createElement('div');
                    listItem.textContent = JSON.stringify(item).replace(/^"(.*)"$/, '$1');
                    resultContainer.appendChild(listItem);

                    index++;
                }); // 每隔1秒显示一行语法分析结果
            })
            .catch(error => {
                console.error('请求发生错误:', error);
            });
    });
</script>
</body>
</html>

实验结果分析及心得体会

通过对算术表达式文法的分析,我使用了递归下降分析法对任意输入的符号串进行了分析。这个实验让我更深入地理解了语法分析的原理和方法,并学会了如何通过递归下降分析法来构建分析器。
在实验中,我首先定义了算术表达式的文法规则,包括运算符+、-、*、/和括号()。然后,我使用递归下降分析法来逐步解析输入的符号串。
在编写分析器的过程中,我将每个文法规则转化为相应的递归函数,每个函数负责分析和处理对应的非终结符。通过递归调用这些函数,我可以逐步解析表达式,并判断其是否合法。如果遇到不合法的情况,我尽量在错误的产生式中定位问题,以便给出准确的错误信息。
通过完成这个实验,我对递归下降分析法有了更深入的了解。我认识到递归下降分析法是一种简单而有效的语法分析方法,尤其适用于上下文无关文法。通过递归下降分析法,我可以直观地理解文法规则和语法结构,并通过递归的方式逐步解析符号串。
在实验中,我也面临了一些挑战。在设计递归函数时,我需要考虑如何处理运算符的优先级和结合性,以确保表达式的正确计算顺序。此外,我还需要处理错误输入和异常情况,以提供准确的错误信息,帮助用户定位问题所在。
通过这个实验,我不仅学会了递归下降分析法,还了解了其他语法分析方法,如预测分析方法和算符优先分析方法。这些方法为我理解和构建编译器的各个阶段提供了基础。我相信这些经验将对我今后的语法分析和编译器设计工作有很大的帮助。

原创出品,如有不足,欢迎指正

  • 2
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
递归下降分析法 一、实验目的: 根据某一文法编制调试递归下降分析程序,以便对任意输入的符号串进行分析。本次实验的目的主要是加深对递归下降分析法的理解。 二、实验说明 1、递归下降分析法的功能 词法分析器的功能是利用函数之间的递归调用模拟语法树自上而下的构造过程。 2、递归下降分析法的前提 改造文法:消除二义性、消除左递归、提取左因子,判断是否为LL(1)文法, 3、递归下降分析法实验设计思想及算法 为G的每个非终结符号U构造一个递归过程,不妨命名为U。 U的产生式的右边指出这个过程的代码结构: (1)若是终结符号,则和向前看符号对照, 若匹配则向前进一个符号;否则出错。 (2)若是非终结符号,则调用与此非终结符对应的过程。当A的右部有多个产生式时,可用选择结构实现。 三、实验要求 (一)准备: 1.阅读课本有关章节, 2.考虑好设计方案; 3.设计出模块结构、测试数据,初步编制好程序。 (二)上课上机: 将源代码拷贝到机上调试,发现错误,再修改完善。第二次上机调试通过。 (三)程序要求: 程序输入/输出示例: 对下列文法,用递归下降分析法对任意输入的符号串进行分析: (1)E->eBaA (2)A->a|bAcB (3)B->dEd|aC (4)C->e|dc 输出的格式如下: (1)递归下降分析程序,编制人:姓名,学号,班级 (2)输入一以#结束的符号串:在此位置输入符号串例如:eadeaa# (3)输出结果:eadeaa#为合法符号串 注意: 1.如果遇到错误的表达式,应输出错误提示信息(该信息越详细越好); 2.对学有余力的同学,可以详细的输出推导的过程,即详细列出每一步使用的产生式。 (四)程序思路 0.定义部分:定义常量、变量、数据结构。 1.初始化:从文件将输入符号串输入到字符缓冲区中。 2.利用递归下降分析法分析,对每个非终结符编写函数,在主函数中调用文法开始符号的函数。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

谭你一个脑瓜崩

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

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

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

打赏作者

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

抵扣说明:

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

余额充值