【发布时间】:2016-08-07 20:42:06
【问题描述】:
我正在创建一个词法分析器/解析器,它应该接受属于无限语言集的字符串。
一个这样的字符串是"a <2L>AA <2U>a <2L>AA <2U>a</2U></2L></2U></2L>"。
语言集定义如下:
基础语言,L0
- 来自 L0 的字符串由几个由空格字符分隔的块组成。 必须至少存在一个块。
- 块是奇数长度的小写字母 (a-z) 序列。
- 第一个块之前或最后一个块之后不允许有空格。
- 块之间的空格数必须是奇数。
属于L0的字符串示例:
zyx abcba m xyzvv
zyx和abcba之间有1个空格字符,有3个空格
在abcba 和m 之间,并且在m 和xyzvv 之间只有一个。字符串中没有其他空格字符。
语言 L1
- 来自 L1 的字符串由几个由空格字符分隔的块组成。 必须至少存在一个块。
- 有两种块。第一类块必须是
大写字母 (A-Z) 的偶数长度序列。一块
第二种必须有
<2U>. . .</2U>的形状,. . .代表 对于 L0 中的任何字符串。 - 第一个块之前或最后一个块之后不允许有空格。
- 块之间的空格数必须是奇数。
属于L1的字符串示例:
YZ <2U>abc zzz</2U> ABBA <2U>kkkkk</2U> KM
请注意,YZ 和 <2U>abc zzz</2U> 有五个空格分开,abc 和 zzz 分开三个空格。否则使用单个空格作为分隔符。 YZ 前面没有空格,KM 后面也没有空格。
语言 L2
- 来自 L2 的字符串由多个由空格字符分隔的块组成。 必须至少存在一个块。
- 有两种块。第一类块必须是
一个奇数长度的小写字母序列 (a-z)。一块
第二种必须具有
<2L>. . .</2L>的形状,其中. . .代表 对于 L1 中的任何字符串。 - 第一个块之前或最后一个块之后不允许有空格。
- 块之间的空格数必须是奇数。
属于L2的字符串示例:
abc <2L>AA ZZ <2U>a bcd</2U></2L> z <2L><2U>abcde</2U></2L>
在上面给出的句子中使用单个空格作为分隔符,但任何其他奇数个空格也会导致有效的 L2 句子。
语言 L{2k + 1}, k > 0
- 来自 L{2k + 1} 的字符串由多个由空格字符分隔的块组成。必须至少存在一个块。
- 有两种块。第一类块必须是
大写字母 (A-Z) 的偶数长度序列。一块
第二种必须有
<2U>. . .</2U>的形状,. . .代表 对于来自 L{2k} 的任何字符串。 - 第一个块之前或最后一个块之后不允许有空格。
- 块之间的空格数必须是奇数。
语言 L{2k + 2}, k > 0
- 来自 L{2k + 2} 的字符串由几个用空格分隔的块组成 人物。必须至少存在一个块。
- 有两种块。第一类块必须是
一个奇数长度的小写字母序列 (a-z)。一块
第二种必须有
<2L>. . .</2L>的形状,. . .代表 对于来自 L{2k + 1} 的任何字符串。 - 第一个块之前或最后一个块之后不允许有空格。
- 块之间的空格数必须是奇数。
我的词法分析器/解析器的代码如下:
PARSER_BEGIN(Assignment)
/** A parser which determines if user's input belongs to any one of the set of acceptable languages. */
public class Assignment {
public static void main(String[] args) {
try {
Assignment parser = new Assignment(System.in);
parser.Start();
System.out.println("YES"); // If the user's input belongs to any of the set of acceptable languages, then print YES.
} catch (ParseException e) {
System.out.println("NO"); // If the user's input does not belong to any of the set of acceptable languages, then print NO.
}
}
}
PARSER_END(Assignment)
//** A token which matches any lowercase letter from the English alphabet. */
TOKEN :
{
< #L_CASE_LETTER: ["a"-"z"] >
}
//* A token which matches any uppercase letter from the English alphabet. */
TOKEN:
{
< #U_CASE_LETTER: ["A"-"Z"] >
}
//** A token which matches an odd number of lowercase letters from the English alphabet. */
TOKEN:
{
< ODD_L_CASE_LETTER: <L_CASE_LETTER>(<L_CASE_LETTER><L_CASE_LETTER>)* >
}
//** A token which matches an even number of uppercase letters from the English alphabet. */
TOKEN:
{
< EVEN_U_CASE_LETTERS: (<U_CASE_LETTER><U_CASE_LETTER>)+ >
}
//* A token which matches the string "<2U>" . */
TOKEN:
{
< OPEN_UPPER: "<2U>" >
}
//* A token which matches the string "</2U>". */
TOKEN:
{
< CLOSE_UPPER: "</2U>" >
}
//* A token which matches the string "<2L>". */
TOKEN:
{
< OPEN_LOWER: "<2L>" >
}
//* A token which matches the string "</2L>". */
TOKEN:
{
< CLOSE_LOWER: "</2L>" >
}
//* A token which matches an odd number of white spaces. */
TOKEN :
{
< ODD_WHITE_SPACE: " "(" "" ")* >
}
//* A token which matches an EOL character. */
TOKEN:
{
< EOL: "\n" | "\r" | "\r\n" >
}
/** This production matches strings which belong to the base language L^0. */
void Start() :
{}
{
LOOKAHEAD(3)
<ODD_L_CASE_LETTER> (<ODD_WHITE_SPACE> <ODD_L_CASE_LETTER>)* <EOL> <EOF>
|
NextLanguage()
|
LOOKAHEAD(3)
NextLanguageTwo()
|
EvenLanguage()
}
/** This production matches strings which belong to language L^1. */
void NextLanguage():
{}
{
(<OPEN_UPPER> (PseudoStart()) <CLOSE_UPPER>)+ (<ODD_WHITE_SPACE> UpperOrPseudoStart())* <EOL> <EOF>
|
(<EVEN_U_CASE_LETTERS>)+ (<ODD_WHITE_SPACE> UpperOrPseudoStart())* <EOL> <EOF>
}
/** This production matches either an even number of uppercase letters, or a string from L^0, encased within the tags <2U> and </2U>. */
void UpperOrPseudoStart() :
{}
{
<EVEN_U_CASE_LETTERS>
|
<OPEN_UPPER> (PseudoStart()) <CLOSE_UPPER>
}
/** This production matches strings from L^0, in a similar way to Start(); however, the strings that it matches do not have EOL or EOF characters after them. */
void PseudoStart() :
{}
{
<ODD_L_CASE_LETTER> (<ODD_WHITE_SPACE> <ODD_L_CASE_LETTER>)*
}
/** This production matches strings which belong to language L^2. */
void NextLanguageTwo() :
{}
{
(<ODD_L_CASE_LETTER>)+ (<ODD_WHITE_SPACE> LowerOrPseudoNextLanguage())* <EOL> <EOF>
|
(<OPEN_LOWER> PseudoNextLanguage() <CLOSE_LOWER>)+ (<ODD_WHITE_SPACE> LowerOrPseudoNextLanguage())* <EOL> <EOF>
}
/** This production matches either an odd number of lowercase letters, or a string from L^1, encased within the tags <2L> and </2L>. */
void LowerOrPseudoNextLanguage() :
{}
{
<ODD_L_CASE_LETTER>
|
<OPEN_LOWER> PseudoNextLanguage() <CLOSE_LOWER>
}
/** This production matches strings from L^1, in a similar way to NextLanguage(); however, the strings that it matches do not have EOL or EOF characters after them. */
void PseudoNextLanguage() :
{}
{
(<OPEN_UPPER> (PseudoStart()) <CLOSE_UPPER>)+ (<ODD_WHITE_SPACE> UpperOrPseudoStart())*
|
(<EVEN_U_CASE_LETTERS>)+ (<ODD_WHITE_SPACE> UpperOrPseudoStart())*
}
/** This production matches strings which belong to any of the languages L^{2k + 2}, where k > 0 (the infinite set of even languages). */
void EvenLanguage() :
{}
{
(<ODD_L_CASE_LETTER>)+ (<ODD_WHITE_SPACE> EvenLanguageAuxiliary())* <EOL> <EOF>
|
(CommonPattern())+ (<ODD_WHITE_SPACE> EvenLanguageAuxiliary())* <EOL> <EOF>
}
/** This production is an auxiliary production that helps when parsing strings from any of the even set of languages. */
void EvenLanguageAuxiliary() :
{}
{
CommonPattern()
|
<ODD_L_CASE_LETTER>
}
void CommonPattern() :
{}
{
<OPEN_LOWER> <EVEN_U_CASE_LETTERS> <ODD_WHITE_SPACE> <OPEN_UPPER> <ODD_L_CASE_LETTER> (<ODD_WHITE_SPACE> CommonPattern())+ <CLOSE_UPPER> <CLOSE_LOWER>
}
现在有好几次,我都输入了字符串"a <2L>AA <2U>a <2L>AA <2U>a</2U></2L></2U></2L>"。
但是,每次都会在终端上打印出NO。
我仔细查看了我的代码几次,检查了我认为应该解析输入字符串的顺序;但是,我无法在我的逻辑中找到任何错误或字符串未被接受的原因。
请给我一些关于为什么它不被接受的建议吗?
【问题讨论】:
-
如果您不准备描述该语言,至少要为其提供语法,那么很难看到任何人可以帮助您。
-
@EJP:对不起。没想到会造成这么大的困难。我会马上修改我的问题。
-
您尝试过 JavaCC 的任何调试选项吗?我建议你这样做,看看你的期望和现实在哪里分歧。
-
解析这种语言的动机是什么?这只是一个毫无意义的家庭作业还是有一个应用程序?
-
@TheodoreNorvell 这是一个有意义的家庭作业。
标签: parsing compiler-construction lexer javacc