表达式翻译 一
在工作中会经常碰到,在一个框中由用户输入表达式,然后算出一个结果的情形,例如3 + 5 * (10 - 4);如何分析这个表达式呢?这其实涉及到一个常用的思路叫解释器.
它包括词法分析, 语法分析, 语义分析.
本章节只讲词法分析
词法分析就是将输入的字符串符号(例如关键字,常数,运算符等),分解成一系列的标记(Tokens)
既然是分析,那表达式中是否有错误, 在什么位置都能精确的定位
词法分析的任务:
- 过滤:空格、换行符、制表符、注释等
- 识别:根据构词规则,词法分析器识别出单词。这些单词包括标识符、关键字(保留字)、常数、运算符和界符等
- 将编译器生成的错误信息与源程序的位置联系起来
字符串中的加,减,乘,除,括号,关键字,数字,参数名等被称为标记
// 标记类型,这里只列举了部分
public enum TokenType
{
//数字
Number,
//+
Plus,
//-
Minus,
//*
Multiply,
//(
LeftParen,
//)
RightParen,
//结束
EOF // End Of File
}
// 标记类
public class Token
{
public TokenType Type { get; }
public string Value { get; }
public Token(TokenType type, string value = "")
{
Type = type;
Value = value;
}
}
下面我们添加词法分析类
public class Lexer
{
private readonly string _text;
private int _pos;
private char _currentChar;
public Lexer(string text)
{
_text = text;
_pos = 0;
_currentChar = _text[_pos];
}
}
词法分析时要一个字符一个字符的分析,所以我们增加一个读取下一个字符的方法
// 读取下一个字符
private void ReadNextChar()
{
_pos++;
if (_pos >= _text.Length)
{
_currentChar = '\0'; // 表示EOF
}
else
{
_currentChar = _text[_pos];
}
}
如果表达式中有空格,我们要跳过空格
// 跳过空白字符
private void SkipWhitespace()
{
while (_currentChar != '\0' && char.IsWhiteSpace(_currentChar))
{
ReadNextChar();
}
}
下面就要开始形成标记Token,以数字为例
读取数字标记
// 读取数字标记
private Token Number()
{
string result = "";
while (_currentChar != '\0' && char.IsDigit(_currentChar))
{
result += _currentChar;
ReadNextChar();
}
return new Token(TokenType.Number, result);
}
读取所有标记
// 读取标记
public Token GetNextToken()
{
SkipWhitespace();
if (_currentChar == '+')
{
ReadNextChar();
return new Token(TokenType.Plus);
}
else if (_currentChar == '-')
{
ReadNextChar();
return new Token(TokenType.Minus);
}
else if (_currentChar == '*')
{
ReadNextChar();
return new Token(TokenType.Multiply);
}
else if (_currentChar == '(')
{
ReadNextChar();
return new Token(TokenType.LeftParen);
}
else if (_currentChar == ')')
{
ReadNextChar();
return new Token(TokenType.RightParen);
}
else if (char.IsDigit(_currentChar))
{
return Number();
}
else if (_currentChar == '\0')
{
return new Token(TokenType.EOF);
}
else
{
throw new Exception("Invalid character");
}
}