Lexer/Parser 数据文件设计
Lexer/Parser design for data file
我正在编写一个小程序,它需要预处理一些输入到另一个程序的数据文件。因此,我无法更改输入文件的格式,我 运行 遇到了问题。
我正在使用一种没有此类库的语言工作,我不介意这个练习,所以我计划手动实现词法分析器和解析器。我想实现一个大致基于 this 的 Lexer,这是一个相当简单的设计。
我需要解释的输入文件有一个包含化学反应的部分。反应每一侧的不同化学物种由“+”号分隔,但物种的名称也可以包含 + 字符(表示电荷)。例如:
N2+O2=>NO+NO
N2++O2-=>NO+NO
N2+ + O2 => NO + NO
都是有效的,词法分析器输出的标记应该是
'N2' '+' 'O2' '=>' 'NO' '+' 'NO'
'N2+' '+' 'O2-' '=>' 'NO' '+' 'NO'
'N2+' '+' 'O2-' '=>' 'NO' '+' 'NO'
(注意最后两个是一样的)。为了简单起见,我想避免在词法分析器中向前看。问题是词法分析器会开始读取上述任何输入,但是当它到达第 3 个字符(第一个“+”)时,它无法知道它是否是物种名称的一部分或者如果它是反应物之间的分隔符。
为了解决这个问题,我想我会把它分开,所以上面的第二个和第三个例子会输出:
'N2' '+' '+' 'O2-' '=>' 'NO' '+' 'NO'
然后解析器将简单地使用上下文,意识到连续的两个“+”标记意味着第一个是先前物种名称的一部分,并且将正确处理上述所有三种情况。这个问题是现在想象我尝试 lex/parse
N2 + + O2- => NO + NO
(注意 'N2' 和第一个“+”之间的 space)。这是无效的语法,但是我刚刚描述的词法分析器会输出与第二个和第三个示例完全相同的标记输出,而我的解析器将无法捕获错误。
我认为可能的解决方案:
- 实现一个至少有一个字符向前看的词法分析器
- 包括白色标记space
- 在“+”标记中包含前导白色 space
- 创建一个 "combined" 标记,其中包括物种名称和任何尾随的 '+' 之间没有白色 space,然后让解析器判断 '+' 是否实际上是物种名称的一部分名字与否。
由于我对这种编程很陌生,所以我希望有人可以对我提出的解决方案发表评论(或提出其他建议)。我对第一个解决方案的主要保留意见是我根本不知道实现具有前瞻性的词法分析器有多复杂。
您没有提到您的实现语言,但是输入语法与您概述的语法一样相对简单,我认为按照以下 pseudo-code 的逻辑行事不会不合理。
string GetToken()
{
string token = GetAlphaNumeric(); // assumed to ignore (eat) white-space
var ch = GetChar(); // assumed to ignore (eat) white-space
if (ch == '+')
{
var ch2 = GetChar();
if (ch2 == '+')
token += '+';
else
PutChar(ch2);
}
PutChar(ch);
return token;
}
我正在编写一个小程序,它需要预处理一些输入到另一个程序的数据文件。因此,我无法更改输入文件的格式,我 运行 遇到了问题。
我正在使用一种没有此类库的语言工作,我不介意这个练习,所以我计划手动实现词法分析器和解析器。我想实现一个大致基于 this 的 Lexer,这是一个相当简单的设计。
我需要解释的输入文件有一个包含化学反应的部分。反应每一侧的不同化学物种由“+”号分隔,但物种的名称也可以包含 + 字符(表示电荷)。例如:
N2+O2=>NO+NO
N2++O2-=>NO+NO
N2+ + O2 => NO + NO
都是有效的,词法分析器输出的标记应该是
'N2' '+' 'O2' '=>' 'NO' '+' 'NO'
'N2+' '+' 'O2-' '=>' 'NO' '+' 'NO'
'N2+' '+' 'O2-' '=>' 'NO' '+' 'NO'
(注意最后两个是一样的)。为了简单起见,我想避免在词法分析器中向前看。问题是词法分析器会开始读取上述任何输入,但是当它到达第 3 个字符(第一个“+”)时,它无法知道它是否是物种名称的一部分或者如果它是反应物之间的分隔符。
为了解决这个问题,我想我会把它分开,所以上面的第二个和第三个例子会输出:
'N2' '+' '+' 'O2-' '=>' 'NO' '+' 'NO'
然后解析器将简单地使用上下文,意识到连续的两个“+”标记意味着第一个是先前物种名称的一部分,并且将正确处理上述所有三种情况。这个问题是现在想象我尝试 lex/parse
N2 + + O2- => NO + NO
(注意 'N2' 和第一个“+”之间的 space)。这是无效的语法,但是我刚刚描述的词法分析器会输出与第二个和第三个示例完全相同的标记输出,而我的解析器将无法捕获错误。
我认为可能的解决方案:
- 实现一个至少有一个字符向前看的词法分析器
- 包括白色标记space
- 在“+”标记中包含前导白色 space
- 创建一个 "combined" 标记,其中包括物种名称和任何尾随的 '+' 之间没有白色 space,然后让解析器判断 '+' 是否实际上是物种名称的一部分名字与否。
由于我对这种编程很陌生,所以我希望有人可以对我提出的解决方案发表评论(或提出其他建议)。我对第一个解决方案的主要保留意见是我根本不知道实现具有前瞻性的词法分析器有多复杂。
您没有提到您的实现语言,但是输入语法与您概述的语法一样相对简单,我认为按照以下 pseudo-code 的逻辑行事不会不合理。
string GetToken()
{
string token = GetAlphaNumeric(); // assumed to ignore (eat) white-space
var ch = GetChar(); // assumed to ignore (eat) white-space
if (ch == '+')
{
var ch2 = GetChar();
if (ch2 == '+')
token += '+';
else
PutChar(ch2);
}
PutChar(ch);
return token;
}