标记化后的良好解析方法

时间:2017-04-24 03:07:38

标签: c# parsing token interpreter

我编写了一个程序,在其中我读取了一个字符串或文件并对其进行了标记。 示例字符串: "int w = sad&&s||a|d++ != == < > >= <= -- sadsa++ % int sads = 232.32; if reg string test = \"Hello World\";% % +- + - / * ** false true"

Exmaple输出:

Token[Type:'Identifier',Value:'int',Line:'1',Position:'3']
Token[Type:'Literal',Value:'w',Line:'1',Position:'4']
Token[Type:'Assign',Value:'=',Line:'1',Position:'4']
Token[Type:'Literal',Value:'sad',Line:'1',Position:'8']
Token[Type:'Logical',Value:'&&',Line:'1',Position:'8']
Token[Type:'Literal',Value:'s',Line:'1',Position:'11']
Token[Type:'Logical',Value:'||',Line:'1',Position:'11']
Token[Type:'Literal',Value:'a',Line:'1',Position:'14']
Token[Type:'Unknown',Value:'|d',Line:'1',Position:'14']
Token[Type:'Literal',Value:'d',Line:'1',Position:'16']
Token[Type:'Arithmetic',Value:'++',Line:'1',Position:'16']
Token[Type:'Relational',Value:'!=',Line:'1',Position:'18']
Token[Type:'Relational',Value:'==',Line:'1',Position:'20']
Token[Type:'Relational',Value:'<',Line:'1',Position:'22']
Token[Type:'Relational',Value:'>',Line:'1',Position:'23']
Token[Type:'Relational',Value:'>=',Line:'1',Position:'24']
Token[Type:'Relational',Value:'<=',Line:'1',Position:'26']
Token[Type:'Arithmetic',Value:'--',Line:'1',Position:'28']
Token[Type:'Literal',Value:'sadsa',Line:'1',Position:'35']
Token[Type:'Arithmetic',Value:'++',Line:'1',Position:'35']
Token[Type:'Arithmetic',Value:'%',Line:'1',Position:'37']
Token[Type:'Identifier',Value:'int',Line:'1',Position:'41']
Token[Type:'Literal',Value:'sads',Line:'1',Position:'45']
Token[Type:'Assign',Value:'=',Line:'1',Position:'45']
Token[Type:'DoubleValue',Value:'232.32',Line:'1',Position:'51']
Token[Type:'Semicolon',Value:';',Line:'1',Position:'51']
Token[Type:'Identifier',Value:'if',Line:'1',Position:'53']
Token[Type:'Literal',Value:'reg',Line:'1',Position:'56']
Token[Type:'Identifier',Value:'string',Line:'1',Position:'62']
Token[Type:'Literal',Value:'test',Line:'1',Position:'66']
Token[Type:'Assign',Value:'=',Line:'1',Position:'66']
Token[Type:'StringValue',Value:'Hello World',Line:'1',Position:'78']
Token[Type:'Semicolon',Value:';',Line:'1',Position:'78']
Token[Type:'Arithmetic',Value:'%',Line:'1',Position:'78']
Token[Type:'Arithmetic',Value:'%',Line:'1',Position:'79']
Token[Type:'Unknown',Value:'+-',Line:'1',Position:'80']
Token[Type:'Arithmetic',Value:'+',Line:'1',Position:'82']
Token[Type:'Arithmetic',Value:'-',Line:'1',Position:'83']
Token[Type:'Arithmetic',Value:'/',Line:'1',Position:'84']
Token[Type:'Arithmetic',Value:'*',Line:'1',Position:'85']
Token[Type:'Unknown',Value:'**',Line:'1',Position:'86']
Token[Type:'Identifier',Value:'false',Line:'1',Position:'93']
Token[Type:'Identifier',Value:'true',Line:'1',Position:'97']
Elapsed time: 31

(忽略位置,将来必须修复)

所以现在我真的不知道一个很好的方法来进一步解释这个,以便自己运行一个简单的小脚本语言。

1 个答案:

答案 0 :(得分:0)

一个好的第一种方法是为每件事物提出名称,例如&#34;操作&#34;,&#34;操作数&#34;,&#34;文字&#34;,&#34;声明& #34;等

然后创建一个函数,可以从令牌流中读取每个函数,并在适当的地方调用其他函数。例如。如果你有:

operation: <operand> <operator> <operand>
operator: + | -
operand: <number> | <string>

等,然后你可以有一个函数(伪代码):

Operation parseOperation( tokens )
{
    Operand operand1 = parseOperand( tokens )
    Operation theOp = new Operation( tokens.fetchNextToken() )
    Operand operand2 = parseOperand( tokens )
    theOp.operand[0] = operand1
    theOp.operand[1] = operand2
    return theOp
}

以类似的方式实现其他功能。当然,某些功能可能必须检查下一个令牌以决定调用哪个其他功能,甚至可以查看几个令牌。

这通常被称为&#34;递归下降&#34;解析器。

每个函数都返回一个表示操作的对象,并将其参数挂起。这基本上是一个树结构,然后你可以递归地走(&#34;深度优先&#34;)。

最简单的方法是给你定义不同的对象类型你的操作和值方法,比如asString()或asInt(),然后执行以下操作:

int Operation::asInt()
{
   int a = operand[0].asInt()
   int b = operand[1].asInt()
   return a + b;
}

已经是正确类型的对象(如IntOperand类)只返回它们的值:

int IntOperand::asInt()
{
    return self.numericValue
}

或其他什么。不属于正确类型的对象要么产生错误而不是返回值,要么自行转换。所以不管表达式有多复杂,最后你得到一个int或字符串或者其他任何东西。

要运行程序,您现在可以询问最底层的对象的值。

相关问题