|
|
1.1 ! root 1: // ! 2: // XM6i ! 3: // Copyright (C) 2013 [email protected] ! 4: // ! 5: // 簡易アセンブラ: 字句解析 ! 6: // ! 7: ! 8: #include <ctype.h> ! 9: #include <errno.h> ! 10: #include <stdint.h> ! 11: #include <stdio.h> ! 12: #include <stdlib.h> ! 13: #include <limits.h> ! 14: #include "iasm.h" ! 15: ! 16: ! 17: /* コンストラクタ */ ! 18: Token::Token() ! 19: { ! 20: clear(); ! 21: } ! 22: ! 23: /* クリア */ ! 24: void ! 25: Token::clear() ! 26: { ! 27: type = T_END; ! 28: word.erase(); ! 29: number = 0; ! 30: } ! 31: ! 32: /* トークン種別 t の表示用文字列を返す (static 関数) */ ! 33: const char * ! 34: Token::type_name(token_type_t t) ! 35: { ! 36: if (t < 0 || t >= T_MAX) { ! 37: return "?"; ! 38: } ! 39: return type_str[t]; ! 40: } ! 41: ! 42: /* 現在のトークンの種別文字列を返す */ ! 43: const char * ! 44: Token::type_name() const ! 45: { ! 46: return type_name(type); ! 47: } ! 48: ! 49: /* トークン種別の表示用文字列 */ ! 50: /* token_type_t の順序と合わせること orz */ ! 51: const char *Token::type_str[] = { ! 52: "END", ! 53: "SPACE", ! 54: "CHAR", ! 55: "STRING", ! 56: "NUMBER", ! 57: "LITERAL", ! 58: "SIZE", ! 59: "SHARP", ! 60: "COLON", ! 61: "COMMA", ! 62: "LPAREN", ! 63: "RPAREN", ! 64: "PLUS", ! 65: "MINUS", ! 66: "MULTI", ! 67: "DIVIDE", ! 68: "LT", ! 69: "GT", ! 70: }; ! 71: ! 72: ! 73: /* 1文字の記号テーブル */ ! 74: Scanner::mark_t Scanner::mark[] = { ! 75: { '#', T_SHARP, }, ! 76: { ':', T_COLON, }, ! 77: { ',', T_COMMA, }, ! 78: { '(', T_LPAREN, }, ! 79: { ')', T_RPAREN, }, ! 80: { '+', T_PLUS, }, ! 81: { '-', T_MINUS, }, ! 82: { '*', T_MULTI, }, ! 83: { '/', T_DIVIDE, }, ! 84: { '<', T_LT, }, ! 85: { '>', T_GT, }, ! 86: }; ! 87: ! 88: /* コンストラクタ */ ! 89: Scanner::Scanner(String& src) ! 90: { ! 91: buf = src; ! 92: ptr = 0; ! 93: } ! 94: ! 95: /* デストラクタ */ ! 96: Scanner::~Scanner() ! 97: { ! 98: } ! 99: ! 100: /* リテラルの1文字目を判定 (ドットを含み数字は含まない) */ ! 101: bool ! 102: Scanner::isLabel1(int c) ! 103: { ! 104: return (isalpha(c) || c == '_' || c == '.'); ! 105: } ! 106: ! 107: /* リテラルの2文字目以降を判定 (数字は含みドットを含まない) */ ! 108: bool ! 109: Scanner::isLabel2(int c) ! 110: { ! 111: return (isalpha(c) || c == '_' || isdigit(c)); ! 112: } ! 113: ! 114: /* ! 115: * サイズサフィックス文字を判定。 ! 116: * 正しいものならバイト数を返す。 ! 117: * bra.s (と fmove.s ?) のため .S なら 0 を返すのでそっちで判断しろ下さい。 ! 118: * 正しくなければ -1 を返す。 ! 119: */ ! 120: int ! 121: Scanner::isSize(int c) const ! 122: { ! 123: c = tolower(c); ! 124: ! 125: if (c == 's') { ! 126: return 0; ! 127: } ! 128: if (c == 'b') { ! 129: return 1; ! 130: } ! 131: if (c == 'w') { ! 132: return 2; ! 133: } ! 134: if (c == 'l') { ! 135: return 4; ! 136: } ! 137: ! 138: return -1; ! 139: } ! 140: ! 141: /* トークンを1つ切り出す */ ! 142: bool ! 143: Scanner::get_token(Token& token) ! 144: { ! 145: int c; ! 146: ! 147: /* 戻り値を初期化 */ ! 148: token.clear(); ! 149: errmsg.erase(); ! 150: ! 151: c = getch(); ! 152: ! 153: /* 終端 */ ! 154: if (c == 0) { ! 155: token.type = T_END; ! 156: return true; ! 157: } ! 158: ! 159: /* 連続する空白は1つの空白 */ ! 160: if (isspace(c)) { ! 161: for(; isspace((c = getch())); ptr++) { ! 162: token.word += c; ! 163: } ! 164: token.type = T_SPACE; ! 165: return true; ! 166: } ! 167: ! 168: /* シングルクォートなら1文字 */ ! 169: if (c == '\'') { ! 170: token.word = c; ! 171: ptr++; ! 172: /* 文字コンテキスト */ ! 173: bool escape = false; ! 174: bool terminate = false; ! 175: int charnum = 0; ! 176: for (; (c = getch()) != 0; ptr++) { ! 177: if (escape) { ! 178: token.word += c; ! 179: /* 制御文字のコードをここで解釈 */ ! 180: if (c == 't') { ! 181: token.number = '\t'; ! 182: } else if (c == 'r') { ! 183: token.number = '\r'; ! 184: } else if (c == 'n') { ! 185: token.number = '\n'; ! 186: } else if (c == '0') { ! 187: token.number = '\0'; ! 188: } else { ! 189: token.number = c; ! 190: } ! 191: charnum++; ! 192: escape = false; ! 193: continue; ! 194: } ! 195: if (c == '\\') { ! 196: token.word += c; ! 197: escape = true; ! 198: continue; ! 199: } ! 200: if (c == '\'') { ! 201: token.word += c; ! 202: terminate = true; ! 203: ptr++; ! 204: break; ! 205: } ! 206: token.word += c; ! 207: token.number = c; ! 208: charnum++; ! 209: } ! 210: if (!terminate) { ! 211: errmsg = "single char not terminated"; ! 212: return false; ! 213: } ! 214: if (charnum != 1) { ! 215: errmsg = "invalid char"; ! 216: return false; ! 217: } ! 218: token.type = T_CHAR; ! 219: return true; ! 220: } ! 221: ! 222: /* ダブルクォートなら文字列 */ ! 223: if (c == '\x22') { ! 224: token.word = c; ! 225: ptr++; ! 226: /* 文字列コンテキスト */ ! 227: bool escape = false; ! 228: bool terminate = false; ! 229: for (; (c = getch()) != 0; ptr++) { ! 230: if (escape) { ! 231: token.word += c; ! 232: escape = false; ! 233: continue; ! 234: } ! 235: if (c == '\\') { ! 236: token.word += c; ! 237: escape = true; ! 238: continue; ! 239: } ! 240: if (c == '\x22') { ! 241: token.word += c; ! 242: terminate = true; ! 243: ptr++; ! 244: break; ! 245: } ! 246: token.word += c; ! 247: } ! 248: if (!terminate) { ! 249: errmsg = "string not terminated"; ! 250: return false; ! 251: } ! 252: token.type = T_STRING; ! 253: return true; ! 254: } ! 255: ! 256: /* 16進数 */ ! 257: if (c == '$') { ! 258: token.word += c; ! 259: ptr++; ! 260: for (; isxdigit((c = getch())); ptr++) { ! 261: token.word += c; ! 262: } ! 263: /* 8桁('$'含めて9文字)越えたらアウトっていう判定だけでいいはず */ ! 264: if (token.word.size() > 9) { ! 265: errmsg = "too large number"; ! 266: return false; ! 267: } ! 268: /* 変換できるはず */ ! 269: token.number = (uint32_t)strtol(token.word.c_str() + 1, NULL, 16); ! 270: token.type = T_NUMBER; ! 271: return true; ! 272: } ! 273: ! 274: /* 10進数 */ ! 275: if (isdigit(c)) { ! 276: for (; isdigit((c = getch())); ptr++) { ! 277: token.word += c; ! 278: } ! 279: errno = 0; ! 280: long lval; ! 281: lval = strtol(token.word.c_str(), NULL, 10); ! 282: if (errno == ERANGE && (lval == LONG_MAX || lval == LONG_MIN)) { ! 283: errmsg = "too large number"; ! 284: return false; ! 285: } ! 286: token.number = (uint32_t)lval; ! 287: token.type = T_NUMBER; ! 288: return true; ! 289: } ! 290: ! 291: /* プレインなところでのセミコロンはコメント開始記号 */ ! 292: if (c == ';') { ! 293: /* ! 294: * コメント以降を字句解析すると文法エラーになる可能性があるので ! 295: * ここで解析をやめる。 ! 296: */ ! 297: token.word = c; ! 298: token.type = T_END; ! 299: return true; ! 300: } ! 301: ! 302: /* 1文字の記号 */ ! 303: for (int i = 0; i < countof(mark); i++) { ! 304: if (mark[i].chr == c) { ! 305: token.word = c; ! 306: ptr++; ! 307: token.type = mark[i].type; ! 308: return true; ! 309: } ! 310: } ! 311: ! 312: /* サイズサフィックス */ ! 313: if (c == '.') { ! 314: int c1 = getch(1); ! 315: int c2 = getch(2); ! 316: int size; ! 317: if ((size = isSize(c1)) != -1 && !isalpha(c2)) { ! 318: token.word += c; ! 319: token.word += c1; ! 320: ptr += 2; ! 321: token.type = T_SIZE; ! 322: token.number = size; ! 323: return true; ! 324: } ! 325: ! 326: /* そうでなければリテラル(擬似命令)かも */ ! 327: /* PASSTHROUGH */ ! 328: } ! 329: ! 330: /* ラベル (1文字目と2文字目以降は判定条件が違う) */ ! 331: if (isLabel1(c)) { ! 332: token.word = c; ! 333: ptr++; ! 334: for (; isLabel2((c = getch())); ptr++) { ! 335: token.word += c; ! 336: } ! 337: token.type = T_LITERAL; ! 338: return true; ! 339: } ! 340: ! 341: errmsg = "syntax error"; ! 342: return false; ! 343: } ! 344: ! 345: /* 現在位置の文字を返す。文字列の終端以降なら 0 を返す */ ! 346: int ! 347: Scanner::getch(int offset) const ! 348: { ! 349: int c; ! 350: ! 351: if (ptr + offset < buf.size()) { ! 352: c = (int)buf[ptr + offset]; ! 353: } else { ! 354: c = 0; ! 355: } ! 356: return c; ! 357: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.