精华内容
下载资源
问答
  • 上下文无关文法

    2019-01-27 13:17:44
    引进文法的目的在于描述程序设计语言。在实际应用中,一方面,需要对文法提出一些限制条件,但... 上下文无关文法化简的目的是在不降低文法生成句子能力的前提下,通过限制产生式的格式来降低文法分析算法的复杂度。
  • 上下文无关文法是描述程序语言语法的强有力的数学工具。乔姆斯基文法体系3型文法:正则文法:词法结构2型文法:上下文无关文法语法结构1型文法:上下文有关文法0型文法:任意文法每一个外部文法(大圈)都比内部...

    上下文无关文法是描述程序语言语法的强有力的数学工具。

    70f2bba372e6a859d6299a7fc29e9ab3.png

    乔姆斯基文法体系

    3型文法:正则文法:词法结构

    2型文法:上下文无关文法:语法结构

    1型文法:上下文有关文法

    0型文法:任意文法

    每一个外部文法(大圈)都比内部文法(小圈)表达能力强。

    举个自然语言处理的例子

    • 自然语言中的句子的典型结构
      • 主语 谓语 宾语
      • 名词 动词 名词
    • 例子:
      • 名词:{羊, 老虎, 草, 水}
      • 动词:{吃, 喝}
    • 句子:
      • 羊 吃 草
      • 羊 喝 水
      • 老虎 吃 老虎
      • 草 吃 老虎
      • ......

    对这个例子,我们进行形式化分析:

    (S 表示句子, -> 表示推出, N 表示名词, V 表示动词)

    S -> N V N 
    N -> s(sheep)
       | t(tiger)
       | g(grass)
       | w(water)
    V -> e(eat)
       | d(drink)

    我们将其中的大写符号叫做非终结符:{S, N, V}

    将小写的符号(名词+谓词)叫做终结符:{s, t, g, w, e, d}

    开始符号是:S

    上下文无关文法

    上下文无关文法 G 是一个四元组:

    G = (T, N, P, S)

    • 其中 T 是终结符集合
    • N 是非终结符集合
    • P 是一组产生式规则
      • 每条规则的形式: X -> β1 β2 ... βn, n >= 0
        • 其中 X ∈ N, βi ∈(T ∪ N)
    • S 是唯一的开始符号(非终结符)
      • S ∈ N

    对于之前给出的上下文无关文法的例子

    S -> N V N 
    N -> s
       | t
       | g
       | w
    V -> e
       | d

    G = {N, T, P, S}

    非终结符号:N = {S, N, V}

    终结符号: T = {s, t, g, w, e, d}

    开始符号:S

    产生式规则集合:

    { S -> N V N,

    N -> s,

    N -> t,

    N -> g,

    N -> w,

    V -> e,

    V -> d}

    在给一个上下文无关文法的例子

    E -> num
       | id
       | E + E
       | E * E

    G = {N, T, P, S}

    非终结符: N = {E}

    终结符: T = {num, id, +, *}

    开始符号:E

    产生式规则集合:

    { E -> num

    E -> id

    E -> E + E

    E -> E * E }

    也可以将上述集合中的四条语句相互连接起来,组合成如题所示的用或表示的一条语句。

    推导

    • 给定文法 G, 从 G 的开始符号 S 开始,用产生式的右部替换左侧的 非终结符
    • 此过程不断重复,直到不出现非终结符为止
    • 最终的串称为句子

    举个例子,如下面的文法 G

    S -> N V N 
    N -> s
       | t
       | g
       | w
    V -> e
       | d

    首先,从开始符号 S 开始进行替换。 S -> N V N

    此中还有三个非终结符,对其进行循环,替换 V, 得到 N d N ;

    接着,替换第三个 N 为 g , 得到 N d g ;

    最后,替换仅剩下的最后一个非终结符 N 为 t, 得到 t d g。

    对于上面的三个终结节点 N V N 的选取先后顺序可以自行调整,没有严格的规定。

    最左推导和最右推导

    • 最左推导:每次总是选择最左侧的符号进行替换。
      • 即对于上例中的 N V N ,首先替换最左边的 N, 再替换之后最左侧的非终结符 V, 最后替换最有一个非终结符 N。
    • 最右推导:每次总是选择最右侧的符号进行替换。

    语法分析

    给定文法 G 和句子 S, 语法分析要回答的问题:是否存在对句子 S 的推导?

    若仍然选择上面的文法 G,当 S = t d g 时,我们能够实现 S 通过若干步的推导得到 t d g。所以回答 是。

    若 S = t d d, 则不能实现该推导,回答 否。

    语法分析器的任务

    70f2bba372e6a859d6299a7fc29e9ab3.png

    语法分析器从记号流中获取 句子 S ,再接受使用 上下文无关文法 G 描述的语言的语言规则,回答在 G 中是否存在对 S 的推导。是或者否。并给程序员反馈精确的出错信息。


    原文链接:

    • 编译原理 - 网易云课堂
    展开全文
  • 上下文无关语法

    千次阅读 2018-01-06 21:34:31
    本博文主要介绍基于巴科斯-诺尔范式的上下文无关语法,以及在计算机编程语言和解析技术上的应用。 引言 编程语言,协议规范,查询语言,文件格式,模式语言,内存布局,形式语言,配置文件,标记语言,格式化...

    本博文主要介绍基于巴科斯-诺尔范式的上下文无关语法,以及在计算机编程语言和解析技术上的应用。

    引言

    编程语言,协议规范,查询语言,文件格式,模式语言,内存布局,形式语言,配置文件,标记语言,格式化语言和元语言构成了我们计算的方式。

    那么,什么构成了语言呢?
    是语法。
    语法是语言的语言。
    在每一种语言的背后,都有一个决定其结构的语法。

    下面我们将要解释语法和语法的常用符号,例如Backus-Naur Form(BNF)(巴科斯-诺尔范式,是由John Backus和Peter Naur首次引入一种形式化符号来描述给定语言的语法),Extended Backus-Naur Form(EBNF,扩展巴科斯-诺尔范式),ABNF(增强巴科斯-诺尔范式)以及常规扩展BNF。

    现在几乎每一位新编程语言书籍的作者都会使用巴科斯范式来定义编程语言的语法规则
    巴科斯-诺尔范式的内容大概是这样的:
    (1) 在双引号中的字"word"代表着这些字符本身。double_quota 用来代表双引号
    (2) 在双引号外的字(有可能是下划线)代表着语法部分
    (3) 尖括号(<>)内包含的为必选项
    (4) 方括号([])内包含的是可选项
    (5) 大括号({})内包含的是可重复0到无数次的项
    (6) 竖线(|)表示在其左右两边任选一项,相当于OR的意思
    (7) ::= 是"被定义为"的意思。

    下面是使用巴科斯范式定义的java语言中的for语句的实例:

    FOR_STATEMENT ::= 
    "for" "(" ( variable_declaration | (expression ";")| ";")
    [ expression ] ";"
    [ expression ]
    ")" statement

    通过本次学习,您将能够识别和解释所有常用的语法符号。

    语法定义一种语言

    在计算机科学中,最常见的语法类型是上下文无关语法,而这些语法将作为本文的重点进行讲解。
    上下文无关语法很丰富,可以用来描述很多(尽管不是全部)语言的递归句法结构,至于上下文无关语法之外的语法我们稍后再讨论。

    上下文无关语法的组件:
    一套规则是语法的核心组成部分。
    每个规则有两个部分:(1)名称(2)名称的扩展

    例如,我们正在创建一个语法来处理英文文本,我们可能会添加一条规则。如:
    名词短语可以扩展为文章名词。
    由此我们可以最终推断出“the dog” 是一个名词短语。

    或者,如果我们正在描述一种编程语言,我们可以添加一个规则。如:
    表达式可能扩展为表达式+表达式
    如果我们将语法作为数学对象来使用,那么我们会把“可能扩展到”改为→
    这样上面的例子就可以写成:
    名词短语→ 文章名词
    表达式→ 表达式+表达式

    举个例子,考虑经典明确的表达式语法:

    expr→term+expr
    expr→term
    term→term∗factor
    term→factor
    factor→(expr)
    factor→const
    const→integer
    
    那么我们如何知道3*7 是一个有效的表达式呢?
    因为:
    expr 可以扩展为term
    进而可以扩展为 term * factor
    进而可以扩展为 factor * facor
    进而可以扩展为 const * factor
    进而可以扩展为 const * const
    进而可以扩展为 3 * const
    进而可以扩展为 3 * 7

    巴科斯-诺尔范式(BNF)符号

    当描述语言时,Backus-Naur范式(BNF)是用于编码语法的正式符号。
    很多编程语言,协议和格式都在其规范中有一个BNF描述。
    Backus-Naur范式的每一条规则都有如下结构:
    name ::= 扩展
    其中::= 表示为“可扩展为”,”可以替换为”
    在一些文本中,名称也被称为非终端符号。

    Backus-Naur范式中的每个名称都被尖括号<>包围,无论它出现在规则的左侧还是右侧。
    扩展是一个包含终端符号和非终端符号的表达式,通过排列逻辑和选择逻辑连接在一起。
    简单的并排表达式表示表达式排序关系。
    终端符号是字面值类似于(”+” 或者”function”)或者字面量类型(如整数)
    |符号表示选择逻辑。

    举个例子说明一下,用BNF表示经典表达式语法如下:

    <expr> ::= <term> "+" <expr>
             |  <term>
     <term> ::= <factor> "*" <term>
             |  <factor>
     <factor> ::= "(" <expr> ")"
               |  <const>
     <const> ::= integer

    自然,我们可以为BNF的规则定义一个语法如下:

    rule —> name ::= expansion
    name —> <identifier>
    expansion —> expansion expansion
    expansion —> expansion | expansion
    expansion —> name
    expansion —> terminal
    
    我们可以使用正则表达式[A-Za-z_0-9]+来定义identifier
    terminal 可以是引号包围的字面量或者是字面量类型(如整数)。

    扩展BNF(EBNF)符号

    扩展Backus-Naur范式是BNF范式的扩展集合。EBNF不能说是BNF的超集,因为EBNF更改了部分规则定义关系。比如::= 改为了=,从非终端规则中删除了尖括号等。
    EBNF范式中更为重要的差异是它扩展了附加操作。

    取反操作
    例如,规则:
     <term> :: = ["-"] <factor>
    允许因素是相反数。

    重复操作
    在EBNF中,{}表示表达式可以重复零次或多次。
    例如,规则:
     <args> :: = <arg> {"," <arg>}
    定义了一个常规的逗号分隔参数列表。

    分组操作
    为了表达优先级,EBNF语法可以使用括号()来明确地定义扩展顺序。
    例如,
     <expr> :: = <term>("+"|"-")<expr>
    定义了一个允许加法和减法的表达式。

    级联操作
    在某些形式的EBNF中,运算符明确表示串联,而不是形式上的并列。

    增强的BNF范式(ABNF)

    协议规范通常使用增强的Backus-Naur范式(BNF)
    ABNF原则上与EBNF相似,只不过其在选择操作,可选操作以及重复操作表达用的符号不同。
    ABNF还提供了精确指定特定字节值的能力,这在协议中非常重要。
    在ABNF中,
    选择符号是/
    选项符号是方括号[]
    重复符号是前缀*
    重复n次或者更多次符号是前缀n*
    重复n到m次符号是前缀n*m
    EBNF的 {expansion}在ABNF中使用*(expansion) 符号表示

    以下是从RFC 5322中获取的日期和时间格式的定义。

    date-time =[ day-of-week "," ] date time [CFWS]
    day-of-week  =([FWS] day-name) / obs-day-of-week
    day-name  ="Mon" / "Tue" / "Wed" / "Thu" /"Fri" / "Sat" / "Sun"
    date=day month year
    day =([FWS] 1*2DIGIT FWS) / obs-day
    month  ="Jan" / "Feb" / "Mar" / "Apr" /"May" / "Jun" / "Jul" / "Aug" /"Sep" / "Oct" / "Nov" / "Dec"
    year=(FWS 4*DIGIT FWS) / obs-year
    time=time-of-day zone
    time-of-day  =hour ":" minute [ ":" second ]
    hour=2DIGIT / obs-hour
    minute =2DIGIT / obs-minute
    second =2DIGIT / obs-second
    zone=(FWS ( "+" / "-" ) 4DIGIT) / obs-zone

    常规扩展BNF范式

    在语法中类似正则表达式的操作是很常见的。
    例如,pyhon的语法规范使用它们。
    在这些语法中:
    postfix *表示"重复0次以上"
    后缀+表示"重复1次以上"
    后缀?意味着"0或1次"

    Python中浮点文字的定义是一个很好的结合几个符号的例子:

    floatnumber   ::=  pointfloat | exponentfloat
    pointfloat    ::=  [intpart] fraction | intpart "."
    exponentfloat ::=  (intpart | pointfloat) exponent
    intpart       ::=  digit+
    fraction      ::=  "." digit+
    exponent      ::=  ("e" | "E") ["+" | "-"] digit+
    
    它没有在名称周围使用的尖括号(如许多EBNF符号和ABNF),但使用:: =(如BNF)。 它将常规操作(如非空重复的+)与EBNF约定(如[])混合在一起进行选择。
    整个Python语言的语法使用略有不同(但仍然是常规)的符号。

    上下文无关语法之外的世界

    以上我们讨论的都是上下文无关语法,虽然正则表达式在属于上下文无关语法:你可以将任何正则表达式重写为一个语法来表达这个正则表达式想要表达的内容,但是相反,并不是每个语法都可以转换成一个等价的正则表达式。

    为了超越上下文无关语法的表达能力,需要在语法中允许一定程度的上下文敏感度。
    上下文敏感性意味着终端符号可能出现在规则的左侧:
    考虑下面的设计语法:
    <top> :: = <a>")"
    <a> :: ="("<exp>
    "("<exp>")":: = 7
    <top>可以展开成<a>")";
    进而可能扩展为"("<exp>")";
    进而可能扩展为7。

    尽管设计上这种改变看起来很小,但是它使得语法等同于和它们描述的语言相关的图灵机。
    通过限制规则使左侧的符号比右侧的所有扩展符号严格少,上下文相关的语法相当于(可确定的)线性有界自动机。

    尽管有些语言是上下文敏感的,但是上下文敏感的语法很少用于描述计算机语言。
    例如,由于C处理标识符和类型的方式的需要,C稍微有点上下文敏感性,但是这种上下文敏感性是通过特殊的约定来解决的,而不是通过在语法中引入上下文敏感性。

    解析

    解析是跟语法密切相关的一个话题。
    解析需要一个语法和一个字符串,并回答两个问题:
    1.字符串是否是文法的语言
    2.字符串相对应的语法结构是什么

    参考:

    The language of languages

    Parsing Techniques: A Practical Guide (Monographs in Computer Science)

    展开全文
  • 上下文无关文法概述 下推自动机 非上下文无关语言 上下文无关文法的重要性如下 表达能力强大足于表示大多数程序设计语言语法 可以构造有效的分析算法以检验一个给定的字符串是否由某个上下文无关文法产生
  • 上下文无关文法和正则文法Have you ever noticed that, when you are writing code in a text editor like VS code, it recognizes things like unmatched braces? And it also sometimes warns you, with an ...

    上下文无关文法和正则文法

    Have you ever noticed that, when you are writing code in a text editor like VS code, it recognizes things like unmatched braces? And it also sometimes warns you, with an irritating red highlight, about the incorrect syntax that you have written?

    您是否曾经注意到,当您在像VS代码这样的文本编辑器中编写代码时,它会识别出不匹配的花括号之类的东西吗? 有时它还会以红色高亮警告您有关您编写的语法错误的警告?

    If not, then think about it. That is after all a piece of code. How can you write code for such a task? What would be the underlying logic behind it?

    如果没有,请考虑一下。 那毕竟是一段代码。 您如何为此类任务编写代码? 其背后的潜在逻辑是什么?

    These are the kinds of questions that you will face if you have to write a compiler for a programming language. Writing a compiler is not an easy task. It is bulky job that demands a significant amount of time and effort.

    如果您必须为编程语言编写编译器,则将遇到这些问题。 编写编译器并非易事。 这项繁琐的工作需要大量的时间和精力。

    In this article, we are not going to talk about how to build compilers. But we will talk about a concept that is a core component of the compiler: Context Free Grammars.

    在本文中,我们将不讨论如何构建编译器。 但是,我们将讨论作为编译器核心组件的概念:上下文无关文法。

    介绍 (Introduction)

    All the questions we asked earlier represent a problem that is significant to compiler design called Syntax Analysis. As the name suggests, the challenge is to analyze the syntax and see if it is correct or not. This is where we use Context Free Grammars. A Context Free Grammar is a set of rules that define a language.

    我们之前提出的所有问题都代表着一个对编译器设计非常重要的问题,称为语法分析。 顾名思义,挑战在于分析语法并查看其是否正确。 这是我们使用上下文无关文法的地方。 上下文无关语法是定义语言的一组规则。

    Here, I would like to draw a distinction between Context Free Grammars and grammars for natural languages like English.

    在这里,我想区分上下文无关文法和自然语言(如英语)的语法之间的区别。

    Context Free Grammars or CFGs define a formal language. Formal languages work strictly under the defined rules and their sentences are not influenced by the context. And that's where it gets the name context free.

    上下文无关文法或CFG定义了一种正式语言。 形式语言严格按照定义的规则工作,其句子不受上下文的影响。 这就是免费获取名称上下文的地方。

    Languages such as English fall under the category of Informal Languages since they are affected by context. They have many other features which a CFG cannot describe.

    诸如英语之类的语言属于非正式语言,因为它们受上下文的影响。 它们具有CFG无法描述的许多其他功能。

    Even though CFGs cannot describe the context in the natural languages, they can still define the syntax and structure of sentences in these languages. In fact, that is the reason why the CFGs were introduced in the first place.

    即使CFG无法用自然语言描述上下文,它们仍然可以使用这些语言定义句子的语法和结构。 实际上,这就是为什么首先引入CFG的原因。

    In this article we will attempt to generate English sentences using CFGs. We will learn how to describe the sentence structure and write rules for it. To do this, we will use a JavaScript library called Tracery which will generate sentences on the basis of rules we defined for our grammar.

    在本文中,我们将尝试使用CFG生成英语句子。 我们将学习如何描述句子结构并为其编写规则。 为此,我们将使用一个称为TraceryJavaScript库,该库将根据我们为语法定义的规则生成句子。

    Before we dive into the code and start writing the rules for the grammar, let's just discuss some basic terms that we will use in our CFG.

    在深入研究代码并开始编写语法规则之前,我们仅讨论一些将在CFG中使用的基本术语。

    Terminals: These are the characters that make up the actual content of the final sentence. These can include words or letters depending on which of these is used as the basic building block of a sentence.

    终端 :这些字符组成了最后一句话的实际内容。 这些可以包括单词或字母,具体取决于将哪个单词或字母用作句子的基本组成部分。

    In our case we will use words as the basic building blocks of our sentences. So our terminals will include words such as "to", "from", "the", "car", "spaceship", "kittens" and so on.

    在我们的案例中,我们将单词作为句子的基本组成部分。 因此,我们的航站楼将包含诸如“至”,“来自”,“该”,“汽车”,“太空飞船”,“小猫”等词语。

    Non Terminals: These are also called variables. These act as a sub language within the language defined by the grammar. Non terminals are placeholders for the terminals. We can use non terminals to generate different patterns of terminal symbols.

    非终端 :也称为变量。 它们在语法定义的语言中充当副语言。 非终端是终端的占位符。 我们可以使用非终端来生成终端符号的不同模式。

    In our case we will use these Non terminals to generate noun phrases, verb phrases, different nouns, adjectives, verbs and so on.

    在本例中,我们将使用这些Non终端生成名词短语,动词短语,不同的名词,形容词,动词等。

    Start Symbol: a start symbol is a special non terminal that represents the initial string that will be generated by the grammar.

    起始符号 :起始符号是一个特殊的非终结符,表示将由语法生成的初始字符串。

    Now that we know the terminology let's start learning about the grammatical rules.

    现在我们已经知道了术语,让我们开始学习语法规则。

    While writing grammar rules, we will start by defining the set of terminals and a start state. As we learned before, that start symbol is a non-terminal. This means it will belong to the set of non-terminals.

    在编写语法规则时,我们将从定义一组终端和一个开始状态开始。 正如我们之前所了解的,该开始符号是一个非终止符。 这意味着它将属于非终端集合。

    T: ("Monkey", "banana", "ate", "the")
    S: Start state.

    And the rules are:

    规则是:

    S --> nounPhrase verbPhrase
    nounPhrase --> adj nounPhrase | adj noun
    verbPhrase --> verb nounPhrase
    adjective  --> the
    noun --> Monkey | banana
    verb --> ate

    The above grammatical rules may seem somewhat cryptic at first. But if we look carefully, we can see a pattern that is being generated out of these rules.

    上面的语法规则乍看起来似乎有些神秘。 但是,如果我们仔细观察,就会发现这些规则正在产生一种模式。

    A better way to think about the above rules is to visualise them in the form of a tree structure. In that tree we can put S in the root and nounPhrase and verbPhrase can be added as children of the root. We can proceed in the same way with nounPhrase and verbPhrase too. The tree will have terminals as its leaf nodes because that is where we end these derivations.

    考虑上述规则的一种更好的方法是以树结构的形式可视化它们。 在那棵树中,我们可以将S放在根中,然后可以将名词短语动词短语添加为根的子代。 我们也可以对名词短语动词短语进行相同的处理。 该树将以终端作为其叶节点,因为这是我们结束这些派生的地方。

    In the above image we can see that S (a nonterminal)  derives two non terminals NP(nounPhrase) and VP(verbPhrase). In the case of NP, it has derived two non terminals, Adj and Noun.

    在上图中,我们可以看到S (一个非终结符)派生了两个非终结符NP ( 名词短语 )和VP ( 动词短语 )。 在NP的情况下,它派生了两个非终结符AdjNoun

    If you look at the grammar, NP could also have chosen Adj and nounPhrase. While generating text, these choices are made randomly.

    如果您查看语法, NP也可能选择了AdjnounPhrase 。 在生成文本时,这些选择是随机进行的。

    And finally the leaf nodes have terminals which are written in the bold text. So if you move from left to right, you can see that a sentence is formed.

    最后,叶节点具有以粗体文字显示的终端。 因此,如果从左向右移动,则可以看到形成了一个句子。

    The term often used for this tree is a Parse Tree. We can create another parse tree for a different sentence generated by this grammar in a similar way.

    通常用于此树的术语是解析树。 我们可以用类似的方式为该语法生成​​的不同句子创建另一个分析树。

    Now let's proceed further to the code. As I mentioned earlier, we will use a JavaScript library called Tracery for text generation using CFGs. We will also write some code in HTML and CSS for the front-end part.

    现在,让我们继续进行代码。 正如我前面提到的,我们将使用一个称为TraceryJavaScript库来使用CFG生成文本。 我们还将在前端部分用HTML和CSS编写一些代码。

    代码 (The Code)

    Let's start by first getting the tracery library. You can clone the library from GitHub here. I have also left the link to the GitHub repository by galaxykate at the end of the article.

    让我们首先获取窗饰库。 您可以在此处从GitHub克隆该库。 我还在文章结尾处留下了galaxykate到GitHub存储库的链接。

    Before we use the library we will have to import it. We can do this simply in an HTML file like this.

    在使用库之前,我们必须先导入它。 我们可以简单地在这样HTML文件中执行此操作。

    <html>
        <head>
            <script src="tracery-master/js/vendor/jquery-1.11.2.min.js"></script>
    		<script src="tracery-master/tracery.js"></script>
    		<script src="tracery-master/js/grammars.js"></script>
            <script src='app.js'></script>
        </head>
        
    </html>

    I have added the cloned tracery file as a script in my HTML code. We will also have to add JQuery to our code because tracery depends on JQuery. Finally, I have added app.js which is the file where I will add rules for the grammar.

    我已将克隆的窗饰文件作为脚本添加到我HTML代码中。 我们还必须将JQuery添加到我们的代码中,因为窗饰取决于JQuery。 最后,我添加了app.js ,这是我将在其中添加语法规则的文件。

    Once that is done, create a JavaScript file where we will define our grammar rules.

    完成此操作后,创建一个JavaScript文件,在其中定义语法规则。

    var rules = {
        	"start": ["#NP# #VP#."],
        	"NP": ["#Det# #N#", "#Det# #N# that #VP#", "#Det# #Adj# #N#"],
        	"VP": ["#Vtrans# #NP#", "#Vintr#"],
        	"Det": ["The", "This", "That"],
        	"N": ["John Keating", "Bob Harris", "Bruce Wayne", "John Constantine", "Tony Stark", "John Wick", "Sherlock Holmes", "King Leonidas"],
        	"Adj": ["cool", "lazy", "amazed", "sweet"],
        	"Vtrans": ["computes", "examines", "helps", "prefers", "sends", "plays with", "messes up with"],
        	"Vintr": ["coughs", "daydreams", "whines", "slobbers", "appears", "disappears", "exists", "cries", "laughs"]
        }

    Here you will notice that the syntax for defining rules is not much different from how we defined our grammar earlier. There are very minor differences such as the way non-terminals are defined between the hash symbols. And also the way in which different derivations are written. Instead of using the "|" symbol for separating them, here we will put all the different derivations as different elements of an array. Other than that, we will use the semicolons instead of arrows to represent the transition.

    在这里,您会注意到定义规则的语法与我们之前定义语法的方式没有太大不同。 有一些细微的差异,例如在哈希符号之间定义非终结符的方式。 以及编写不同派生方式的方式。 代替使用“ |” 符号,将它们分开,在这里,我们将所有不同的导数作为数组的不同元素放置。 除此之外,我们将使用分号代替箭头来表示过渡。

    This new grammar is a little more complicated than the one we defined earlier. This one includes many other things such as Determiners, Transitive Verbs and Intransitive Verbs. We do this to make the generated text look more natural.

    这种新语法比我们之前定义的语法复杂一些。 这包括许多其他事物,例如限定词,及物动词和不及物动词。 我们这样做是为了使生成的文本看起来更自然。

    Let's now call the tracery function "createGrammar" to create the grammar we just defined.

    现在让我们调用窗饰函数“ createGrammar”来创建我们刚刚定义的语法。

    let grammar = tracery.createGrammar(rules);

    This function will take the rules object and generate a grammar on the basis of these rules. After creating the grammar, we now want to generate some end result from it. To do that we will use a function called "flatten".

    该函数将使用规则对象并在这些规则的基础上生成语法。 创建语法后,我们现在要从中生成一些最终结果。 为此,我们将使用一个名为“ flatten”的函数。

    let expansion = grammar.flatten('#start#');

    It will generate a random sentence based on the rules that we defined earlier. But let's not stop there. Let's also build a user interface for it. There's not much we will have to do for that part – we just need a button and some basic styles for the interface.

    它将根据我们之前定义的规则生成一个随机句子。 但是,我们不要就此止步。 我们还为其构建一个用户界面。 在那部分,我们不需要做太多的事情,我们只需要一个按钮和一些界面的基本样式即可。

    In the same HTML file where we added the libraries we will add some elements.

    在添加库的同一HTML文件中,我们将添加一些元素。

    <html>
        <head>
            <title>Weird Sentences</title>
            <link rel="stylesheet" href="style.css"/>
            <link href="https://fonts.googleapis.com/css?family=UnifrakturMaguntia&display=swap" rel="stylesheet">
            <link href="https://fonts.googleapis.com/css?family=Harmattan&display=swap" rel="stylesheet">
            
            <script src="tracery-master/js/vendor/jquery-1.11.2.min.js"></script>
    		<script src="tracery-master/tracery.js"></script>
    		<script src="tracery-master/js/grammars.js"></script>
            <script src='app.js'></script>
        </head>
        <body>
            <h1 id="h1">Weird Sentences</h1>
            <button id="generate" onclick="generate()">Give me a Sentence!</button>
            <div id="sentences">
    
            </div>
        </body>
    </html>

    And finally we will add some styles to it.

    最后,我们将为其添加一些样式。

    body {
        text-align: center;
        margin: 0;
        font-family: 'Harmattan', sans-serif;
    }
    
    #h1 {
        font-family: 'UnifrakturMaguntia', cursive;
        font-size: 4em;
        background-color: rgb(37, 146, 235);
        color: white;
        padding: .5em;
        box-shadow: 1px 1px 1px 1px rgb(206, 204, 204);
    }
    
    #generate {
        font-family: 'Harmattan', sans-serif;
        font-size: 2em;
        font-weight: bold;
        padding: .5em;
        margin: .5em;
        box-shadow: 1px 1px 1px 1px rgb(206, 204, 204);
        background-color: rgb(255, 0, 64);
        color: white;
        border: none;
        border-radius: 2px;
        outline: none;
    }
    
    #sentences p {
        box-shadow: 1px 1px 1px 1px rgb(206, 204, 204);
        margin: 2em;
        margin-left: 15em;
        margin-right: 15em;
        padding: 2em;
        border-radius: 2px;
        font-size: 1.5em;
    }

    We will also have to add some more JavaScript to manipulate the interface.

    我们还必须添加更多JavaScript来操纵接口。

    let sentences = []
    function generate() {
        var data = {
        	"start": ["#NP# #VP#."],
        	"NP": ["#Det# #N#", "#Det# #N# that #VP#", "#Det# #Adj# #N#"],
        	"VP": ["#Vtrans# #NP#", "#Vintr#"],
        	"Det": ["The", "This", "That"],
        	"N": ["John Keating", "Bob Harris", "Bruce Wayne", "John Constantine", "Tony Stark", "John Wick", "Sherlock Holmes", "King Leonidas"],
        	"Adj": ["cool", "lazy", "amazed", "sweet"],
        	"Vtrans": ["computes", "examines", "helps", "prefers", "sends", "plays with", "messes up with"],
        	"Vintr": ["coughs", "daydreams", "whines", "slobbers", "appears", "disappears", "exists", "cries", "laughs"]
        }
        
        let grammar = tracery.createGrammar(data);
        let expansion = grammar.flatten('#start#');
    
        sentences.push(expansion);
    
        printSentences(sentences);
    }
    
    function printSentences(sentences) {
        let textBox = document.getElementById("sentences");
        textBox.innerHTML = "";
        for(let i=sentences.length-1; i>=0; i--) {
            textBox.innerHTML += "<p>"+sentences[i]+"</p>"
        }
    }

    Once you have finished writing the code, run your HTML file. It should look something like this.

    完成编写代码后,运行HTML文件。 它看起来应该像这样。

    Every time you click the red button it will generate a sentence. Some of these sentences might not make any sense. This is because, as I said earlier, CFGs cannot describe the context and some other features that natural languages possess. It is used only to define the syntax and structure of the sentences.

    每次单击红色按钮,都会生成一个句子。 其中一些句子可能没有任何意义。 正如我前面所说,这是因为CFG无法描述自然语言所具有的上下文和其他某些功能。 它仅用于定义句子的语法和结构。

    You can check out the live version of this here.

    您可以在此处查看此版本的实时版本。

    结论 (Conclusion)

    If you have made it this far, I highly appreciate your resilience. It might be a new concept for some of you, and others might have learnt about it in their college courses. But still, Context Free Grammars have interesting applications that range widely from Computer Science to Linguistics.

    如果您能做到这一点,我非常感谢您的应变能力。 对于您中的某些人来说,这可能是一个新概念,而其他人可能已经在大学课程中学到了这一概念。 但是,上下文无关文法仍然具有有趣的应用,范围从计算机科学到语言学。

    I have tried my best to present the main ideas of CFGs here, but there is a lot more that you can learn about them. Here I have left links to some great resources:

    我已经尽力在这里介绍CFG的主要思想,但是您可以了解到更多的知识。 在这里,我留下了一些重要资源的链接:

    翻译自: https://www.freecodecamp.org/news/context-free-grammar/

    上下文无关文法和正则文法

    展开全文
  • 一、上下文无关文法 ( CFG )、 二、上下文无关文法 ( CFG ) 示例、 三、确定性有限自动机 DFA 转为 上下文无关语法 CFG



    参考博客 :





    一、上下文无关文法 ( CFG )



    上下文无关语法 组成 : {V,Σ,R,S}\{ \quad V , \Sigma , R , S \quad \} 四部分组成 ;

    变量集 VV : 有限的变量集合 ;

    终端字符集 Σ\Sigma : 有限的终端字符组成的集合 ; 相当于常量的含义 , 与变量相对 ;

    规则集 RR : 有限的规则组成的集合 , 规则规定如何进行代换操作 , 规定 变量 , 终端字符 , 字符串变量 等 ;

    开始变量 SS : 该变量作为开始变量 ;


    规则 :

    ① 已知条件 : 假设 u,v,wu, v , w变量 ( 变元 )终端字符集 ( 常量 / 常元 ) ;

    ② 规则描述 : 规则是一个箭头 , AwA \to w , AA 是变元 , ww 是 变元 和 常元 组成的终端字符 ;

    ③ 规则用法 : 在字符串中 , 根据 AwA \to w 规则进行替换 , 只需要将 AA 变元替换成 ww 字符串即可 ;

    ④ 规则示例 : uAvuAv 中使用上述规则进行替换 , 将 AA 替换成 ww , 替换结果是得到新字符串 uwvuwv ;

    uAvuwvuAv \Rightarrow uwv





    二、上下文无关文法 ( CFG ) 示例



    上下文无关文法 ( CFG ) : G3=(  {S},{a,b},R,S  )\rm G3 =( \; \{ S \}, \{ a, b \}, R , S \; ) 其组成如下 :

    • 变量集 {S}\rm \{ S \} ;

    • 终端字符集 {a,b}\rm \{ a, b \} ;

    • 规则 R\rm R ;

    • 开始变量 S\rm S ;


    规则 R\rm R 描述 : SaSb    SS    ε\rm S \to aSb \; | \; SS \; | \; \varepsilon

    • S\rm S 变量 可以使用 aSb\rm aSb 字符串替换 ;
    • S\rm S 变量 可以使用 SS\rm SS 字符串替换 ;
    • S\rm S 变量 可以使用 ε\rm \varepsilon 字符串替换 ;

    规则替换过程 : 下面的 ① ~ ⑦ 分别对应七次规则替换 ;

    SaSbaaSbbaaSSbbaaaSbSbbaaabSbbaaabaSbbbaaababbb\rm S \Rightarrow aSb \Rightarrow aaSbb \Rightarrow aaSSbb \Rightarrow aaaSbSbb \Rightarrow aaabSbb \Rightarrow aaabaSbbb \Rightarrow aaababbb

    • SS\rm S S 是开始变量 , 可以使用 aSb\rm aSb 替换 S\rm S ; SaSb\rm S \Rightarrow aSb
    • ② 使用 aSb\rm aSb 替换 S\rm S ; aSbaaSbb\rm aSb \Rightarrow aaSbb
    • ③ 使用 SS\rm SS 替换 S\rm S ; aaSbbaaSSbb\rm aaSbb \Rightarrow aaSSbb
    • ④ 使用 aSb\rm aSb 替换第一个 S\rm S ; aaSSbbaaaSbSbb\rm aaSSbb \Rightarrow aaaSbSbb
    • ⑤ 使用 ε\rm \varepsilon 替换第一个 S\rm S ; aaaSbSbbaaabSbb\rm aaaSbSbb \Rightarrow aaabSbb
    • ⑥ 使用 aSb\rm aSb 替换 S\rm S ; aaabSbbaaabaSbbb\rm aaabSbb \Rightarrow aaabaSbbb
    • ⑦ 使用 ε\rm \varepsilon 替换 S\rm S ; aaabaSbbbaaababbb\rm aaabaSbbb \Rightarrow aaababbb




    三、确定性有限自动机 DFA 转为 上下文无关语法 CFG



    1 . 确定性有限自动机 ( DFA ) 转为 上下文无关语法 ( CFG ) :

    确定性有限自动机 ( DFA ) 的指令 , 转为 对应的

    上下文无关语法 ( CFG ) 规则 : δ(qi,a)=qjRiaRj\rm \delta ( q_i, a ) = q_j \Rightarrow R_i \to aR_j

    δ(qi,a)=qj\delta ( q_i, a ) = q_j 表示 qiq_i 状态下 , 读取字符 aa , 跳转到 qjq_j 状态 ;


    2 . 自动机的 状态跳转 转换成 规则 示例 : 下图中的 确定性有限自动机 , 开始状态 AA 读取 11 字符 转化成 BB 状态 , 表示成规则就是 RA1RBR_A \to 1R_B

    在这里插入图片描述


    3 . 自动机的状态 AA 读取 字符 aa 转换成另一个状态 BB , 都可以转换成对应的规则 RAaRBR_A \to aR_B ;


    4 . 计算能力对比 : 上下文无关语法 的计算能力 要大于等于 自动机的计算能力 ;

    展开全文
  • 计算理论-上下文无关文法 计算理论-上下文无关文法 计算理论-上下文无关文法
  • 上下文无关文法 上下文无关文法 G 是一个四元组 G = (VN , VT , S, £), 其中 VN :非终结符的非空有限集合 VT :终结符的非空有限集合, VN ∩ VT = Φ S: 开始符号,且S∈ VN £ :形式为 P→α的产生式...
  • I . 上下文无关语法 设计 示例 II . 上下文无关语法 的歧义性 III . Chomsky 范式 IV . 上下文无关语法 转为 Chomsky 范式 V . 上下文无关语法 转为 Chomsky 范式 示例
  • I . 代数表达式 语法 II . 代数表达式 语法 示例 III . 设计 上下文无关语法 IV . 确定性有限自动机 DFA 转为 上下文无关语法
  • 编译原理-词法分析-上下文无关文法

    千次阅读 2019-11-29 15:11:08
    上下文无关文法 前言 正规式来定义一些简单的语言,能表示给定结构的固定次数的重复或者没有指定次数的重复, 但 正规式不能用于描述配对或嵌套的结构 定义 上下文无关文法是四元组( VT,VN,S,PV_T,V_N,S,PV...
  • 程序使用的语法上下文无关文法,是乔姆斯基分类法则中的第2类语法。 0 1 2 3 文法名称 非限制型文法 上下文有关文法 上下文无关文法 正则文法 对应机器 图灵机 线性(边界)...
  • snl上下文无关文法

    2011-04-07 10:58:24
    包含了 snl语言的上下文无关文法 总共104条
  • 上下文无关文法与藏语句法分析

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 32,638
精华内容 13,055
关键字:

上下文无关文法