0

最近,我一直在尝试在 jQuery 和 JavaScript 中模拟一种小型语言,但我遇到了我认为是一个问题。我认为我可能完全错误地解析了所有内容。
在代码中:

@name Testing
@inputs
@outputs
@persist 
@trigger 
print("Test")

我目前分离和解析字符串的方法是将所有代码拆分为行,然后使用搜索和拆分读取此行数组。例如,我会使用以下内容找到名称:

if(typeof lines[line] === 'undefined')
{
}
else
{
    if(lines[line].search('@name') == 0)
    {
        name = lines[line].split(' ')[1];
    }
}

但我认为我在处理解析的方式上可能大错特错。
在阅读有关其他人如何处理这样的代码块解析的示例时,似乎人们解析了整个块,而不是像我那样将其分成几行。我想问题是,解析这样的事情的正确和传统方式是什么,你建议我如何使用它来解析这样的事情?

4

2 回答 2

0

在这样的简单情况下正则表达式是您选择的工具:

matches = code.match(/@name\s+(\w+)/)
name = matches[1]

要解析“真正的”编程语言,正则表达式不够强大,您需要一个解析器,可以是手写的,也可以使用PEG等工具自动生成。

于 2013-07-13T21:31:28.897 回答
0

我喜欢经常采用的一般解析方法如下:

  1. 逐个字符循环遍历整个文本块。
  2. 如果你发现一个字符表示一个单元的开始,调用一个专门的子函数来解析下一个字符。
  3. 在每个子函数中,如果您发现某些字符,则调用其他子函数
  4. 当找到一个字符时从每个子函数返回,这表明该单元已经结束。

这是一个小例子:

var text = "@func(arg1,arg2)"

function parse(text) {
    var i, max_i, ch, funcRes;

    for (i = 0, max_i = text.length; i < max_i; i++) {
        ch = text.charAt(i);

        if (ch === "@") {
            funcRes = parseFunction(text, i + 1);
            i = funcRes.index;
        }
    }
    console.log(funcRes);
}

function parseFunction(text, i) {
    var max_i, ch, name, argsRes;

    name = [];    
    for (max_i = text.length; i < max_i; i++) {
        ch = text.charAt(i);

        if (ch === "(") {
            argsRes = parseArguments(text, i + 1);
            return {
                name: name.join(""),
                args: argsRes.arr,
                index: argsRes.index
            };
        } 
        name.push(ch);
    }
}

function parseArguments(text, i) {
    var max_i, ch, args, arg;

    arg = [];
    args = [];
    for (max_i = text.length; i < max_i; i++) {
        ch = text.charAt(i);

        if (ch === ",") {
            args.push(arg.join(""));
            arg = [];
            continue;
        } else if (ch === ")") {
            args.push(arg.join(""));
            return {
                arr: args,
                index: i
            };
        }
        arg.push(ch);
    }
}

小提琴

这个例子只是解析函数表达式,它遵循语法“@functionName(argumentName1, argumentName2, ...)”。一般的想法是只访问每个字符一次,而无需保存当前状态,如“hasSeenAtCharacter”或“hasSeenOpeningParentheses”,当您解析大型结构时,它们会变得非常混乱。

请注意,这是一个非常简化的示例,它遗漏了所有错误处理和类似的东西,但我希望可以看到总体思路。另请注意,我并不是说您应该一直使用这种方法。这是一种非常通用的方法,可以在许多场景中使用。但这并不意味着它不能与正则表达式结合使用,例如,如果它在文本的某些部分比解析每个单独的字符更有意义。

最后一点:如果你把专门的解析函数放在主解析函数中,你可以省去麻烦,这样所有函数都可以访问同一个变量i

于 2013-07-13T22:09:52.213 回答