首页 > 编程语言 >编译原理动手实操,用java实现一个简易编译器-语法解析

编译原理动手实操,用java实现一个简易编译器-语法解析

时间:2023-06-14 11:03:49浏览次数:47  
标签:java buffer 从句 刘德华 名词 编译器 实操 谓语 动词


语法和解析树:

举个例子看看,语法解析的过程。句子:“我看到刘德华唱歌”。在计算机里,怎么用程序解析它呢。从语法上看,句子的组成是由主语,动词,和谓语从句组成,主语是“我”,动词是“看见”, 谓语从句是”刘德华唱歌“。因此一个句子可以分解成 主语 + 动词 + 谓语从句:


句子-->主语+动词 + 谓语从句 


主语是名词,因此有 :


主语->名词


句子里的名词有: “我”, “刘德华”,因此有解析规则:

名词-> "我“  |  "刘德华".

句子里的动词是“看见”, “唱歌”,由此有解析规则:

动词-> “看见” | “唱歌”


再看谓语从句,谓语从句由宾语和谓语动词组成, 宾语是 “刘德华”, 谓语动词是“唱歌", 谓语从句的解析规则就是:

谓语从句 -> 宾语 + 谓语动词

谓语动词是属于动词,于是又有:

谓语动词-> 动词

动词->”看见” | "唱歌"


这样,整个句子的解析规则就有:


1.句子-->主语+动词 + 谓语从句

2.谓语从句 -> 宾语 + 谓语动词

3.主语->名词

4.谓语动词->动词

5.动词-> “看见” | “唱歌”

6.名词-> "我“  |  "刘德华".


上面这组解析规则就是在计算机中用来解析句子的算法,接下来我们通过一系列替换,从这组规则还原回句子,首先从第一个规则开始,用右边的式子替换左边的符号,

1. 句子 通过规则 :句子-->主语+动词 + 谓语从句 替换得到:

2. 主语+动词 + 谓语从句, 通过规则 主语->名词 替换得到:

3. 名词 + 动词 + 谓语从句, 通过规则 名词-> "我“  |  "刘德华" 替换得到

4. 我 + 动词 + 谓语从句, 通过规则 动词-> "看见" 替换得到:

5. 我 看见 + 谓语从句, 通过规则 谓语从句 -> 宾语 + 谓语动词 替换得到:

6. 我 看见 宾语+谓语动词, 通过规则 宾语->名词 替换得到:

7. 我 看见 名词+谓语动词, 通过规则 名词-> "我“  |  "刘德华" 替换得到:

8. 我 看见 刘德华 + 谓语动词, 通过规则 谓语动词->动词 替换得到:

9. 我 看见 刘德华 动词。通过规则 动词-> “唱歌” 替换得到

10 我 看见 刘德华 唱歌

至此,我们已经没有可替换的地方,于是语法解析完成。 由此可见,语法解析就是通过设立一组规则,然后判断输入的文本是否符合给定规则的过程。我们看到,最底层的一些规则是这样的:

名词-> "我“  |  "刘德华", 动词-> “看见” |“唱歌“

这几条规则,,-> 左边就是标签,右边就是词法分析的字符串。整个解析过程,形成了一种树状结构,这个结构就叫语法解析树:

编译原理动手实操,用java实现一个简易编译器-语法解析_编译器

                         

设想,由文字组成的文本,其形式是无穷的,语法解析的规则是将无穷的文本中,选取出组合形式符合语法规则的文本,例如对于上述语法,句子:“我看见张学友唱歌” 就无法通过语法规则,按照上面的替换过程,我们发现,到第7步时 解析到宾语,宾语替换成名词后无法将名词替换成“张学友”, 因此“我看见张学友唱歌”对于上面的语法规则而言,是非法输入。


当然,语法规则所限定的文本输入也不是唯一的,句子:“刘德华看见我唱歌” 也符合上面的语法规则,大家可以仿照上面的替换过程验证一下。

如果想要语法识别“我看见张学友唱歌”, 那么只要将规则改一下:名词->”我“ | ”刘德华” | “张学友” 即可。


我们看看,将上述替代过程转成计算机伪码是怎样的:

假定“我看见刘德华唱歌” 这歌句子存在缓冲区buffer 里,那么代码表述如下:

句子(buffer) {
   //主语 + 动词 + 谓语从句 替换 句子
    主语(buffer);
    动词(buffer);
   谓语从句(buffer);
}
主语(buffer) {
//名词 替换 主语
   名词(buffer);
}

名词(buffer) {
  // “我” | “刘德华” 替换 名词
    if (buffer[0] == “我”) {
        buffer = buffer.substring(1);
        return;
  }
 if (buffer[0,1,2] == “刘德华”) {
    buffer = buffer.substring(3);
    return;
 }

throw new Exception (“该语句不符合语法”);
}

动词(buffer) {
 // “看见” | “唱歌“ 替换 动词
  if (buffer[0,1]== “看见” || buffer[0,1] == “唱歌") {
    buffer = buffer.substring(2);
    return; 
  }
 throw new Exception (“该语句不符合语法”);
}

谓语从句(buffer) {
//宾语 谓语动词 替换 谓语从句
    宾语(buffer);
    谓语动词(buffer);
}

宾语(buffer) {
  //名词 替换 宾语
    名词(buffer);
}

谓语动词(buffer) {
  //动词 替换 谓语动词
    动词(buffer);
}


在下一篇,我们看看,如何对带有加好和乘号的算术表达式,如何制定一套语法规则以及相应的语法替换代码。


标签:java,buffer,从句,刘德华,名词,编译器,实操,谓语,动词
From: https://blog.51cto.com/u_16160261/6476231

相关文章

  • java开发系统内核:进程的挂起和恢复
    有了进程的自动调度后,接下来的任务在于,如何将空闲进程挂起,空闲进程往往是那些没有具体任务需要处理的进程,因此,如果继续让其运行的话,那么必然会耗费宝贵的CPU资源,如果能让它先挂起,等到它需要执行具体任务时,再把它调度到前台,那才是一种合理的进程管理机制。我们实现的进程调度,是依赖......
  • java开发C语言编译器: return 语句的解释和执行
    在C语言程序中,很多函数并不是执行全部语句后,才从最底部返回的,大多数情况下,当某些条件成立时就可以通过return语句立即返回,而无需执行接下来的代码,本节,我们继续增强java开发的C语言解释器功能,使其能够处理return语句,完成本节代码后,我们的C语言解释器能够正常解析和执行下面的代码:in......
  • java开发系统内核:自动化进程切换
    我们已经通过时钟中断完成了两个进程间的相互切换。但当前实现有很大的缺陷,例如我们只能在两个指定的进程间切换,如果要想增添新的进程,那么,没增加一个进程,按照当前模式,我们只能再增加相应代码,这显然是不可接受的。因此,这节,我们希望完成进程的切换机制,使得有新进程时,我们无需改动代码......
  • java开发系统内核:实现进程自动切换,再现Linus当年辉煌一刻
    Linux操作系统内核于1991年10月5日被LinusBenedictTorvalds所开发,从此后,世界软件史揭开了新的帷幕,我们现在很多伟大的软件项目,都构建在Linux的基础之上,不说用于支撑谷歌,阿里,百度等巨头业务的后台大型服务器,现在风靡世界的安卓操作系统,也是构建在Linux之上的,可以说,没有当年Linux......
  • java实现C语言编译器:实现有参数的函数调用
    上一节,我们实现了没有参数传递的函数调用,本节,我们看看如何实现有参数传递的函数调用。有参数的函数调用要比无参数的函数调用复杂的多,一个难题在于,我们需要确定参数变量的作用域,例如下面的代码:inta;voidf(inta,intb){intc;c=a+b;}在代码里,有两个同名变量都......
  • 拼多多接口|api接口数据采集获取商品详情数据源代码Java演示
    ​拼多多提供了商品API,可以通过该API获取拼多多所有商品的详细信息,具体步骤如下: 申请开放平台接入。注册获取apikey和apisecret,调用API时需提供。调用拼多多API,获取商品详情。请求参数:参数说明通用参数说明version:API版本key:调用key,测试key:test_api_......
  • 书写高质量JavaScript代码的要义(The Essentials of Writing High Quality JavaScript)
    原文:TheEssentialsofWritingHighQualityJavaScript才华横溢的StoyanStefanov,在他写的由O’Reilly初版的新书《JavaScriptPatterns》(JavaScript模式)中,我想要是为我们的读者贡献其摘要,那会是件很美妙的事情。具体一点就是编写高质量JavaScript的一些要素,例如避免全局变量,使......
  • Java_memcached-release 安装 原理 实例
     Java_memcached-release安装原理实例  一、了解和使用使用安装memcached在这一块已经有车了,就不再造了。一个日本君写的:长野雅广memcached-全面剖析.pdfheiyeluren(黑夜路人) Memcached-原理和使用详解.pdf  二、javamemcached客启端的调用   2.1下载客户端jar包......
  • javascript现代编程系列教程之二——IIFE
    IIFE(ImmediatelyInvokedFunctionExpression,立即执行函数表达式)是一个在定义后立即执行的JavaScript函数。它具有以下特点:是一个匿名函数:通常情况下,IIFE是一个没有名字的函数,称为匿名函数。立即执行:这个函数在声明后立即被调用并执行,而无需手动调用。创建局部作用域:它创建......
  • javascript现代编程系列教程之一:区块作用域对VAR不起作用的问题
    在JavaScript中,使用var声明的变量具有函数作用域,而不是块级作用域。这意味着在一个函数内部,使用var声明的变量在整个函数范围内都是可见的,包括嵌套的块(如if语句、for循环等)。为了避免区块对var不起作用的问题,你可以采用以下方法:使用let和const代替var:从ECMAScript2015(ES6)开始,引......