如何在一段代码中识别变量名称

时间:2014-08-19 13:01:14

标签: regex axapta x++

我试图在X ++中编写一个halstead复杂性度量(语言并不重要),我认为最好的方法是在源代码上使用正则表达式。

我已经成功完成了90%但我在变量名称上苦苦挣扎。

如何在一段代码中识别变量名称。

给出以下代码

public void main()
{
    int a, b, c, av;
    className class;
    strFmt("%1 %2 %3", a, b, c);
    av = (a + b + c) / 3;
    info("avg = %1");*/

    if(a)
    {
        a++;
        class.add(a);
    }
    else
    {
        b++;
        class.subtract(b)
    }

    this.main();
}

我希望得到“a”“b”“c”“av”“class”

对于halstead,它需要计算它们的实例。我想的方法是将上面的内容存储在一个列表中,然后在正则表达式查询中使用列表中的任何内容。迎合变量的所有可能用途将是疯狂的。

6 个答案:

答案 0 :(得分:2)

我认为你必须反思AOT以获得不同的变量。

您可以使用TreeNode的反射,或者您可以使用XPPC编译器获取有关您正在处理的对象的信息以提供帮助:

info(strFmt("%1", new xppCompiler().dumpClass('salesformletter')));

答案 1 :(得分:2)

这个问题让我有点好奇如何做到这一点,我发现这篇很棒的文章有一个自定义的AX工具来测量复杂性以及一篇175页的毕业论文。

http://bojanjovicic.com/complexity-tool-dynamics-ax-2009/

我现在正在试验它,看看我是如何构建它的。

答案 2 :(得分:2)

我回复了实际答案!使用SysScannerClassTreeNode对象正确解析代码。这是我写的一个漂亮的样本,应该让它成为蛋糕。

static void JobParseSourceCode(Args _args)
{
    TreeNode        treeNode = TreeNode::findNode(@'\Data Dictionary\Tables\SalesTable\Methods\find');
    SysScannerClass sysScannerClass = new SysScannerClass(treeNode);
    int             symbol;
    int             curLine;
    str             lineStr;  

    setPrefix("Scanning " + treeNode.treeNodePath());
    for (symbol = sysScannerClass.firstSymbol(); symbol; symbol = sysScannerClass.nextSymbol())
    {
        if (curLine != sysScannerClass.line())
        {
            curLine = sysScannerClass.line();
            lineStr = sysScannerClass.sourceLine(curLine);
        }

        // NOTE: symbol corresponds to macros in #TokenTypes
        info(strFmt("Line %1: %2\t(Col %3): '%4' - MacroValue: %5, [%6]", curLine, lineStr, sysScannerClass.col(), sysScannerClass.strValue(), symbol, xppScanner::symbolClass(symbol)));
    }
}

答案 3 :(得分:1)

嗯,这个例子并不完全符合X ++的要求,因为class是一个保留字,不能用于变量名。

除此之外,对[a-zA-Z_][a-zA-Z_0-9]+的粗略搜索会为您提供可能变量名称的所有字符串。但如果没有完整的解析器,您将难以确定它是关键字,类名,表名等等还是真正的变量名。

您也可以TextBuffer使用tokenize your source

static void TokenTest(Args _args)
{
    str src = @'
        public void main()
        {
            int a = 7, b = 11, c = 13, av;
            info(strFmt("%1 %2 %3", a, b, c));
            av = (a + b + c) / 3;
            info(strFmt("avg = %1"));
            this.main();
        }    
    ';
    TextBuffer t = new TextBuffer();
    t.ignoreCase(true);
    t.setText(src); // Set the text to break in to tokens
    while (t.nextToken(false,' (){}.,:;!=+-*/\n')) // The delimiters to search 
    {
        info(t.token());
    }
}

当然,这不适用于字符串和注释。

甚至还有一个未记录的Keywords内核类可供使用!

也许最好的选择是与cross reference tool集成,它已经为你做了分裂!

我担心剩下的10%可能占用你90%的时间!

答案 4 :(得分:0)

您可以使用regex101.com来玩正则表达式。我认为您可以使用前瞻(?=...)和后瞻(?<=...)组:

此正则表达式将匹配您的所有变量:

/(?!void)(?<=[ \(])[a-z]+(?=[, ;+*\/\)])/

这里有证据:

http://regex101.com/r/hS9dQ6/2

答案 5 :(得分:0)

我最终在解决方案中作弊。我已经获得了所有运算符信息,例如int / public / methods等...所以我只是在源代码上使用了替换,然后运行了下面的正则表达式,它找到了度量标准的操作数。

'_?\w+(?=([^"]*"[^"]*")*[^"]*$)|".+"'

这里有一些非常好的答案,所以我将考虑使用它们的混合来改进以后的实施,但是现在我们得到了我们需要的信息,它似乎适用于所有情况我们已经测试过了。

如果有人对我用于运营商的正则表达式感兴趣,请使用以下

(?i)\(|\{|\w+(?=(\(|:|\.))|\w+(?=\s\w)|(break|continue|return|true|false|retry|asc|breakpoint|desc|null|pause|throw|ttsAbort|ttsBegin|ttsCommit)(?=;)|((try|catch|else|by|do)(?=\n))|(\+=|-=|>=|<=|==|!=|=|\+\+|--|<<|>>|&&|\|\||\*|\/|\+|-|~|&|\^|\||>|<|!|\?|::|:|\.)+(?=([^"]*"[^"]*")*[^"]*$)

它包含前4个语句未涵盖的所有保留关键字,我还得到了x ++使用的运算符列表。

在其他语言中需要进行一些修改,但考虑到其他语言有更好的方法来处理这些你可能不需要的东西。

感谢您的所有答案