我正在尝试为自定义编程语言创建一个编译器,我在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以错误的顺序吐出令牌的原因。
答案 0 :(得分:2)
只是看了一下你的代码,这似乎导致了你的问题。
每次调用nextToken()
foreach(TokenData tokenData in tokenDatas)
{
Match matcher = Regex.Match(str, tokenData.getPattern(), RegexOptions.IgnoreCase);
if (matcher.Success)
...
}
导致此循环,其中Match函数被赋予新模式
对于每个新的tokenData
像所有引擎一样,这将在位置0开始匹配检查。
它失序的原因是它匹配任何顺序 正则表达式模式恰好位于中,无论匹配发生在哪里。