当前位置: 首页 > article >正文

PL/0-语法分析器

本文主要按照笔者逻辑思考的顺序进行语法分析部分的说明。如有不明白的部分请见谅。

在拿到词法分析部分的一个又一个的 Token 时,庞大的语法分析让我无法下手,我不知道如何利用这些 Token,也不知道将 PL/0 语言用上下文无关文法描述出来有什么用,但这并不妨碍我们先将上下文无关文法写出来(看懂)😎

上下文无关文法描述的 PL/0 语言:

  • Program → Block .

  • Block → [ConstDecl][VarDecl][ProcDecl] Stmt

    程序块的基本结构是:常量定义、变量定义、过程定义、语句

  • ConstDecl → const ConstDef {, ConstDef} ;
    常量定义

  • ConstDef → ident = number

  • VarDecl → var ident {, ident} ;
    变量定义

  • ProcDecl → procedure ident ; Block ; {procedure ident ; Block ;}
    过程定义

  • Stmt → ident := Exp | call ident | begin Stmt {; Stmt} end | if Cond then Stmt | while Cond do Stmt | ε

    赋值语句、调用语句、begin-end 块语句、判断语句、循环语句

  • Cond → odd Exp | Exp RelOp Exp
    条件表达式

  • RelOp → = | <> | < | > | <= | >=
    关系运算符

  • Exp → [+ | − ] Term {+ Term | − Term}
    表达式

  • Term → Factor {* Factor | / Factor}

  • Factor → ident | number | ( Exp )

  • ident:字母开头的字母 / 数字串

  • number:无符号整数

从上面的文法中我们可以得到以下的信息:

  • 🤔:PL/0 语言有着严格的先后顺序,必须将常量的声明、定义以及变量的声明放在最前面,然后是过程的声明和定义,最后才是语句。
  • 😎:过程里可以嵌套过程的定义,过程里也可以调用(call)其他的过程。
  • 😴:分号的位置很重要,常量和变量声明和定义的最后有;过程名后有;过程体结束后有;语句(stmt)只有在 begin 中的语句中有。
  • 😋:程序最后是以 . 结束的。

有了上述的理解,我们终于知道程序的大概流程了。因为这里我们不用预测分析表,所以对于流程的了解挺重要的。下面将结合流程图展开分析(这里先不着急写代码,一切都理解了写代码其实很快。

程序的入口:

我们进入程序的“大门”,遇到了一个程序体,这里的程序体就像一个黑盒子(函数),我们一头扎进去,最后又会走出来,然后遇到一个 . ,这样程序就结束了。

程序体:

下面我们走进黑盒子中,发现又有许多分支 😵,但我们有一个竖向的“主线”,不妨就沿着主线走一遭。第一个“路口”是 const,我们忍住了没进去;第二个“路口”是 var,我们再次忍住了,因为我们是为了走到最后,而不能误入“歧途”。就这样,我们到了第三个 procedure 以及第四个“语句”,终于没有“路”可以走了,我们走到了尽头。

这一路上,我们遇到了很多“分叉口” – const、var、prodedure 和语句,但我们都不知道里面究竟是什么,它们对我们来说就是一个又一个的黑盒子,没错就是黑盒子,而在之后我们都会定义一个函数来代表黑盒子。这时,你可能感觉到了什么 😳,我们继续往下进行。

语句这个就更容易看出来分了五路,但不同于上面的程序体,语句这五条路,你一次只能选一条!

这样基本的程序结构,我们已经分析完了,但毕竟 talk is cheap. Show me the code 现在写完整的代码还为时尚早,不如用伪代码(可能)代替。

我们从头开始,进入了一个程序之中,并在其中发现了程序体(黑盒)和一个点号。

prog(){
    block();
    match('.');
}

然后是程序体内部,有 const、var 和 procedure 和语句:

block(){
    const();
    var();
    procedure();
    statement();
}

最后是语句,有五个分支:

statement(){
    assign();
    call();
    begin();
    if();
    while();
    // 空就不写了
}

下面就是对于函数体内部的补充了。待续……


http://www.kler.cn/a/395907.html

相关文章:

  • 生成式GPT商品推荐:精准满足用户需求
  • 《数学年刊A辑》
  • 速盾:如何有效防止服务器遭受攻击?
  • 传奇996_19——常用函数
  • Git在版本控制中的应用
  • 蓝桥杯c++算法学习【2】之搜索与查找(九宫格、穿越雷区、迷宫与陷阱、扫地机器人:::非常典型的必刷例题!!!)
  • SystemVerilog学习——类的继承
  • node.js知识点总结
  • PaoluGPT——千里挑一
  • Windows安装Elasticsearch及Spring Boot整合ES教程
  • Flutter-左侧导航栏跟随窗口的宽变化
  • 使用机器学习优化数据库查询性能
  • FastGPT部署通义千问Qwen和智谱glm模型|OneAPI配置免费的第三方API
  • 基于集成Whisper 与 Pepper-GPT改进人机交互体验并实现顺畅通信
  • Git之国内项目托管平台
  • 物联网低功耗广域网LoRa开发(二):LoRa开发环境搭建及驱动移植
  • CSS基础知识01
  • 论文 | On Second Thought, Let’s Not Think Step by Step!
  • 【澜舟科技-注册/登录安全分析报告】
  • 蓝桥杯每日真题 - 第12天
  • 刷别的学校oj—河工大oj1073-1099
  • linux 下调试 bmp280 气压传感器
  • jmeter常用配置元件介绍总结之逻辑控制器
  • 【笔记】关于git和GitHub和git bash
  • Neo4j Desktop 和 Neo4j Community Edition 区别
  • CAN编程示例之socket CAN