语法分析器的两个重要函数 FIRST和FOLLOW

FIRST的定义

FIRST(α),可从α推导得到的串的首符号的集合

1.如果X是一个终结符,那么FIRST(X) = X

2.如果X是一个非终结符,且X -> Y1Y2...Yk 是一个产生式,

1)如果Y1..Yj-1=>ε 那么 FIRST(Yj) 添加到 FIRST(X)

2)如果Y1...Yk=>ε,那么ε添加到FIRST(X)

3.如果X->ε是一个产生式,那么ε添加到FIRST(X)

代码实现

1.符号类

import java.util.Objects;

/**
* 符号
*/
public class Symbol { protected String name; @Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Symbol symbol = (Symbol) o;
return Objects.equals(name, symbol.name);
} @Override
public int hashCode() {
return Objects.hash(name);
}
}

2.终结符

public class Terminal extends Symbol {

    public static Terminal of(String name) {
Terminal result = new Terminal();
result.name = name;
return result;
}
}

 

3.非终结符

/**
* 非终结符
*/
public class Nonterminal extends Symbol { public static Nonterminal of(String name) {
Nonterminal result = new Nonterminal();
result.name = name;
return result;
}
}

  

4.产生式

import java.util.List;
import java.util.Objects; /**
* 产生式
*/
public class Production { /** 产生式头 */
private Nonterminal head;
/** 产生式体 */
private List<Symbol> body; public Nonterminal getHead() {
return head;
} public List<Symbol> getBody() {
return body;
} @Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Production that = (Production) o;
return Objects.equals(head, that.head) && Objects.equals(body, that.body);
} @Override
public int hashCode() {
return Objects.hash(head, body);
}
}

  

5.文法

package com.kashin.grammar.model;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set; /**
* 文法
*/
public class Grammar { /** 开始符号 */
private Nonterminal start;
/** 产生式 */
private List<Production> productions; }

  

6.FIRST函数

/**
* P140 FIRST(X)集合
* @param token
* @return
*/
public Set<Terminal> first(Symbol token) { Set<Terminal> result = new HashSet<>(); // X 是一个终结符号
// 1) if X is a terminal, then FIRST(X) = {X}
if (token instanceof Terminal) {
result.add((Terminal) token);
return result;
} List<Production> productionList = getProduction((Nonterminal) token);
for (Production production : productionList) { // 如果 X->ε是一个产生式,那么将ε加入到FIRST(X)
if (production.getBody().size() == 1 && production.getBody().get(0).equals(Terminal.of("ε"))) {
result.add(Terminal.of("ε"));
} else {
Set<Terminal> firstSet = first(production.getBody());
result.addAll(firstSet);
}
} return result;
}

  

/**
* P140 FIRST(X)集合
* @param tokens
* @return
*/
public Set<Terminal> first(List<Symbol> tokens) { // 是否全部包含ε
boolean allContainsEpsilon = true;
Set<Terminal> result = new HashSet<>();
for (Symbol token : tokens) { Set<Terminal> firstSet = first(token);
for (Terminal terminal : firstSet) {
if (terminal.equals(Terminal.of("ε"))) {
continue;
}
result.add(terminal);
} if (!firstSet.contains(Terminal.of("ε"))) {
allContainsEpsilon = false;
break;
}
} // 如果对于所有的j=1,2,...,k,ε在FIRST(Yj)中,那么将ε加入到FIRST(X)
if (allContainsEpsilon) {
result.add(Terminal.of("ε"));
} return result;
}

  

编译器-FIRST集合的更多相关文章

  1. Java集合框架——容器的快速报错机制 fail-fast 是什么?

    前言:最近看 java 集合方面的源码,了解到集合使用了 fail-fast 的机制,这里就记录一下这个机制是什么,有什么用,如何实现的. 一.fail-fast 简介 fail-fast 机制,即快 ...

  2. g++编译器的使用

    关于g++ g++  是GNU组织开发出的编译器软件集合(GCC)下的一个C++编译器.它是Unix 和 Linux  系统下标配的 基于命令行的 C++编译器.如果你的系统是Windows,可以按照 ...

  3. g++编译器的使用(转载)

    关于g++ g++  是GNU组织开发出的编译器软件集合(GCC)下的一个C++编译器.它是Unix 和 Linux  系统下标配的 基于命令行的 C++编译器.如果你的系统是Windows,可以按照 ...

  4. cc 和gcc编译器

    从名字上看,老的unix系统的CC程式叫做C Compiler.但GCC这个名字按GNU的说法叫做Gnu Compiler Collection.因为gcc包含非常多编译器(C, C++, Objec ...

  5. Android.mk 文件语法详解

    0. Android.mk简介: Android.mk文件用来告知NDK Build 系统关于Source的信息. Android.mk将是GNU Makefile的一部分,且将被Build Syst ...

  6. GCC的gcc和g++区别

    看的Linux公社的一篇文章,觉得不错,内容复制过来了. 其实在这之前,我一直以为gcc和g++是一个东西,只是有两个不同的名字而已,今天在linux下编译一个c代码时出现了错误才找了一下gcc和g+ ...

  7. Android.mk 文件语法详解 转:http://blog.sina.com.cn/s/blog_602f8770010148ce.html

    0. Android.mk简介: Android.mk文件用来告知NDK Build 系统关于Source的信息. Android.mk将是GNU Makefile的一部分,且将被Build Syst ...

  8. Android NDK开发之Android.mk文件

    Android NDK开发指南---Android.mk文件 博客分类: Android NDK开发指南   Android.mk文件语法详述 介绍: ------------ 这篇文档是用来描述你的 ...

  9. Android.mk文件语法规范及使用模板

    Android.mk文件语法详述 介绍:------------这篇文档是用来描述你的C或C++源文件中Android.mk编译文件的语法的,为了理解她们我们需要您先看完docs/OVERVIEW.h ...

  10. 【转】configure/make/make install的使用说明

    这些都是典型的使用GNU的AUTOCONF和AUTOMAKE产生的程序的安装步骤. ./configure是用来检测你的安装平台的目标特征的.比如它会检测你是不是有CC或GCC,并不是需要CC或GCC ...

随机推荐

  1. DOM – Browser Reflow & Repaint

    前言 没有深入研究过, 懂个概念就好, 等性能遇到问题在来看看. 以前写的笔记: 游览器 reflow 参考: reflow和repaint引发的性能问题 精读<web reflow> R ...

  2. SEO – Schema and JSON-LD

    大纲介绍 Schema 是 Google, Microsoft, Yahoo 联合成立的, 目的是统一网页的表示方式, 这样搜素引擎会比较方便显示内容. 它虽然不算那种 w3c 独立的组织. 但其它的 ...

  3. .NET 开源工业级移动端仓库管理系统

    前言 在工业生产中,定制化的软件对于每个环节都至关重要.对于仓库管理,推荐一款开源的仓库管理系统(WMS)解决方案. 这款基于.NET 框架开发的移动应用,提供了全面的仓库操作.订单处理.主数据管理. ...

  4. JAVAEE——MySQL安装

    一.下载MySQL(两种方式) 1.官网下载 官网下载地址:https://www.mysql.com/downloads   2.点击下载(版本:mysql-8.0.28-winx64) 链接:ht ...

  5. PasteForm最佳CRUD实践,实际案例PasteTemplate详解之3000问(二)

    作为"贴代码"力推的一个CRUD实践项目PasteTemplate,在对现有的3个项目进行实战后效果非常舒服!下面就针对PasteForm为啥我愿称为最佳CRUD做一些回答: 哪里 ...

  6. Resource Acquisition Is Initialization

    在 C++ 中,资源获取即初始化(RAII, Resource Acquisition Is Initialization)是一种管理资源的编程惯用法.其核心思想是将资源的获取和释放绑定到对象的生命周 ...

  7. 2023年3月中国数据库行业分析报告正式发布,带你了解NL2SQL技术原理

    为了帮助大家及时了解中国数据库行业发展现状.梳理当前数据库市场环境和产品生态等情况,从2022年4月起,墨天轮社区行业分析研究团队出品将持续每月为大家推出最新<中国数据库行业分析报告>,持 ...

  8. 2023年3月中国数据库排行榜:开源OTO揽获前三,传统达梦、GBase触机便发

    东风何时至,已绿湖上山. 春风送来了2023年3月的 墨天轮中国数据库流行度排行,本月共有260个数据库参与排名,本月榜单前十可以用一句话概括为:榜单前八较上月岿然不动,GBase 奋勇向前重返第九. ...

  9. vue2 + webpack 分析报告 report == webpack-bundle-analyzer

    packjson.js 配置 "build-report":"vue-cli-service build --report", 执行 : npm run bui ...

  10. MongoDB安装及配置Navicat MongoDB Tools

    一.下载MongoDB 1.下载网址:https://www.mongodb.com/try/download/community 注:本文档以Windows和msi安装为例 二.安装MongoDB ...