Parsing 数据文件的Lexer/Parser设计

Parsing 数据文件的Lexer/Parser设计,parsing,lexical-analysis,Parsing,Lexical Analysis,我正在写一个小程序,它需要预处理一些数据文件,这些文件是另一个程序的输入。由于这个原因,我无法更改输入文件的格式,我遇到了一个问题 我在一种没有用于这类事情的库的语言中工作,我不介意这个练习,所以我计划手工实现lexer和parser。我想实现一个Lexer,它基本上是一个相当简单的设计 我需要解释的输入文件有一个包含化学反应的部分。反应两侧的不同化学物质以“+”符号分开,但物质名称中也可以有+字符(表示电荷)。例如: N2+O2=>NO+NO N2++O2-=>NO+NO N2+

我正在写一个小程序,它需要预处理一些数据文件,这些文件是另一个程序的输入。由于这个原因,我无法更改输入文件的格式,我遇到了一个问题

我在一种没有用于这类事情的库的语言中工作,我不介意这个练习,所以我计划手工实现lexer和parser。我想实现一个Lexer,它基本上是一个相当简单的设计

我需要解释的输入文件有一个包含化学反应的部分。反应两侧的不同化学物质以“+”符号分开,但物质名称中也可以有+字符(表示电荷)。例如:

N2+O2=>NO+NO
N2++O2-=>NO+NO
N2+ + O2 => NO + NO
都是有效的,lexer输出的令牌应该是

'N2' '+' 'O2' '=>' 'NO' '+' 'NO'
'N2+' '+' 'O2-' '=>' 'NO' '+' 'NO'
'N2+' '+' 'O2-' '=>' 'NO' '+' 'NO'
(请注意,最后两个是相同的)。为了简单起见,我希望避免在lexer中进行前瞻。问题是lexer将开始读取上述任何输入,但当它到达第三个字符(第一个“+”)时,它将无法知道它是物种名称的一部分还是反应物之间的分隔符

为了解决这个问题,我想我应该将其拆分,这样上面的第二个和第三个示例将输出:

'N2' '+' '+' 'O2-' '=>' 'NO' '+' 'NO'
然后,解析器将简单地使用上下文,认识到一行中的两个“+”标记意味着第一个是前一个物种名称的一部分,并将正确处理上述三种情况。问题是,现在想象一下我尝试lex/parse

N2 + + O2- => NO + NO
(注意“N2”和第一个“+”之间的空格)。这是无效的语法,但是我刚才描述的lexer将输出与第二个和第三个示例完全相同的令牌输出,并且我的解析器将无法捕获错误

我认为可能的解决方案如下:

  • 实现至少具有一个字符前瞻性的lexer
  • 包含空白的标记
  • 在“+”标记中包含前导空格
  • 创建一个“组合”标记,该标记包含物种名称和任何尾随的“+”,中间没有空格,然后让解析器排序“+”是否实际上是名称的一部分

由于我对这种编程非常陌生,我希望有人能对我提出的解决方案发表评论(或提出其他建议)。我对第一种解决方案的主要保留意见是,我不知道使用前瞻性实现lexer要复杂多少。

您没有提到您的实现语言,但输入语法与您概述的一样简单,我不认为按照以下伪代码的思路进行逻辑是不合理的

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;
}

所以这本质上是前瞻的一个特征?我在Matlab中工作(由于项目的其他要求,这也是为什么目前没有任何完善的库),所以我甚至实现了一个非常轻的字符流类。我想给下一个角色加上一个“窥视”是相当直截了当的。你可能可以根据需要暂时前进和后退输入缓冲区指针,但是如果你这样做的话,请注意空格。是的,我必须注意细节,但是我读得越多,我认为拥有这个功能就越有用。