我正在尝试编写一个无上下文语法来做一些非常简单的事情 - 将字符串解析为(1)行尾空白和(2)其他所有内容的交替部分列表。例如:
This.first.line...\n..and.this....second.line\n.\n..and.final.line
(将" "
显示为"."
,将新行显示为"\n"
以提高可读性)将被解析为
"This.first.line", "...\n..", "and.this....second.line", "\n.\n..", "and.final.line"
我写了这个语法:
string = raw_start | newline_start
raw_start = raw_section [newline_start]
newline_start = newline_section [raw_start]
raw_section = {any_character_except_newline}
newline_section = {whitespace_except_newline} new_line {any_whitespace_character}
但这不正确,因为{any_character_except_newline}
会消耗导致换行符的空格,当我想要new_line_section
中包含的空格时。{/ p>
是否有可能说"消费空间,除非它们在换行前是正确的"不会失去语法的无上下文属性?
答案 0 :(得分:3)
当然,没有上下文不是问题。两个"行尾空白"和其他一切"是常规语言。
作为参考,这里是正则表达式(正式常规,而不是"可以通过一些' regex'包"识别)。我们假设 A
是字母表,并定义:
NOTSPACE = { ∀x | x ∈ A ∧ x ≠ NL ∧ x ≠ SPACE }
NOTEOL = { ∀x | x ∈ A ∧ x ≠ NL }
EVERYTHING_ELSE = { xωy | x,y ∈ NOTSPACE ∧ ω ∈ NOTEOL* } ⋃ NOTSPACE
EOL_WHITESPACE = { ωNLγ | ω,γ ∈ {SPACE, NL}* }
这很容易转化为CFG。 (文本可能以空格结尾,但不包含换行符。以下忽略了这种可能性,但可以轻松添加):
S → Spaces
S → S Other
S → S EOL_WS
Spaces → ε
Spaces → Spaces [ ]
Other → [^ \n] Line [^ \n]
Other → [^ \n]
Line → ε
Line → Line [^\n]
EOL_WS → Spaces NL_Spaces
NL_Spaces → NL_Space
NL_Spaces → NL_Spaces NL_Space
NL_Space → [/n] Spaces
如上所述,上述内容含糊不清,因为它并不坚持Other
和EOL_WS
最长。这很容易修复但很乏味,而且由于OP只要求CFG而不是明确的或LR(1)CFG,我会留下它。
答案 1 :(得分:0)
这是我在我的问题中使用的EBNF格式的完美答案的翻译:
string = raw_start | newline_start
raw_start = raw_section [newline_start]
newline_start = newline_section [raw_start]
raw_section = any_nonwhite_character [{any_character_except_newline} any_nonwhite_character]
newline_section = {whitespace_except_newline} new_line {any_whitespace_character}
关键是改变raw_section
的定义,要求它以非白色字符结尾。这个简单的语法不会匹配以空格结尾的空字符串或字符串,但这很容易修复。