语法分析器的两个重要函数 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. ASP.NET Core C# 反射 & 表达式树 (第二篇)

    前言 上一篇讲到了各种反射的操作方式, 这一篇主要说说如何找到类型. Type Information 在找类型的时候, 除了依据简单的 string 以外, 还会用到很多类型属性来做判断. 比如它是 ...

  2. tailwindcss 经验

    树摇时扫描的文件范围 根据 tailwindcss.config.js 中 content 的配置,跟打包软件加载的模块无关.即未使用的模块中的 class 也会被包含进来.

  3. C++ 数组元素操作

    数组元素的移除 核心思路:创建一个新的内存空间存储移除后的数组,再将原数组delete释放,再将指针指向新数组. cout << "----------------------- ...

  4. QT数据可视化框架编程实战之三维曲面图 实时变化的三维曲面图 补天云QT技术培训专家

    QT数据可视化框架编程实战之三维曲面图 实时变化的三维曲面图 补天云QT技术培训专家 简介 本文将介绍QT数据可视化框架编程实战之三维曲面图,本文通过构造一个数据实时变化的三维曲面图的应用实例来展示Q ...

  5. SQL limit字句

    limit用法介绍 limit子句可以返回检索查询行的某一连续的部分 用法介绍: SELECT column_list FROM table1 ORDER BY column_list LIMIT r ...

  6. 一次基于AST的大规模代码迁移实践

    作者:来自 vivo 互联网大前端团队- Wei Xing 在研发项目过程中,我们经常会遇到技术架构迭代更新的需求,通过技术的迭代更新,让项目从新的技术特性中受益,但由于很多新的技术迭代版本并不能完全 ...

  7. Camera 冷启动阶段分解

    目录 一.Camx trace 调试开关设置 1.设置 camxoverridesettings trace开关 2. 重启后设置开启camx trace 开关 二.Camera 冷启动阶段分解分析 ...

  8. nextjs 的函数,参数,属性装饰器的使用

    // 属性装饰器 const doc1:PropertyDecorator = (target:any,val: string | symbol) => { console.log(target ...

  9. 浅谈 K-D Tree 及其进阶应用

    前言 \(\text{K-D Tree (K-Dimension Tree)}\) 是一种可以有效处理高维信息的数据结构. 在一般信息学竞赛题目中 \(k = 2\),此时它又称 \(\text{2- ...

  10. 不用PLC和板卡,一台电脑就可以控制伺服

    1.前言 大家好!我是付工. EtherCAT是运动控制领域使用最广泛的总线通信协议之一. 如果我们只有一台电脑,能不能直接控制EtherCAT总线伺服呢? 这个是完全可以的. 我们可以在电脑上安装实 ...