语法分析器的两个重要函数 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. C++面试题整理 2

    8. C++11新特性又哪些 自动类型推导auto,智能指指针(share_ptr,unique_ptr等),for循环简化,线程相关的(std::thread/std::mutex),空指针null ...

  2. Hugging Face NLP课程学习记录 - 2. 使用 Hugging Face Transformers

    Hugging Face NLP课程学习记录 - 2. 使用 Hugging Face Transformers 说明: 首次发表日期:2024-09-19 官网: https://huggingfa ...

  3. 月薪20k以上的软件测试工程师的必备知识点?全部拿走吧!

    我们都知道作为一个软件测试工程师,入门相对比较简单,但是要达到技术精通,甚至薪资能达到20k以上的话,那绝对需要对测试开发有一个系统的了解,以及对这些系统的知识能够熟练掌握. 今天的话是我从阿里以为做 ...

  4. 系统编程-操作系统概论PART2

    <1> 操作系统提供的服务   <2> 现代操作系统的特征 2.1 微内核(英文中常译作µ-kernel或者micro kernel) 这是一种能够提供必要服务的操作系统内核: ...

  5. 12 Masked Self-Attention(掩码自注意力机制)

    博客配套视频链接: https://space.bilibili.com/383551518?spm_id_from=333.1007.0.0 b 站直接看 配套 github 链接:https:// ...

  6. Office365常用的命令(持续更新中)

    Office365常用的命令(持续更新中) 持续更新中............. Enable-ExchangeCertificate -Thumbprint B9C93420E7BEE46C1CD2 ...

  7. 《刚刚问世》系列初窥篇-Java+Playwright自动化测试-2-环境准备与搭建-基于Maven(详细教程)

    1.简介 上一篇宏哥已经讲解和分享了如何通过引入jar包来搭建Java+Playwright自动化测试环境,这一种是比较老的方法,说白了就是过时的老古董,但是我们必须了解和知道,其实maven搭建无非 ...

  8. 华为OpenEnler Linux系统部署LNMP

    LNMP是Linux+Nginx+Mysql+PHP所构建的一个动态开发环镜 我这里使用的系统是华为的OpenEnler系统,使用了Nginx1.12版本.Mysql8和PHP7.4 如果有出错的地方 ...

  9. activiti教程

    一.工作流介绍 1.1 概念 工作流(Workflow),就是通过计算机对业务流程自动化执行管理.它主要解决的是"使在多个参与者之间按照某种预定义的规则自动进行传递文档.信息或任务的过程,从 ...

  10. Stream流,集合与基本数组的相互转换

    Arrays类的Api stream()方法传入数组,返回对应的stream流. Collection集合的Api: stream()不传参数,返回Stream流. 有了上述Api可以完成如下转换.. ...