|
|
nono 1.7.0
//
// XM6i
// Copyright (C) 2013 Tetsuya Isaki
//
// 簡易アセンブラ: 字句解析
//
#include <errno.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include "iasm.h"
#include "ascii_ctype.h"
/* コンストラクタ */
Token::Token()
{
clear();
}
/* クリア */
void
Token::clear()
{
type = T_END;
word.erase();
number = 0;
}
/* トークン種別 t の表示用文字列を返す (static 関数) */
const char *
Token::type_name(token_type_t t)
{
if (t < 0 || t >= T_MAX) {
return "?";
}
return type_str[t];
}
/* 現在のトークンの種別文字列を返す */
const char *
Token::type_name() const
{
return type_name(type);
}
/* トークン種別の表示用文字列 */
/* token_type_t の順序と合わせること orz */
const char *Token::type_str[] = {
"END",
"SPACE",
"CHAR",
"STRING",
"NUMBER",
"LITERAL",
"SIZE",
"SHARP",
"COLON",
"COMMA",
"LPAREN",
"RPAREN",
"PLUS",
"MINUS",
"MULTI",
"DIVIDE",
"LT",
"GT",
};
/* 1文字の記号テーブル */
Scanner::mark_t Scanner::mark[] = {
{ '#', T_SHARP, },
{ ':', T_COLON, },
{ ',', T_COMMA, },
{ '(', T_LPAREN, },
{ ')', T_RPAREN, },
{ '+', T_PLUS, },
{ '-', T_MINUS, },
{ '*', T_MULTI, },
{ '/', T_DIVIDE, },
{ '<', T_LT, },
{ '>', T_GT, },
};
/* コンストラクタ */
Scanner::Scanner(String& src)
{
buf = src;
ptr = 0;
}
/* デストラクタ */
Scanner::~Scanner()
{
}
/* リテラルの1文字目を判定 (ドットを含み数字は含まない) */
bool
Scanner::isLabel1(int c)
{
return (isalpha(c) || c == '_' || c == '.');
}
/* リテラルの2文字目以降を判定 (数字は含みドットを含まない) */
bool
Scanner::isLabel2(int c)
{
return (isalpha(c) || c == '_' || isdigit(c));
}
/*
* サイズサフィックス文字を判定。
* 正しいものならバイト数を返す。
* bra.s (と fmove.s ?) のため .S なら 0 を返すのでそっちで判断しろ下さい。
* 正しくなければ -1 を返す。
*/
int
Scanner::isSize(int c) const
{
c = tolower(c);
if (c == 's') {
return 0;
}
if (c == 'b') {
return 1;
}
if (c == 'w') {
return 2;
}
if (c == 'l') {
return 4;
}
return -1;
}
/* トークンを1つ切り出す */
bool
Scanner::get_token(Token& token)
{
int c;
/* 戻り値を初期化 */
token.clear();
errmsg.erase();
c = getch();
/* 終端 */
if (c == 0) {
token.type = T_END;
return true;
}
/* 連続する空白は1つの空白 */
if (is_ascii_space(c)) {
for(; is_ascii_space((c = getch())); ptr++) {
token.word += c;
}
token.type = T_SPACE;
return true;
}
/* シングルクォートなら1文字 */
if (c == '\'') {
token.word = c;
ptr++;
/* 文字コンテキスト */
bool escape = false;
bool terminate = false;
int charnum = 0;
for (; (c = getch()) != 0; ptr++) {
if (escape) {
token.word += c;
/* 制御文字のコードをここで解釈 */
if (c == 't') {
token.number = '\t';
} else if (c == 'r') {
token.number = '\r';
} else if (c == 'n') {
token.number = '\n';
} else if (c == '0') {
token.number = '\0';
} else {
token.number = c;
}
charnum++;
escape = false;
continue;
}
if (c == '\\') {
token.word += c;
escape = true;
continue;
}
if (c == '\'') {
token.word += c;
terminate = true;
ptr++;
break;
}
token.word += c;
token.number = c;
charnum++;
}
if (!terminate) {
errmsg = "single char not terminated";
return false;
}
if (charnum != 1) {
errmsg = "invalid char";
return false;
}
token.type = T_CHAR;
return true;
}
/* ダブルクォートなら文字列 */
if (c == '\x22') {
token.word = c;
ptr++;
/* 文字列コンテキスト */
bool escape = false;
bool terminate = false;
for (; (c = getch()) != 0; ptr++) {
if (escape) {
token.word += c;
escape = false;
continue;
}
if (c == '\\') {
token.word += c;
escape = true;
continue;
}
if (c == '\x22') {
token.word += c;
terminate = true;
ptr++;
break;
}
token.word += c;
}
if (!terminate) {
errmsg = "string not terminated";
return false;
}
token.type = T_STRING;
return true;
}
/* 16進数 */
if (c == '$') {
token.word += c;
ptr++;
for (; isxdigit((c = getch())); ptr++) {
token.word += c;
}
/* 8桁('$'含めて9文字)越えたらアウトっていう判定だけでいいはず */
if (token.word.size() > 9) {
errmsg = "too large number";
return false;
}
/* 変換できるはず */
token.number = (uint32_t)strtol(token.word.c_str() + 1, NULL, 16);
token.type = T_NUMBER;
return true;
}
/* 10進数 */
if (isdigit(c)) {
for (; isdigit((c = getch())); ptr++) {
token.word += c;
}
errno = 0;
long lval;
lval = strtol(token.word.c_str(), NULL, 10);
if (errno == ERANGE && (lval == LONG_MAX || lval == LONG_MIN)) {
errmsg = "too large number";
return false;
}
token.number = (uint32_t)lval;
token.type = T_NUMBER;
return true;
}
/* プレインなところでのセミコロンはコメント開始記号 */
if (c == ';') {
/*
* コメント以降を字句解析すると文法エラーになる可能性があるので
* ここで解析をやめる。
*/
token.word = c;
token.type = T_END;
return true;
}
/* 1文字の記号 */
for (int i = 0; i < countof(mark); i++) {
if (mark[i].chr == c) {
token.word = c;
ptr++;
token.type = mark[i].type;
return true;
}
}
/* サイズサフィックス */
if (c == '.') {
int c1 = getch(1);
int c2 = getch(2);
int size;
if ((size = isSize(c1)) != -1 && !isalpha(c2)) {
token.word += c;
token.word += c1;
ptr += 2;
token.type = T_SIZE;
token.number = size;
return true;
}
/* そうでなければリテラル(擬似命令)かも */
/* PASSTHROUGH */
}
/* ラベル (1文字目と2文字目以降は判定条件が違う) */
if (isLabel1(c)) {
token.word = c;
ptr++;
for (; isLabel2((c = getch())); ptr++) {
token.word += c;
}
token.type = T_LITERAL;
return true;
}
errmsg = "syntax error";
return false;
}
/* 現在位置の文字を返す。文字列の終端以降なら 0 を返す */
int
Scanner::getch(int offset) const
{
int c;
if (ptr + offset < buf.size()) {
c = (int)buf[ptr + offset];
} else {
c = 0;
}
return c;
}
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.