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