C(C++)で何かを字句解析してみる(?) その2
3※なお、C++11の機能を使って書いてるのであしからず。
前回は、整数と文字列、空白文字(タブ、改行、スペース)だけを認識するというプログラムを書いた。
今回は少し拡張し、空白文字を細かく認識するようにし、今後のための些末な改良も加えた。
//Start. 2017/08/24 #include <cstdio> #include <cctype> #include <cstring> const int MAX_TOKEN_STR = 1024 + 1; enum KIND_OF_TOKEN {SPACE, TAB, NEWLINE, NUMBER, STRING, OTHER}; struct TOKEN{ KIND_OF_TOKEN kind; int count = 0;//何文字読み込んだかを保存 union{ int number; char str[MAX_TOKEN_STR]; }; }; bool ishyphen(char c){ if(c == '-'){ return true; } else{ return false; } } struct TOKEN tokenize_number(char* str){ int offset = 0; //追加した処理 if(ishyphen(str[0])){ offset = 1; } int i = 0; int num = 0; while(std::isdigit(str[i+offset])){ if(i > 0){ num *= 10; } num += str[i+offset] - '0'; ++i; } if(offset == 1){ num = 0 - num; } TOKEN token; token.kind = KIND_OF_TOKEN::NUMBER; token.number = num; token.count = i + offset; return token; } struct TOKEN tokenize_string(char* str){ TOKEN token; int i = 0; while(std::isalpha(str[i])){ token.str[i] = str[i]; ++i; } token.kind = KIND_OF_TOKEN::STRING; token.str[i] = '\0'; token.count = i; return token; } void tokenize(char* str){ int pos = 0; while(str[pos] != '\0'){ if(str[pos] == ' '){ TOKEN token; token.kind = KIND_OF_TOKEN::SPACE; token.count = 1; std::printf("[pos:%d]:[Space]\n", pos); pos++; } else if(str[pos] == '\r' || str[pos] == '\n'){ TOKEN token; token.kind = KIND_OF_TOKEN::NEWLINE; token.count = 1; std::printf("[pos:%d]:[NewLine]\n", pos); pos++; } else if(str[pos] == '\t'){ TOKEN token; token.kind = KIND_OF_TOKEN::TAB; token.count = 1; std::printf("[pos:%d]:[Tab]\n", pos); pos++; } else if(std::isdigit(str[pos]) || str[pos] == '-' || str[pos] == '+'){ struct TOKEN token = tokenize_number(&str[pos]); std::printf("[pos:%d-%d]:[Number]\n", pos, pos+token.count-1); pos += token.count; } else if(std::isalpha(str[pos])){ TOKEN token = tokenize_string(str+pos); std::printf("[pos:%d-%d]:[Alpha]\n", pos, pos+token.count-1); pos += token.count; } else{ TOKEN token; token.kind = KIND_OF_TOKEN::OTHER; token.count = 1; std::printf("[pos:%d]: unrecognize token\n", pos); pos++; } } } /* ** main */ int main(int argc, char **argv){ char str[40] = "0 12 -3\n\t4.56 i abc;\n"; std::printf("source:%s\n", str); tokenize(str); return 0; }
ソースコードをカット&ペーストするのも面倒なんで、
GitHub - seekerkrt/compiler
コレに置いとく。