编译原理

感谢vczh轮子叔的坑了的教程,我的编译原理第一次入了个门,词法分析写完了,今后可以看看书继续往下学了。

http://www.cppblog.com/vczh/archive/2014/03/02/206014.html

词法分析,就是对于一段代码,把他们分割成一个个的token,同时记录他们的行列号,丢掉不必要的信息,这个词法分析器很简单,简单的状态机就能胜任,用正则就没有自己造轮子的快感了,所以要自己手撸状态机拆token出来。

模仿vczh的语言,我的语言包括了以下要素

  标识符:大小写字母和下划线构成的连续串[a-zA-Z_]

  数字:自然书写的整数和浮点数,整数部分为0的浮点数必须要用0.开头

  运算符:单个符号

  注释:#开头,#或 结尾的任意内容,也就是说注释最多是一整行

  字符串:双引号"开头结尾的任意内容,支持\, 两种转义字符。

这样简单的语言,用正则表达式处理也很简单,但是为了贯彻自己造轮子的原则,我们手写一波状态机

首先把状态机的图画出来,就像这样(因为没有钱买visio,所以只能用一个叫lucidchart的在线应用画图了)

虚线表示这个状态可以直接跳到End状态,而所谓End状态就是Start状态,所以到了有虚线的状态,可以看情况直接跳到Start,并且有些状态也可以直接优化掉,比如InStringEnd, InOperator等,遇到这样的状态,直接输出一个token,然后把state设为Start就好了。

这样的状态机是不是很简单,更加复杂的一些状态,也可以手动构造正则表达式,然后用vczh的另一篇教程手写出状态机来。

忘了说Token的结构了,这个很简单

struct Token
{
    int line;
    int column;
    TokenType type;
    std::wstring value;
    Token(): Token(0, 0, TokenType::Unknown, L"", 0)
    {
    }
    Token(int _line, int _column, TokenType _type, const wchar_t* str, int len)
        : line(_line)
        , column(_column)
        , type(_type)
        , value(str, len)
    {
    }
    void Reset()
    {
        line = 0;
        column = 0;
        type = TokenType::Unknown;
        value.clear();
    }
    void Push(const wchar_t ch)
    {
        value.push_back(ch);
    }
};

那个Reset和Push纯粹是因为我偷懒,把这个第一个版本的代码写得很烂,只能用这种不科学的封装来减少一下代码的重复了。

有了状态机和具体的状态:

enum class TokenType
{
    Unknown,
    Number,
    Comment,
    Operator,
    Identifier,
    String
};

enum class ParseState
{
    Begin,
    InComment,
    //InCommentEnd,
    InInteger,
    InFloat,
    InOperator,
    InIdentifier,
    InString,
    InStringEscaping,
    //InStringEnd
};

可以构造状态机了,模板是这样的:

while (*reading)
{
    switch (state)
    {
    case 某个状态:
    {
        switch (*reading)
        {
        case 某个或某几个字符:
            #根据状态机里当前状态能接受和不能接受的字符,修改新的状态,读入字符,reading++,或者直接抛异常
        break;
        }
    }
}

第一个版本的代码写得很烂,纯粹是能用的程序,放在这里纯粹是显摆一下,之后我会考虑重构什么的,然后再来更新这篇文章,而且没有写单元测试,正确性纯粹是肉眼检查,报错信息也很不友善,这一点下一个版本的代码再改。

更新,稍微优化了一下,重复代码少了不少,我很喜欢,还能接着改

下面贴代码:

TokenStream.h

  1 #pragma once
  2 #ifndef TOKEN_STREAM
  3 #define TOKEN_STREAM
  4 
  5 #include <string>
  6 #include <vector>
  7 enum class TokenType
  8 {
  9     Unknown,
 10     Number,
 11     Comment,
 12     Operator,
 13     Identifier,
 14     String
 15 };
 16 
 17 enum class ParseState
 18 {
 19     Begin,
 20     InComment,
 21     //InCommentEnd,
 22     InInteger,
 23     InFloat,
 24     InOperator,
 25     InIdentifier,
 26     InString,
 27     InStringEscaping,
 28     //InStringEnd
 29 };
 30 struct Token
 31 {
 32     int line;
 33     int column;
 34     TokenType type;
 35     std::wstring value;
 36     Token(int _line, int _column, TokenType _type, const wchar_t* begin, const wchar_t* end)
 37         : line(_line)
 38         , column(_column)
 39         , type(_type)
 40         , value(begin, end)
 41     {
 42         if (type == TokenType::String)
 43         {
 44             for (size_t i = 0; i < value.length(); i++)
 45             {
 46                 if (value[i] == '\')
 47                 {
 48                     if (i + 1 < value.length())
 49                     {
 50                         switch (value[i + 1])
 51                         {
 52                         case'\':
 53                         {
 54                             value.replace(i, 2, 1, '\');
 55                             break;
 56                         }
 57                         case'n':
 58                         {
 59                             value.replace(i, 2, 1, '
');
 60                             break;
 61                         }
 62                         case'"':
 63                         {
 64                             value.replace(i, 2, 1, '"');
 65                             break;
 66                         }
 67                         default:
 68                         {
 69                             throw std::exception("error in escaping");
 70                             break;
 71                         }
 72                         }
 73                     }
 74                     else
 75                     {
 76                         throw std::exception("error in escaping");
 77                     }
 78                 }
 79             }
 80         }
 81     }
 82 };
 83 
 84 class TokenStream
 85 {
 86 private:
 87     struct ParsingState
 88     {
 89         ParseState State;
 90         int Line;
 91         int Column;
 92         const wchar_t* TokenStart;
 93         const wchar_t* TokenEnd;
 94     };
 95     std::vector<Token> tokenList;
 96     
 97     void PushToken(ParsingState& state, TokenType type)
 98     {
 99         tokenList.push_back(Token(state.Line, state.Column, type, state.TokenStart, state.TokenEnd));
100     }
101 public:
102     std::vector<Token> Parse(std::wstring& source)
103     {
104         ParsingState state{ParseState::Begin, 0, 0, source.c_str(), source.c_str()};
105         int lineNumber = 1;
106         int columnNumber = 1;
107 
108         while (*state.TokenEnd)
109         {
110             switch (state.State)
111             {
112             case ParseState::Begin:
113             {
114                 state.TokenStart = state.TokenEnd;
115                 state.Column = columnNumber;
116                 state.Line = lineNumber;
117                 switch (*state.TokenEnd)
118                 {
119                 case'+':case'-':case'*':case'/':case'(':case')':case'<':case'>':case'=':case';':
120                 case'^':case'&':case'.':
121                 {
122                     state.TokenEnd++;
123                     PushToken(state, TokenType::Operator);
124                     state.TokenEnd--;
125                     break;
126                 }
127                 case'0':case'1':case'2':case'3':case'4':case'5':case'6':case'7':case'8':case'9':
128                 {
129                     state.State = ParseState::InInteger;
130                     break;
131                 }
132                 case'a':case'b':case'c':case'd':case'e':case'f':case'g':case'h':case'i':case'j':case'k':case'l':case'm':case'n':case'o':case'p':case'q':case'r':case's':
133                 case't':case'u':case'v':case'w':case'x':case'y':case'z':case'A':case'B':case'C':case'D':case'E':case'F':case'G':case'H':case'I':case'J':case'K':case'L':
134                 case'M':case'N':case'O':case'P':case'Q':case'R':case'S':case'T':case'U':case'V':case'W':case'X':case'Y':case'Z':case'_':
135                 {
136                     state.State = ParseState::InIdentifier;
137                     break;
138                 }
139                 case'#':
140                 {
141                     state.TokenStart++;
142                     state.State = ParseState::InComment;
143                     break;
144                 }
145                 case'"':
146                 {
147                     state.TokenStart++;
148                     state.State = ParseState::InString;
149                     break;
150                 }
151                 case'
':
152                 {
153                     lineNumber++;
154                     columnNumber = 0;
155                     break;
156                 }
157                 case' ':
158                 {
159                     break;
160                 }
161                 default:
162                 {
163                     throw std::exception("parse error");
164                     break;
165                 }
166                 }
167                 break;
168             } //case ParseState::Begin
169             case ParseState::InInteger:
170             {
171                 switch (*state.TokenEnd)
172                 {
173                 case'0':case'1':case'2':case'3':case'4':case'5':case'6':case'7':case'8':case'9':
174                 {
175                     break;
176                 }
177                 case'.':
178                 {
179                     state.State = ParseState::InFloat;
180                     break;
181                 }
182                 default:
183                 {
184                     state.State = ParseState::Begin;
185                     PushToken(state, TokenType::Number);
186                     state.TokenEnd--;
187                     columnNumber--;
188                     break;
189                 }
190                 }
191                 break;
192             } //case ParseState::InInteger
193             case ParseState::InComment:
194             {
195                 if (*state.TokenEnd == '
' || *state.TokenEnd == '#')
196                 {
197                     state.State = ParseState::Begin;
198                     if (*state.TokenEnd == '
')
199                     {
200                         lineNumber++;
201                     }
202                     columnNumber = 1;
203                     PushToken(state, TokenType::Comment);
204                 }
205                 break;
206             } //ParseState::InComment
207             case ParseState::InIdentifier:
208             {
209                 switch (*state.TokenEnd)
210                 {
211                 case'a':case'b':case'c':case'd':case'e':case'f':case'g':case'h':case'i':case'j':case'k':case'l':case'm':case'n':case'o':case'p':case'q':case'r':case's':
212                 case't':case'u':case'v':case'w':case'x':case'y':case'z':case'A':case'B':case'C':case'D':case'E':case'F':case'G':case'H':case'I':case'J':case'K':case'L':
213                 case'M':case'N':case'O':case'P':case'Q':case'R':case'S':case'T':case'U':case'V':case'W':case'X':case'Y':case'Z':case'_':
214                 {
215                     break;
216                 }
217                 default:
218                 {
219                     state.State = ParseState::Begin;
220                     PushToken(state, TokenType::Identifier);
221                     columnNumber--;
222                     state.TokenEnd--;
223                     break;
224                 }
225                 }
226                 break;
227             } //ParseState::InIdentifier
228             case ParseState::InString:
229             {
230                 switch (*state.TokenEnd)
231                 {
232                 case '\':
233                 {
234                     state.State = ParseState::InStringEscaping;
235                     break;
236                 }
237                 case '"':
238                 {
239                     state.State = ParseState::Begin;
240                     PushToken(state, TokenType::String);
241                     break;
242                 }
243                 case '
':
244                 {
245                     throw std::exception("parse error in string");
246                     break;
247                 }
248                 default:
249                 {
250                     break;
251                 }
252                 }
253                 break;
254             } // ParseState::InString
255             case ParseState::InFloat:
256             {
257                 switch (*state.TokenEnd)
258                 {
259                 case'0':case'1':case'2':case'3':case'4':case'5':case'6':case'7':case'8':case'9':
260                 {
261                     break;
262                 }
263                 default:
264                 {
265                     PushToken(state, TokenType::Number);
266                     columnNumber--;
267                     state.TokenEnd--;
268                     state.State = ParseState::Begin;
269                     break;
270                 }
271                 }
272                 break;
273             } //ParseState::InFloat
274             case ParseState::InStringEscaping:
275             {
276                 state.State = ParseState::InString;
277                 switch (*state.TokenEnd)
278                 {
279                 case'n':case'\':case'"':
280                 {
281                     break;
282                 }
283                 default:
284                 {
285                     throw std::exception("parse error in escaping");
286                     break;
287                 }
288                 }
289                 break;
290             } //ParseState::InStringEscaping
291             } //switch state
292             state.TokenEnd++;
293             columnNumber++;
294         }
295         return tokenList;
296     }
297 };
298 
299 #endif // !TOKEN_STREAM

300行的大函数,我也是醉了

原文地址:https://www.cnblogs.com/pointer-smq/p/4904531.html