使用正则表达式的C#Tokenizer - 阻止它向前看英里

时间:2015-12-10 18:40:56

标签: c# regex

我正在尝试为自定义编程语言创建一个编译器,我在Java中已经这样做了。但是出于好的理由我想把它移植到本机代码,C#是我的选择。我面临的问题是,当我与正则表达式匹配时,匹配器正在查看整个源代码文件而不是开始。

源代码示例:

namespace CrazyRedd{
    class Test{
        public function main(string[] args){
            System.println("Hello World");
        }
    }
}

输出(格式为tokenValue +" |" + tokenType):

namespace | KEYWORD
class | KEYWORD
function | KEYWORD
 | STR_LITERAL
 | STR_LITERAL
public | IDENTIFIER
Hello | IDENTIFIER
. | SYMBOL
; | SYMBOL
( | SYMBOL
( | SYMBOL
Systemprintln | IDENTIFIER
) | SYMBOL
) | SYMBOL
World | IDENTIFIER
[ | SYMBOL
] | SYMBOL
string | BUILT_IN_TYPE
main | IDENTIFIER
{ | SYMBOL
CrazyRedd | IDENTIFIER
{ | SYMBOL
Test | IDENTIFIER
{ | SYMBOL
args | IDENTIFIER
} | SYMBOL
} | SYMBOL
} | SYMBOL

获取下一个令牌的方法是:

    public Token nextToken()
    {
        str = str.Trim();
        if (pushBack)
        {
            pushBack = false;
            return lastToken;
        }
        if (String.IsNullOrEmpty(str))
        {
            return (lastToken=new Token("", TokenType.EMPTY));
        }
        foreach(TokenData tokenData in tokenDatas)
        {
            Match matcher = Regex.Match(str, tokenData.getPattern(), RegexOptions.IgnoreCase);
            if (matcher.Success)
            {
                string token = matcher.Value.Trim();
                Regex replacer = new Regex(Regex.Escape(token));
                str = replacer.Replace(str,"",1);
                if (tokenData.getType() == TokenType.STR_LITERAL)
                {
                    return (lastToken = new Token(token.Substring(1, token.Length - 1),
                        TokenType.STR_LITERAL));
                }
                else
                {
                    return (lastToken = new Token(token, tokenData.getType()));
                }
            }
        }
        throw new Exception("Fatal Error: Could not compile: "+str);
    }

最后,以下是进入Tokenizer的方法:

public void init()
        {
            string[] keys = { "if", "else", "namespace", "class", "function" };
            foreach (string key in keys)
            {
                tokenDatas.Add(new TokenData(key + "\\s", TokenType.KEYWORD));
            }
            string[] types = { "int", "byte", "char", "string", "bool", "const" };
            foreach (string type in types)
            {
                tokenDatas.Add(new TokenData(type + "\\s", TokenType.BUILT_IN_TYPE));
            }
            tokenDatas.Add(new TokenData("(-)?[0-9]+", TokenType.INT_LITERAL));
            tokenDatas.Add(new TokenData("\"*\"", TokenType.STR_LITERAL));
            tokenDatas.Add(new TokenData("[a-zA-Z][a-zA-Z0-9]*\\s", TokenType.IDENTIFIER));
            string[] syms = { "\\.", "\\,", "\\;", "\\(", "\\)", "\\[", "\\]", "\\{", "\\}" };
            foreach (string sym in syms)
            {
                tokenDatas.Add(new TokenData(sym, TokenType.SYMBOL));
            }
            string[] ops = { "\\+", "\\-", "\\*", "/", "%", "=", "\\+=", "-=", "\\*=", "/=", "%=" };
            foreach (string op in ops)
            {
                tokenDatas.Add(new TokenData(op, TokenType.OPERATOR));
            }
            string[] coms = { "<", ">", "<=", ">=", "==", "!=" };
            foreach (string com in coms)
            {
                tokenDatas.Add(new TokenData(com, TokenType.COMPARATOR));
            }
        }

我需要知道的是导致Tokenizer以错误的顺序吐出令牌的原因。

1 个答案:

答案 0 :(得分:2)

只是看了一下你的代码,这似乎导致了你的问题。

每次调用nextToken()

foreach(TokenData tokenData in tokenDatas)
{
   Match matcher = Regex.Match(str, tokenData.getPattern(), RegexOptions.IgnoreCase);
   if (matcher.Success)
       ...
}

导致此循环,其中Match函数被赋予新模式
对于每个新的tokenData 像所有引擎一样,这将在位置0开始匹配检查。

它失序的原因是它匹配任何顺序 正则表达式模式恰好位于中,无论匹配发生在哪里