algorithm - 在 C# 中解析脚本循环

标签 algorithm c#-3.0 text-parsing

我正在编写一个应用程序,它将使用自定义语言(略微基于 C 语法和 Allman style 格式)解析脚本,并且正在寻找更好(阅读:更快)的方式将脚本代码块解析为字符串数组,而不是我目前正在执行的方式(当前方法可以,但它更多的是为了调试而不是其他任何方式)。

脚本内容当前从文件中读取到字符串数组中并传递给方法。

这是一个脚本 block 模板:

loop [/* some conditional */ ]
{
  /* a whole bunch of commands that are to be read into
   * a List<string>, then converted to a string[] and
   * passed to the next step for execution */

   /* some command that has a bracket delimited set of
    * properties or attributes */
   {
     /* some more commands to be acted on */
   }
}

基本上,花括号 block 可以嵌套(就像在任何其他基于 C 的语言中一样),我正在寻找找到像这样的单个 block 的最佳方法。

大括号分隔的 block 将始终格式化为这样 - 括号的内容将从左括号后的行开始,并在最终属性后的行上跟一个括号/command/comment/whatever.

一个例子可能是:

loop [ someVar <= 10 ]
{
  informUser "Get ready to do something"
  readValue
  {
    valueToLookFor = 0x54
    timeout = 10 /* in seconds */
  }
}

这会告诉应用程序在 someVar 小于 10 时循环(对于吮吸鸡蛋的评论感到抱歉)。每一轮,我们都会向用户传递一条消息,并从某处查找特定值(超时为 10 秒)。

这是我目前的做法(注意:调用此方法的方法将包含当前脚本的整个字符串 [] 传递到其中,并带有要读取的索引):

private string[] findEntireBlock(string[] scriptContents, int indexToReadFrom,
                                out int newIndex)
{
    newIndex = 0;
    int openBraceCount = 0;     // for '{' char count
    int closeBraceCount = 0;    // for '}' char count
    int openSquareCount = 0;    // for '[' char count
    int closeSquareCount = 0;   // for ']' char count

    List<string> fullblock = new List<string>();

    for (int i = indexToReadFrom; i < scriptContents.Length; i++)
    {
        if (scriptContents[i].Contains('}'))
        {
            if (scriptContents[i].Contains("[") && fullblock.Count > 0)
            {
                //throw new exception, as we shouldn't expect to
                //to find a line which starts with [ when we've already
            }
            else
            {
                if (scriptContents[i].Contains('{')) openBraceCount++;
                if (scriptContents[i].Contains('}')) closeBraceCount++;
                if (scriptContents[i].Contains('[')) openSquareCount++;
                if (scriptContents[i].Contains(']')) closeBraceCount++;
                newIndex = i;
                fullblock.Add(scriptContents[i]);
                break;
            }
        }
        else
        {
            if (scriptContents[i].Contains("[") && fullblock.Count > 0)
            {
                //throw new exception, as we shouldn't expect to
                //to find a line which starts with [ when we've already
            }
            else
            {
                if (scriptContents[i].Contains('{')) openBraceCount++;
                if (scriptContents[i].Contains('}')) closeBraceCount++;
                if (scriptContents[i].Contains('[')) openSquareCount++;
                if (scriptContents[i].Contains(']')) closeBraceCount++;
                fullblock.Add(scriptContents[i]);
            }
        }
    }
    if (openBraceCount == closeBraceCount &&
        openSquareCount == closeSquareCount)
          return fullblock.ToArray();
    else
        //throw new exception, the number of open brackets doesn't match
        //the number of close brackets
}

我同意这可能是一种稍微迟钝和缓慢的方法,这就是为什么我要就如何重新实现它以提高速度和清晰度(如果可以达到平衡,那就是)寻求任何想法。

我希望远离 RegEx,因为我不能用它来维护括号计数,而且我不确定您是否可以编写一个 RegEx 语句(这是正确的术语吗?)递归地。我正在考虑从内到外的工作,但我相信那会很慢。

不是找人帮我重写它,但我可以使用的关于算法或技术/库的一般想法会改进我的方法。

作为附带问题,编译器如何处理源代码中的多个嵌套括号?

最佳答案

Let's Build a Compiler由 Jack Crenshaw 撰写,是关于构建基本编译器的精彩且易于阅读的介绍。所讨论的技术应该有助于您在此处尝试执行的操作。

关于algorithm - 在 C# 中解析脚本循环,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15521074/

相关文章:

c++ - 在排序和旋转的数组中搜索

algorithm - 朴素的 LFSR,将编程语言翻译成数学

python - 如何在 Python 中找到两个单词之间的最短依赖路径?

C# 依赖注入(inject)

c# - 为什么 C# 中匿名类型的属性是只读的?

Python 优化 : Parsing a text file to store default values and create key-pair dictionary in python

算法中的 C# 性能波动

java - 算法中超过时间限制错误

c# - c#中的双引号不允许多行

c#-3.0 - 如何使用Linq将List <string>转换为XML?