Annotation of nono/util/iasm/iasm.cpp, revision 1.1.1.2

1.1       root        1: //
                      2: // XM6i
                      3: // Copyright (C) 2012-2016 [email protected]
                      4: //
                      5: // 簡易アセンブラ
                      6: //
                      7: 
                      8: #include <stdio.h>
                      9: #include <stdint.h>
                     10: #include <stdlib.h>
                     11: #include <stdarg.h>
                     12: #include <string.h>
                     13: #include <unistd.h>
                     14: #include <map>
                     15: #include <stack>
                     16: #include <vector>
                     17: #include "iasm.h"
                     18: 
                     19: // OSX で iconv はちょっと置いておく
                     20: #if !defined(__APPLE__)
                     21: #define IASM_USE_iconv
                     22: #endif
                     23: 
                     24: #if defined(IASM_USE_iconv)
                     25: #include <iconv.h>
                     26: #elif defined(IASM_USE_wxWidgets)
                     27: #include <wx/wx.h>
                     28: #include <wx/strconv.h>
                     29: #endif
                     30: 
                     31: /*
                     32:  * iconv(3) の第2引数は本来は char** だが (Linux)、
                     33:  * 歴史的経緯により const char** な環境もある (NetBSD、FreeBSD)。
                     34:  */
                     35: #if defined(IASM_ICONV_CONST)
                     36: typedef const char **iconv_src_t;
                     37: #else
                     38: typedef char **iconv_src_t;
                     39: #endif
                     40: 
                     41: #define BUFSIZE        (1024)
                     42: 
                     43: #define D_INOUT        (0x0001)        /* 入出力のみ */
                     44: #define D_EA   (0x0002)        /* EA のみ */
                     45: #define D_LABEL        (0x0004)        /* ラベル関係 */
                     46: #define D_PARSE        (0x0008)        /* パーサ */
                     47: #define D_EXPR (0x0010)        /* 式 */
                     48: #define D_SCAN (0x0020)        /* スキャナ */
                     49: #define D_STAGE        (0x8000)        /* ステージ */
                     50: 
                     51: typedef std::vector<String> ArrayString;
                     52: typedef std::map<String, String> LabelHash;
                     53: typedef void (opfunc_t)(uint16_t);
                     54: typedef std::vector<Token> ArrayToken;
                     55: 
                     56: /* オペランド形式 */
                     57: enum oprand_type_t {
                     58:        OPR_EA = 0,                     /* 最大2つのEA (命令用) */
                     59:        OPR_LIST,                       /* カンマ区切りリスト */
                     60:        OPR_LITERAL,            /* 1つのリテラル */
                     61: };
                     62: 
                     63: /* 命令処理分岐テーブル */
                     64: struct optable_t {
                     65:        const char *opname;             /* 命令語(完全一致) */
                     66:        opfunc_t *func;                 /* 処理関数 */
                     67:        uint16_t opword;                /* 命令ワード */
                     68:        oprand_type_t oprand_type;      /* オペランド形式 */
                     69: };
                     70: 
                     71: /* EA タイプ */
                     72: enum eatype_t {
                     73:        EAT_Dn          = 0x0001,
                     74:        EAT_An          = 0x0002,
                     75:        EAT_AI          = 0x0004,
                     76:        EAT_API         = 0x0008,
                     77:        EAT_APD         = 0x0010,
                     78:        EAT_AREL        = 0x0020,
                     79:        EAT_ABS         = 0x0040,
                     80:        EAT_PCREL       = 0x0080,
                     81:        EAT_IMM         = 0x0100,
                     82: 
                     83:        EAT_ALL         = 0x01ff,
                     84:        EAT_DATA        = (EAT_ALL & ~EAT_An),
                     85:        EAT_CNTL        = (EAT_An | EAT_AREL | EAT_ABS | EAT_PCREL),
                     86: };
                     87: 
                     88: /* EA */
                     89: enum eamode_t {
                     90:        EA_Dn           = 0x00,
                     91:        EA_An           = 0x08,
                     92:        EA_An_I         = 0x10,
                     93:        EA_An_PI        = 0x18,
                     94:        EA_An_PD        = 0x20,
                     95:        EA_d16An        = 0x28,
                     96:        EA_d8AnIX       = 0x30,
                     97:        EA_ABS_W        = 0x38,
                     98:        EA_ABS_L        = 0x39,
                     99:        EA_d16PC        = 0x3a,
                    100:        EA_d8PCIX       = 0x3b,
                    101:        EA_IMMEDIATE = 0x3c,
                    102: };
                    103: 
                    104: class EA {
                    105:  public:
                    106:        int mode;               /* 種別 */
                    107:        uint32_t val;   /* 値。ABS か #imm の場合に使用 */
                    108:        int size;               /* サイズ(バイト数)。#imm の場合に使用 */
                    109:        String label;   /* あれば未解決ラベル。空文字列なら val を使用のこと */
                    110: 
                    111:        EA() {
                    112:                mode = 0;
                    113:                val = 0;
                    114:                size = 0;
                    115:        }
                    116:        int type() const { return (mode >> 3) & 7; };
                    117:        int num()  const { return (mode & 7); };
                    118: };
                    119: 
                    120: /* 参照種別 */
                    121: enum reftype_t {
                    122:        REFTYPE_BYTE,
                    123:        REFTYPE_WORD,
                    124:        REFTYPE_LONG,
                    125: };
                    126: 
                    127: /* 後から参照(式)を解決するための構造体 */
                    128: struct REF {
                    129:        int pos;                        /* 出力位置 */
                    130:        int line;                       /* 現在の行数 */
                    131:        reftype_t type;         /* 種別(サイズ) */
                    132:        ArrayString expr;       /* 中間式 */
                    133: };
                    134: typedef std::vector<REF*> ArrayRef;
                    135: 
                    136: /* サイズサフィックスから bit7-6 がサイズを示すやつ用に変換 */
                    137: const uint16_t size6[] = {
                    138:        0,
                    139:        0x0000, /* 1=.B */
                    140:        0x0040, /* 2=.W */
                    141:        0,
                    142:        0x0080, /* 4=.L */
                    143: };
                    144: 
                    145: /* 出力形式 */
                    146: enum format_t {
                    147:        FORMAT_C,                       /* C ソース */
                    148:        FORMAT_BINARY,          /* バイナリ */
                    149: };
                    150: 
                    151: const char *outfile;           /* 出力ファイル名 */
                    152: FILE *outfp;                           /* 出力ファイル */
                    153: int debug;                                     /* デバッグモード */
                    154: const char *current_infile;    /* 現在の入力ファイル名 */
                    155: int line;                                      /* 現在のファイル中の行数(エラー表示用) */
                    156: format_t format;                       /* 出力形式 */
                    157: uint32_t origin;                       /* 現在のブロックの開始アドレス */
                    158: uint32_t pc;                           /* 現在の PC */
                    159: String label0;                         /* 現在行のラベル */
                    160: String op0;                                    /* 現在の命令語 */
                    161: String size0;                          /* 現在のサイズサフィックス (文字) */
                    162: int size_sfx;                          /* 現在のサイズサフィックス (B=1/W=2/L=4) */
                    163: ArrayString oprand;                    /* 現在のオペランド */
                    164: String current_name;           /* .start で指示された変数名 */
                    165: String outbin;                         /* 現在出力しているバイナリ列 */
                    166: LabelHash label_list;          /* ラベルのリスト */
                    167: ArrayRef ref_list;                     /* ラベルを参照する側のリスト */
                    168: int rept_start;                                /* .rept 開始位置 */
                    169: int rept_count;                                /* .rept 回数 */
                    170: 
                    171: void usage(const char *) __attribute__((__noreturn__));
                    172: int asm_main(const char *);
                    173: void parse_asm(String&);
                    174: void scan_asm(String&, ArrayToken&);
                    175: void parse_token(ArrayToken&);
                    176: void parse_arg_literal(ArrayToken&, ArrayToken::iterator&);
                    177: void parse_arg_list(ArrayToken&, ArrayToken::iterator&);
                    178: void parse_arg_ea(ArrayToken&, ArrayToken::iterator&);
                    179: void include_iocs();
                    180: void add_label(String&);
                    181: bool find_label(String&, uint32_t&);
                    182: optable_t *lookup(String&);
                    183: void format_c();
                    184: void format_binary();
                    185: bool try_ea(String&, EA&, String&, int);
                    186: EA get_ea(String&);
                    187: EA get_ea(String&, int);
                    188: bool get_reglist(String&, uint16_t&);
                    189: int get_cc(String&);
                    190: void output_ea(EA&);
                    191: void add_ref(reftype_t, String&);
                    192: void output_bin(uint32_t, int);
                    193: void output_b(uint32_t);
                    194: void output_w(uint32_t);
                    195: void output_l(uint32_t);
                    196: void output_ds(int);
                    197: String num2str(int);
                    198: String num2hex(int);
                    199: bool parse_number(String&, int*);
                    200: int tonumber(String&);
                    201: bool parse_expr(String&, ArrayString&);
                    202: bool scan_expr(String&, ArrayString&);
                    203: void add_expr(int pos, reftype_t, ArrayString&);
                    204: String parse_string(String&);
                    205: String convert_charset(String&);
                    206: void DPRINTN_ref(int, REF *);
                    207: void DPRINTN_expr(int, ArrayString&);
                    208: bool calc_expr(ArrayString&, uint32_t&, bool);
                    209: void DPRINTV(int, const char *, va_list);
                    210: void DPRINTN(int, const char *, ...);
                    211: void DPRINTF(int, const char *, ...);
                    212: void error(const char *, ...) __attribute__((__noreturn__)); /* エラー出力 */
                    213: void trim(String&);                                    /* 前後の空白を取り除く */
                    214: void ltrim(String&);                           /* 先頭の空白を取り除く */
                    215: void rtrim(String&);                           /* 末尾の空白を取り除く */
                    216: 
                    217: opfunc_t op_cinclude;
                    218: opfunc_t op_org;
                    219: opfunc_t op_start;
                    220: opfunc_t op_end;
                    221: opfunc_t op_dc;
                    222: opfunc_t op_ds;
                    223: opfunc_t op_even;
                    224: opfunc_t op_equ;
                    225: opfunc_t op_rept;
                    226: opfunc_t op_endrept;
                    227: opfunc_t op_iocs;
                    228: opfunc_t op_bcc;
                    229: opfunc_t op_bra;
                    230: opfunc_t op_clr;
                    231: opfunc_t op_dbra;
                    232: opfunc_t op_jmp;
                    233: opfunc_t op_lea;
                    234: opfunc_t op_move;
                    235: opfunc_t op_movem;
                    236: opfunc_t op_moveq;
                    237: opfunc_t op_sub;
                    238: opfunc_t op_suba;
                    239: opfunc_t op_trap;
                    240: opfunc_t op_noarg;
                    241: 
                    242: optable_t optable[] = {
                    243:        { ".cinclude",  op_cinclude,    0,      OPR_LITERAL, },
                    244:        { ".org",               op_org,                 0,      OPR_LIST, },
                    245:        { ".start",             op_start,               0,      OPR_LITERAL, },
                    246:        { ".end",               op_end,                 0,      OPR_LIST, },
                    247:        { ".dc",                op_dc,                  0,      OPR_LIST, },
                    248:        { ".ds",                op_ds,                  0,      OPR_LIST, },
                    249:        { ".even",              op_even,                0,      OPR_LIST, },
                    250:        { ".equ",               op_equ,                 0,      OPR_LIST, },
                    251:        { ".rept",              op_rept,                0,      OPR_LIST, },
                    252:        { ".endrept",   op_endrept,             0,      OPR_LIST, },
                    253: 
                    254:        /* マクロが定義できないのでここでやっちまう */
                    255:        { "IOCS",               op_iocs, },
                    256: 
                    257:        /* XXX BCC.B <cond>,<label> */
                    258:        { "bcc",                op_bcc,         0x6000, },
                    259: 
                    260:        { "bra",                op_bra,         0x6000, },
                    261:        { "clr",                op_clr,         0x4200, },
                    262:        { "dbra",               op_dbra,        0x51c8, },
                    263:        { "jmp",                op_jmp,         0x4ec0, },
                    264:        { "lea",                op_lea,         0x41c0, },
                    265:        { "move",               op_move,        0x0000, },
                    266:        { "movem",              op_movem,       0x4880, },
                    267:        { "moveq",              op_moveq,       0x7000, },
                    268:        { "sub",                op_sub,         0x9000, },
                    269:        { "suba",               op_suba,        0x90c0, },
                    270:        { "trap",               op_trap,        0x4e40, },
                    271: 
                    272:        /* オペランドのないやつ */
                    273:        { "reset",              op_noarg,       0x4e70, },
                    274:        { "nop",                op_noarg,       0x4e71, },
                    275:        { "rte",                op_noarg,       0x4e73, },
                    276:        { "rtd",                op_noarg,       0x4e74, },
                    277:        { "rts",                op_noarg,       0x4e75, },
                    278:        { "trapv",              op_noarg,       0x4e76, },
                    279:        { "rtr",                op_noarg,       0x4e77, },
                    280: 
                    281:        { NULL, NULL, },
                    282: };
                    283: 
                    284: const char *regname[] = {
                    285:        "D0", "D1", "D2", "D3", "D4", "D5", "D6", "D7",
                    286:        "A0", "A1", "A2", "A3", "A4", "A5", "A6", "A7",
                    287:        "(A0)",  "(A1)",  "(A2)",  "(A3)",  "(A4)",  "(A5)",  "(A6)",  "(A7)",
                    288:        "(A0)+", "(A1)+", "(A2)+", "(A3)+", "(A4)+", "(A5)+", "(A6)+", "(A7)+",
                    289:        "-(A0)", "-(A1)", "-(A2)", "-(A3)", "-(A4)", "-(A5)", "-(A6)", "-(A7)",
                    290: };
                    291: 
                    292: const char *ccname[] = {
                    293:        "t",  "f",  "hi", "ls", "cc", "cs", "ne", "eq",
                    294:        "vc", "vs", "pl", "mi", "ge", "lt", "gt", "le",
                    295: };
                    296: 
                    297: const char *iocscall[] = {
                    298:        "_B_KEYINP",    // $00
                    299:        "_B_KEYSNS",    // $01
                    300:        "_B_SFTSNS",    // $02
                    301:        "_KEY_INIT",    // $03
                    302:        "_BITSNS",              // $04
                    303:        "_SKEYSET",             // $05
                    304:        "_LEDCTRL",             // $06
                    305:        "_LEDSET",              // $07
                    306:        "_KEYDLY",              // $08
                    307:        "_KEYREP",              // $09
                    308:        "$0a",                  // $0a
                    309:        "$0b",                  // $0b
                    310:        "_TVCTRL",              // $0c
                    311:        "_LEDMOD",              // $0d
                    312:        "_TGUSEMD",             // $0e
                    313:        "_DEFCHR",              // $0f
                    314:        "_CRTMOD",              // $10
                    315:        "_CONTRAST",    // $11
                    316:        "_HSVTORGB",    // $12
                    317:        "_TPALET",              // $13
                    318:        "_TPALET2",             // $14
                    319:        "_TCOLOR",              // $15
                    320:        "_FNTADR",              // $16
                    321:        "_VRAMGET",             // $17
                    322:        "_VRAMPUT",             // $18
                    323:        "_FNTGET",              // $19
                    324:        "_TEXTGET",             // $1a
                    325:        "_TEXTPUT",             // $1b
                    326:        "_CLIPPUT",             // $1c
                    327:        "_SCROLL",              // $1d
                    328:        "_B_CURON",             // $1e
                    329:        "_B_CUROFF",    // $1f
                    330:        "_B_PUTC",              // $20
                    331:        "_B_PRINT",             // $21
                    332:        "_B_COLOR",             // $22
                    333:        "_B_LOCATE",    // $23
                    334:        "_B_DOWN_S",    // $24
                    335:        "_B_UP_S",              // $25
                    336:        "_B_UP",                // $26
                    337:        "_B_DOWN",              // $27
                    338:        "_B_RIGHT",             // $28
                    339:        "_B_LEFT",              // $29
                    340:        "_B_CLR_ST",    // $2a
                    341:        "_B_ERA_ST",    // $2b
                    342:        "_B_INS",               // $2c
                    343:        "_B_DEL",               // $2d
                    344:        "_B_CONSOL",    // $2e
                    345:        "_B_PUTMES",    // $2f
                    346:        "_SET232C",             // $30
                    347:        "_LOF232C",             // $31
                    348:        "_INP232C",             // $32
                    349:        "_ISNS232C",    // $33
                    350:        "_OSNS232C",    // $34
                    351:        "_OUT232C",             // $35
                    352:        "$36",                  // $36
                    353:        "$37",                  // $37
                    354:        "_SETFNTADR",   // $38
                    355:        "$39",                  // $39
                    356:        "$3a",                  // $3a
                    357:        "_JOYGET",              // $3b
                    358:        "_INIT_PRN",    // $3c
                    359:        "_SNSPRN",              // $3d
                    360:        "_OUTLPT",              // $3e
                    361:        "_OUTPRN",              // $3f
                    362:        "_B_SEEK",              // $40
                    363:        "_B_VERIFY",    // $41
                    364:        "_B_READDI",    // $42
                    365:        "_B_DSKINI",    // $43
                    366:        "_B_DRVSNS",    // $44
                    367:        "_B_WRITE",             // $45
                    368:        "_B_READ",              // $46
                    369:        "_B_RECALI",    // $47
                    370:        "_B_ASSIGN",    // $48
                    371:        "_B_WRITED",    // $49
                    372:        "_B_READID",    // $4a
                    373:        "_B_BADFMT",    // $4b
                    374:        "_B_READDL",    // $4c
                    375:        "_B_FORMAT",    // $4d
                    376:        "_B_DRVCHK",    // $4e
                    377:        "_B_EJECT",             // $4f
                    378:        "_DATEBCD",             // $50
                    379:        "_DATESET",             // $51
                    380:        "_TIMEBCD",             // $52
                    381:        "_TIMESET",             // $53
                    382:        "_DATEGET",             // $54
                    383:        "_DATEBIN",             // $55
                    384:        "_TIMEGET",             // $56
                    385:        "_TIMEBIN",             // $57
                    386:        "_DATECNV",             // $58
                    387:        "_TIMECNV",             // $59
                    388:        "_DATEASC",             // $5a
                    389:        "_TIMEASC",             // $5b
                    390:        "_DAYASC",              // $5c
                    391:        "_ALARMMOD",    // $5d
                    392:        "_ALARMSET",    // $5e
                    393:        "_ALARMGET",    // $5f
                    394:        "_ADPCMOUT",    // $60
                    395:        "_ADPCMINP",    // $61
                    396:        "_ADPCMAOT",    // $62
                    397:        "_ADPCMAIN",    // $63
                    398:        "_ADPCMLOT",    // $64
                    399:        "_ADPCMLIN",    // $65
                    400:        "_ADPCMSNS",    // $66
                    401:        "_ADPCMMOD",    // $67
                    402:        "_OPMSET",              // $68
                    403:        "_OPMSNS",              // $69
                    404:        "_OPMINTST",    // $6a
                    405:        "_TIMERDST",    // $6b
                    406:        "_VDISPST",             // $6c
                    407:        "_CRTCRAS",             // $6d
                    408:        "_HSYNCST",             // $6e
                    409:        "_PRNINTST",    // $6f
                    410:        "_MS_INIT",             // $70
                    411:        "_MS_CURON",    // $71
                    412:        "_MS_CUROF",    // $72
                    413:        "_MS_STAT",             // $73
                    414:        "_MS_GETDT",    // $74
                    415:        "_MS_CURGT",    // $75
                    416:        "_MS_CURST",    // $76
                    417:        "_MS_LIMIT",    // $77
                    418:        "_MS_OFFTM",    // $78
                    419:        "_MS_ONTM",             // $79
                    420:        "_MS_PATST",    // $7a
                    421:        "_MS_SEL",              // $7b
                    422:        "_MS_SEL2",             // $7c
                    423:        "_SKEY_MOD",    // $7d
                    424:        "_DENSNS",              // $7e
                    425:        "_ONTIME",              // $7f
                    426:        "_B_INTVCS",    // $80
                    427:        "_B_SUPER",             // $81
                    428:        "_B_BPEEK",             // $82
                    429:        "_B_WPEEK",             // $83
                    430:        "_B_LPEEK",             // $84
                    431:        "_B_MEMSTR",    // $85
                    432:        "_B_BPOKE",             // $86
                    433:        "_B_WPOKE",             // $87
                    434:        "_B_LPOKE",             // $88
                    435:        "_B_MEMSET",    // $89
                    436:        "_DMAMOVE",             // $8a
                    437:        "_DMAMOV_A",    // $8b
                    438:        "_DMAMOV_L",    // $8c
                    439:        "_DMAMODE",             // $8d
                    440:        "_BOOTINF",             // $8e
                    441:        "_ROMVER",              // $8f
                    442:        "_G_CLR_ON",    // $90
                    443:        "$91",                  // $91
                    444:        "$92",                  // $92
                    445:        "$93",                  // $93
                    446:        "_GPALET",              // $94
                    447:        "$95",                  // $95
                    448:        "$96",                  // $96
                    449:        "$97",                  // $97
                    450:        "$98",                  // $98
                    451:        "$99",                  // $99
                    452:        "$9a",                  // $9a
                    453:        "$9b",                  // $9b
                    454:        "$9c",                  // $9c
                    455:        "", "", "",
                    456:        "_SFTJIS",              // $a0
                    457:        "_JISSFT",              // $a1
                    458:        "_AKCONV",              // $a2
                    459:        "_RMACNV",              // $a3
                    460:        "_DAKJOB",              // $a4
                    461:        "_HANJOB",              // $a5
                    462:        "", "", "",
                    463:        "", "", "",
                    464:        "_SYS_STAT",    // $ac
                    465:        "_B_CONMOD",    // $ad
                    466:        "_OS_CURON",    // $ae
                    467:        "_OS_CUROF",    // $af
                    468:        "_DRAWMODE",    // $b0
                    469:        "_APAGE",               // $b1
                    470:        "_VPAGE",               // $b2
                    471:        "_HOME",                // $b3
                    472:        "_WINDOW",              // $b4
                    473:        "_WIPE",                // $b5
                    474:        "_PSET",                // $b6
                    475:        "_POINT",               // $b7
                    476:        "_LINE",                // $b8
                    477:        "_BOX",                 // $b9
                    478:        "_FILL",                // $ba
                    479:        "_CIRCLE",              // $bb
                    480:        "_PAINT",               // $bc
                    481:        "_SYMBOL",              // $bd
                    482:        "_GETGRM",              // $be
                    483:        "_PUTGRM",              // $bf
                    484:        "_SP_INIT",             // $c0
                    485:        "_SP_ON",               // $c1
                    486:        "_SP_OFF",              // $c2
                    487:        "_SP_CGCLR",    // $c3
                    488:        "_SP_DEFCG",    // $c4
                    489:        "_SP_GTPCG",    // $c5
                    490:        "_SP_REGST",    // $c6
                    491:        "_SP_REGGT",    // $c7
                    492:        "_BGSCRLST",    // $c8
                    493:        "_BGSCRLGT",    // $c9
                    494:        "_BGCTRLST",    // $ca
                    495:        "_BGCTRLGT",    // $cb
                    496:        "_BGTEXTCL",    // $cc
                    497:        "_BGTEXTST",    // $cd
                    498:        "_BGTEXTGT",    // $ce
                    499:        "_SPALET",              // $cf
                    500:        "", "", "",
                    501:        "_TXXLINE",             // $d3
                    502:        "_TXYLINE",             // $d4
                    503:        "_TXLINE",              // $d5
                    504:        "_TXBOX",               // $d6
                    505:        "_TXFILL",              // $d7
                    506:        "_TXREV",               // $d8
                    507:        "", "", "",
                    508:        "", "", "",
                    509:        "_TXRASCPY",    // $df
                    510:        "", "", "", "",
                    511:        "", "", "", "",
                    512:        "", "", "", "",
                    513:        "", "", "", "",
                    514:        "_OPMDRV",              // $f0
                    515:        "_RSDRV",               // $f1
                    516:        "_A_JOYGET",    // $f2
                    517:        "_MUSICDRV",    // $f3
                    518:        "",
                    519:        "_SCSIDRV",             // $f5
                    520:        "", "", "", "",
                    521:        "", "", "",
                    522:        "_ABORTRST",    // $fd
                    523:        "_IPLERR",              // $fe
                    524:        "_ABORTJOB",    // $ff
                    525: };
                    526: 
                    527: void
                    528: usage(const char *progname)
                    529: {
                    530: #if defined(_WIN32)
                    531:        const char *conv = "Win32";
                    532: #elif defined(IASM_USE_iconv)
                    533:        const char *conv = "iconv";
                    534: #elif defined(IASM_USE_wxWidgets)
                    535:        const char *conv = "wxWidgets";
                    536: #else
                    537:        const char *conv = "none";
                    538: #endif
                    539: 
                    540:        fprintf(stderr, "usage: %s [-d] [-f <fmt>] <infile> [<outfile>]\n",
                    541:                progname);
                    542:        fprintf(stderr, "  -f <fmt>   output format: c, binary\n");
                    543:        fprintf(stderr, "compile option: charset conversion '%s'\n", conv);
                    544:        exit(1);
                    545: }
                    546: 
                    547: int
                    548: main(int ac, char *av[])
                    549: {
                    550:        const char *progname;
                    551:        const char *infile;
                    552:        int c;
                    553: 
                    554:        progname = av[0];
                    555:        while ((c = getopt(ac, av, "d:f:")) != -1) {
                    556:                switch (c) {
                    557:                 case 'd':
                    558:                        debug = strtol(optarg, NULL, 16);
                    559:                        break;
                    560:                 case 'f':
                    561:                        if (strcasecmp(optarg, "c") == 0) {
                    562:                                format = FORMAT_C;
                    563:                        } else if (strcasecmp(optarg, "binary") == 0) {
                    564:                                format = FORMAT_BINARY;
                    565:                        } else {
                    566:                                usage(progname);
                    567:                        }
                    568:                        break;
                    569:                 default:
                    570:                        usage(progname);
                    571:                        break;
                    572:                }
                    573:        }
                    574:        ac -= optind;
                    575:        av += optind;
                    576: 
                    577:        /* デバッグ指定が1つでもあれば STAGE を必ず有効にする */
                    578:        if (debug > 0) {
                    579:                debug |= D_STAGE;
                    580:        }
                    581: 
                    582:        if (ac < 1) {
                    583:                usage(progname);
                    584:        }
                    585:        infile = av[0];
                    586: 
                    587:        if (ac > 1) {
                    588:                outfile = av[1];
                    589:                outfp = fopen(outfile, "wb");
                    590:                if (outfp == NULL) {
                    591:                        fprintf(stderr, "cannot open outfile: %s\n", outfile);
                    592:                        exit(1);
                    593:                }
                    594:        } else {
                    595:                outfile = NULL;
                    596:                outfp = stdout;
                    597:        }
                    598: 
                    599:        /* IOCS コールマクロを定義 */
                    600:        include_iocs();
                    601: 
                    602:        /* メイン処理 */
                    603:        asm_main(infile);
                    604: 
                    605:        if (outfp != stdout) {
                    606:                fclose(outfp);
                    607:        }
                    608: }
                    609: 
                    610: int
                    611: asm_main(const char *infile)
                    612: {
                    613:        FILE *fp;
                    614:        char cbuf[1024];
                    615: 
                    616:        /* ファイルオープン */
                    617:        fp = fopen(infile, "r");
                    618:        if (fp == NULL) {
                    619:                fprintf(stderr, "cannot open %s", infile);
                    620:                exit(1);
                    621:        }
                    622:        current_infile = infile;
                    623: 
                    624:        /* 1st ステージ: 読み込みながら処理 */
                    625:        line = 0;
                    626:        while (fgets(cbuf, sizeof(cbuf), fp)) {
                    627:                String buf(cbuf);
                    628:                line++;
                    629: 
                    630:                rtrim(buf);
                    631:                DPRINTF(D_INOUT, "line %3d |%s|\n", ::line, buf.c_str());
                    632: 
                    633:                /* 1命令処理 */
                    634:                parse_asm(buf);
                    635:        }
                    636: 
                    637:        fclose(fp);
                    638:        return 0;
                    639: }
                    640: 
                    641: /* 1命令処理 */
                    642: void
                    643: parse_asm(String& buf)
                    644: {
                    645:        ArrayToken token_list;
                    646: 
                    647:        /* 字句解析 */
                    648:        scan_asm(buf, token_list);
                    649: 
                    650:        /* 構文解析(?)して分岐 */
                    651:        parse_token(token_list);
                    652: }
                    653: 
                    654: /* 入力の1行 src を字句解析して結果を token_list に返す */
                    655: void
                    656: scan_asm(String& src, ArrayToken& token_list)
                    657: {
                    658:        Scanner s(src);
                    659: 
                    660:        for (;;) {
                    661:                Token t;
                    662: 
                    663:                if (!s.get_token(t)) {
                    664:                        error("syntax error: %s", s.errmsg.c_str());
                    665:                }
                    666: 
                    667:                token_list.push_back(t);
                    668: 
                    669:                if (t.type == T_END) {
                    670:                        break;
                    671:                }
                    672:        }
                    673: 
                    674:        /* 行末(T_ENDの前)が空白なら削除 */
                    675:        if (token_list.size() > 1) {
                    676:                ArrayToken::iterator it = token_list.end();
                    677:                advance(it, -2);
                    678:                if ((*it).type == T_SPACE) {
                    679:                        token_list.erase(it);
                    680:                }
                    681:        }
                    682: 
                    683:        if ((debug & D_SCAN)) {
                    684:                for (int i = 0; i < token_list.size(); i++) {
                    685:                        Token t = token_list[i];
                    686: 
                    687:                        DPRINTF(D_SCAN, " %-7s |%s|", t.type_name(), t.word.c_str());
                    688:                        if (t.type == T_NUMBER || t.type == T_SIZE || t.type == T_CHAR) {
                    689:                                DPRINTN(D_SCAN, " num=$%x", t.number);
                    690:                        }
                    691:                        DPRINTN(D_SCAN, "\n");
                    692:                }
                    693:        }
                    694: }
                    695: 
                    696: /* トークン列をパースして処理する */
                    697: void
                    698: parse_token(ArrayToken& list)
                    699: {
                    700:        ArrayToken::iterator t;
                    701: 
                    702:        /* 命令処理前にグローバル変数をクリア */
                    703:        label0.erase();
                    704:        op0.erase();
                    705:        size0.erase();
                    706:        size_sfx = -1;
                    707:        oprand.clear();
                    708: 
                    709:        /* 先頭がリテラルならラベル */
                    710:        t = list.begin();
                    711:        if ((*t).type == T_LITERAL) {
                    712:                /* ラベルをリストに記憶 */
                    713:                DPRINTF(D_PARSE, "label='%s'\n", (*t).word.c_str());
                    714:                label0 = (*t).word;
                    715:                add_label(label0);
                    716:                t++;
                    717: 
                    718:                /* 直後がコロンならスペースに置き換えてから */
                    719:                if ((*t).type == T_COLON) {
                    720:                        (*t).type = T_SPACE;
                    721:                        t++;
                    722:                }
                    723:        }
                    724: 
                    725:        /* ラベルのみならここで終わり */
                    726:        if ((*t).type == T_END) {
                    727:                return;
                    728:        }
                    729:        /* そうでなければスペースのはずなので読み飛ばす */
                    730:        if ((*t).type == T_SPACE) {
                    731:                t++;
                    732:        }
                    733: 
                    734:        /* 命令語は必ずリテラルから始まっている */
                    735:        if ((*t).type != T_LITERAL) {
                    736:                error("syntax error: invalid opword: %s\n", (*t).word.c_str());
                    737:        }
                    738:        /* 命令語を取り出す */
                    739:        op0 = (*t).word;
                    740:        t++;
                    741: 
                    742:        /* 直後がサイズサフィックスなら記憶 */
                    743:        if ((*t).type == T_SIZE) {
                    744:                size0 = (*t).word;
                    745:                size_sfx = (*t).number;
                    746:                t++;
                    747:        }
                    748:        DPRINTF(D_PARSE, "op0='%s' %s(%d)\n",
                    749:                op0.c_str(), size0.c_str(), size_sfx);
                    750: 
                    751:        /* オペランドなしならここで終わり。ありなら空白のはず */
                    752:        if ((*t).type == T_END) {
                    753:                /* XXX 分岐は実行しないといけないのでこのまま進む */
                    754:                //return;
                    755:        } else if ((*t).type != T_SPACE) {
                    756:                error("syntax error: after opword: %s\n", (*t).word.c_str());
                    757:        }
                    758:        t++;
                    759: 
                    760:        /* 命令語からオペランド種別を取り出す */
                    761:        optable_t *opt = lookup(op0);
                    762:        if (opt == NULL) {
                    763:                error("unknown opcode: %s\n", op0.c_str());
                    764:        }
                    765:        switch (opt->oprand_type) {
                    766:         case OPR_EA:           /* 通常命令用の EA */
                    767:                parse_arg_ea(list, t);
                    768:                break;
                    769:         case OPR_LIST:         /* カンマ区切りリスト */
                    770:                parse_arg_list(list, t);
                    771:                break;
                    772:         case OPR_LITERAL:      /* 書式なし1つの引数 */
                    773:                parse_arg_literal(list, t);
                    774:                break;
                    775:         default:
                    776:                error("unknown oprand_type=%d (op=%s)\n",
                    777:                        opt->oprand_type, op0.c_str());
                    778:                break;
                    779:        }
                    780:        DPRINTF(D_PARSE, "oprand.size=%d", oprand.size());
                    781:        for (int i = 0; i < oprand.size(); i++) {
                    782:                DPRINTN(D_PARSE, " '%s'", oprand[i].c_str());
                    783:        }
                    784:        DPRINTN(D_PARSE, "\n");
                    785: 
                    786:        /* 命令語によって分岐 */
                    787:        opt->func(opt->opword);
                    788: }
                    789: 
                    790: /* オペランドを書式なしとしてパース。全部結合するだけ */
                    791: void
                    792: parse_arg_literal(ArrayToken& list, ArrayToken::iterator& t)
                    793: {
                    794:        String arg;
                    795: 
                    796:        DPRINTF(D_PARSE, "parse_arg_literal\n");
                    797: 
                    798:        for (; t != list.end(); t++) {
                    799:                if ((*t).type == T_END) {
                    800:                        break;
                    801:                }
                    802:                arg += (*t).word;
                    803:        }
                    804:        oprand.push_back(arg);
                    805: }
                    806: 
                    807: /* 疑似命令用のオペランド(カンマ区切りリスト)をパース */
                    808: void
                    809: parse_arg_list(ArrayToken& list, ArrayToken::iterator& t)
                    810: {
                    811:        String arg;
                    812: 
                    813:        DPRINTF(D_PARSE, "parse_arg_list\n");
                    814: 
                    815:        for (; t != list.end(); t++) {
                    816:                if ((*t).type == T_COMMA || (*t).type == T_END) {
                    817:                        oprand.push_back(arg);
                    818:                        arg.clear();
                    819:                } else if ((*t).type != T_SPACE) {
                    820:                        arg += (*t).word;
                    821:                }
                    822:        }
                    823: }
                    824: 
                    825: /* 命令のオペランド (EA) をパース */
                    826: void
                    827: parse_arg_ea(ArrayToken& list, ArrayToken::iterator& t)
                    828: {
                    829:        DPRINTF(D_PARSE, "parse_arg_ea\n");
                    830: #if 1
                    831:        /* XXX オペランドはとりあえず旧パーサの動作をシミュレートしておく */
                    832:        String arg;
                    833:        for (; t != list.end(); t++) {
                    834:                if ((*t).type == T_COMMA || (*t).type == T_END) {
                    835:                        oprand.push_back(arg);
                    836:                        arg.clear();
                    837:                } else if ((*t).type != T_SPACE) {
                    838:                        arg += (*t).word;
                    839:                }
                    840:        }
                    841: #endif
                    842: }
                    843: 
                    844: /* IOCS コールマクロを定義 */
                    845: void
                    846: include_iocs()
                    847: {
                    848:        std::pair<LabelHash::iterator, bool> r;
                    849: 
                    850:        for (int i = 0; i < countof(iocscall); i++) {
                    851:                String name(iocscall[i]);
                    852:                if (name.size() == 0 || name[0] == '$') {
                    853:                        continue;
                    854:                }
                    855:                String var = num2hex(i);
                    856: 
                    857:                r = label_list.insert(std::make_pair(name, var));
                    858:                if (r.second == 0) {
                    859:                        error("iocscall macro '%s' is duplicated\n", name.c_str());
                    860:                }
                    861:                //DPRINTF(D_LABEL, "LABEL '%s' <= '%s'\n", name.c_str(), var.c_str());
                    862:        }
                    863: }
                    864: 
                    865: /* ラベルをリストに記憶 */
                    866: void
                    867: add_label(String& label)
                    868: {
                    869:        std::pair<LabelHash::iterator, bool> r;
                    870:        String addr;
                    871: 
                    872:        addr = num2hex(::pc);
                    873:        r = label_list.insert(std::make_pair(label, addr));
                    874:        if (r.second == 0) {
                    875:                error("label '%s' is duplicated\n", label.c_str());
                    876:        }
                    877:        DPRINTF(D_LABEL, "LABEL '%s' <= '%s'\n", label.c_str(), addr.c_str());
                    878: }
                    879: 
                    880: /*
                    881:  * リストからラベルを探索。
                    882:  * 見付かれば var に置換後の文字列を格納して true を返す。
                    883:  * 見付からなければ false を返す。
                    884:  */
                    885: bool
                    886: find_label(String& label, String& var)
                    887: {
                    888:        LabelHash::iterator i;
                    889: 
                    890:        i = label_list.find(label);
                    891:        if (i == label_list.end()) {
                    892:                DPRINTF(D_LABEL, "'%s' => NOT FOUND\n", label.c_str());
                    893:                return false;
                    894:        }
                    895:        var = (*i).second;
                    896:        DPRINTF(D_LABEL, "'%s' => '%s'\n", label.c_str(), var.c_str());
                    897:        return true;
                    898: }
                    899: 
                    900: /* 命令をテーブルから検索 */
                    901: optable_t *
                    902: lookup(String& op)
                    903: {
                    904:        optable_t *t;
                    905: 
                    906:        for (t = optable; t->opname; t++) {
                    907:                if (strcasecmp(op.c_str(), t->opname) == 0) {
                    908:                        return t;
                    909:                }
                    910:        }
                    911:        return NULL;
                    912: }
                    913: 
                    914: /* .cinclude 擬似命令 */
                    915: void
                    916: op_cinclude(uint16_t opword)
                    917: {
                    918:        if (format == FORMAT_C) {
                    919:                fprintf(outfp, "#include %s\n", oprand[0].c_str());
                    920:        }
                    921: }
                    922: 
                    923: /* .org 擬似命令 */
                    924: void
                    925: op_org(uint16_t opword)
                    926: {
                    927:        if (oprand.size() != 1) {
                    928:                error(".org must have 1 oprand\n");
                    929:        }
                    930:        origin = tonumber(oprand[0]);
                    931:        pc = origin;
                    932:        DPRINTF(D_INOUT, "set origin=%06X\n", origin);
                    933: }
                    934: 
                    935: /* .start 擬似命令 */
                    936: void
                    937: op_start(uint16_t opword)
                    938: {
                    939:        /* C出力なら引数が必要。書式が変か… */
                    940:        if (format == FORMAT_C) {
                    941:                if (oprand.size() < 1) {
                    942:                        error(".start needs 1 oprand for C output\n");
                    943:                }
                    944:                current_name = oprand[0];
                    945:        }
                    946: 
                    947:        outbin.erase();
                    948:        rept_start = -1;
                    949:        rept_count = 0;
                    950: }
                    951: 
                    952: /* .end 擬似命令 */
                    953: void
                    954: op_end(uint16_t opword)
                    955: {
                    956:        /* 出力は必ずワード単位にする */
                    957:        op_even(0);
                    958: 
                    959:        /* 2nd ステージ (ラベルの解決) */
                    960:        DPRINTN(D_STAGE, "\n2nd stage\n");
                    961:        for (ArrayRef::iterator i = ref_list.begin(); i != ref_list.end(); ) {
                    962:                uint32_t uval;
                    963:                int val;
                    964: 
                    965:                /* 構造体を取り出す */
                    966:                REF *ref = *i;
                    967:                DPRINTN_ref(D_INOUT, ref);
                    968: 
                    969:                line = ref->line;
                    970: 
                    971:                /* 値を計算。ラベルが解決できなければ向こうでエラーにする */
                    972:                calc_expr(ref->expr, uval, true);
                    973:                val = uval;
                    974: 
                    975:                /* 種別ごとに範囲チェックして出力 */
                    976: DPRINTF(D_INOUT, "val=%d\n", val);
                    977:                switch (ref->type) {
                    978:                 case REFTYPE_BYTE:
                    979:                        if (val > 127 || val < -128) {
                    980:                                ::line = ref->line;
                    981:                                error("%d is insufficient in byte data\n", val);
                    982:                        }
                    983:                        DPRINTF(D_INOUT, "pos=%d => $%02x\n", ref->pos, val & 0xff);
                    984:                        outbin[ref->pos] = val;
                    985:                        break;
                    986: 
                    987:                 case REFTYPE_WORD:
                    988:                        if (val > 32767 || val < -32768) {
                    989:                                ::line = ref->line;
                    990:                                error("%d is insufficient in word data\n\n", val);
                    991:                        }
                    992:                        DPRINTF(D_INOUT, "pos=%d => $%04x\n", ref->pos, val & 0xffff);
                    993:                        outbin[ref->pos    ] = (val >> 8);
                    994:                        outbin[ref->pos + 1] = (val & 0xff);
                    995:                        break;
                    996: 
                    997:                 case REFTYPE_LONG:
                    998:                        DPRINTF(D_INOUT, "pos=%d => $%08x\n", ref->pos, val);
                    999:                        outbin[ref->pos    ] = (val >> 24) & 0xff;
                   1000:                        outbin[ref->pos + 1] = (val >> 16) & 0xff;
                   1001:                        outbin[ref->pos + 2] = (val >> 8)  & 0xff;
                   1002:                        outbin[ref->pos + 3] =  val & 0xff;
                   1003:                        break;
                   1004: 
                   1005:                 default:
                   1006:                        error("unsupported reftype: %d\n", (int)ref->type);
                   1007:                        break;
                   1008:                }
                   1009: 
                   1010:                /* 解決したので削除 */
                   1011:                ref_list.erase(i);
                   1012:                delete ref;
                   1013:        }
                   1014: 
                   1015:        /* 3rd ステージというか出力 */
                   1016:        DPRINTN(D_STAGE, "\n3rd stage\n");
                   1017:        switch (format) {
                   1018:         case FORMAT_C:
                   1019:                format_c();
                   1020:                break;
                   1021:         case FORMAT_BINARY:
                   1022:                format_binary();
                   1023:                break;
                   1024:        }
                   1025: 
                   1026:        DPRINTN(D_STAGE, "\n3rd stage end\n\n");
                   1027: }
                   1028: 
                   1029: /* Cソース形式で出力 */
                   1030: void
                   1031: format_c()
                   1032: {
                   1033:        fprintf(outfp, "\n");
                   1034:        fprintf(outfp, "const BYTE %s[] = {", current_name.c_str());
                   1035:        for (int i = 0; i < outbin.size(); i++) {
                   1036:                if ((i % 8) == 0) {
                   1037:                        fprintf(outfp, "\n\t");
                   1038:                }
                   1039:                fprintf(outfp, "0x%02x,", (uint8_t)outbin[i]);
                   1040:        }
                   1041:        fprintf(outfp, "\n};\n");
                   1042:        fprintf(outfp, "const int %s_size = %d;\n",
                   1043:                current_name.c_str(), (int)outbin.size());
                   1044: }
                   1045: 
                   1046: /* バイナリ形式で出力 */
                   1047: void
                   1048: format_binary()
                   1049: {
                   1050:        String buf;
                   1051:        int n;
                   1052: 
                   1053:        n = 0;
                   1054:        for (;;) {
                   1055:                buf = outbin.substr(n, 4096);
                   1056:                if (buf.size() == 0) {
                   1057:                        break;
                   1058:                }
                   1059: 
                   1060:                fwrite(buf.c_str(), 1, buf.size(), outfp);
                   1061:                n += buf.size();
                   1062:        }
                   1063: }
                   1064: 
                   1065: /* .dc 擬似命令 */
                   1066: void
                   1067: op_dc(uint16_t opword)
                   1068: {
                   1069:        ArrayString::iterator i;
                   1070:        for (i = oprand.begin(); i != oprand.end(); i++) {
                   1071:                String arg = *i;
                   1072: 
                   1073:                /* .b でダブルクォートから始まってたら文字列 */
                   1074:                if (size_sfx == 1 && arg[0] == '\x22') {
                   1075:                        /* 文字列を解析 */
                   1076:                        String str = parse_string(arg);
                   1077: 
                   1078:                        /* 日本語文字コードを変換 */
                   1079:                        str = convert_charset(str);
                   1080: 
                   1081:                        for (int j = 0; j < str.size(); j++) {
                   1082:                                output_b(str[j]);
                   1083:                        }
                   1084: 
                   1085:                } else if (size_sfx == 1 && arg[0] == '\'') {
                   1086:                        /* XXX まだこれには対応できないので旧方式で対応 */
                   1087:                        output_b(tonumber(arg));
                   1088: 
                   1089:                } else {
                   1090:                        /* そうでなければ式として評価 */
                   1091:                        ArrayString expr;
                   1092:                        uint32_t val;
                   1093:                        parse_expr(*i, expr);
                   1094:                        if (calc_expr(expr, val, false)) {
                   1095:                                /* 解決できたので出力 */
                   1096:                                output_bin(val, size_sfx);
                   1097:                        } else {
                   1098:                                /* 解決できなかった */
                   1099:                                switch (size_sfx) {
                   1100:                                 case 1:
                   1101:                                        add_expr(::outbin.size(), REFTYPE_BYTE, expr);
                   1102:                                        break;
                   1103:                                 case 2:
                   1104:                                        add_expr(::outbin.size(), REFTYPE_WORD, expr);
                   1105:                                        break;
                   1106:                                 case 4:
                   1107:                                        add_expr(::outbin.size(), REFTYPE_LONG, expr);
                   1108:                                        break;
                   1109:                                 default:
                   1110:                                        abort();
                   1111:                                }
                   1112:                                output_bin(0, size_sfx);
                   1113:                        }
                   1114:                }
                   1115:        }
                   1116: }
                   1117: 
                   1118: /* .ds 擬似命令 */
                   1119: void
                   1120: op_ds(uint16_t opword)
                   1121: {
                   1122:        ArrayString::iterator i;
                   1123:        for (i = oprand.begin(); i != oprand.end(); i++) {
                   1124:                int size = tonumber(*i);
                   1125:                output_ds(size * size_sfx);
                   1126:        }
                   1127: }
                   1128: 
                   1129: /* .even 擬似命令 */
                   1130: void
                   1131: op_even(uint16_t opword)
                   1132: {
                   1133:        /* 奇数なら偶数に合わせる */
                   1134:        if ((outbin.size() & 1)) {
                   1135:                output_b(0);
                   1136:        }
                   1137: }
                   1138: 
                   1139: /* .equ 擬似命令 */
                   1140: void
                   1141: op_equ(uint16_t opword)
                   1142: {
                   1143:        if (label0.empty()) {
                   1144:                error(".equ must have a label\n");
                   1145:        }
                   1146:        if (oprand.size() != 1) {
                   1147:                error(".equ must have 1 oprand\n");
                   1148:        }
                   1149: 
                   1150:        /* ラベルの値を PC ではなくオペランド指定の値に差し替える */
                   1151:        LabelHash::iterator i;
                   1152:        /* 見付からないはずはないのでエラー処理省略? */
                   1153:        i = label_list.find(label0);
                   1154:        (*i).second = oprand[0];
                   1155:        DPRINTF(D_LABEL, "LABEL '%s' EQU '%s'\n",
                   1156:                (*i).first.c_str(), (*i).second.c_str());
                   1157: }
                   1158: 
                   1159: /* .rept 擬似命令 */
                   1160: void
                   1161: op_rept(uint16_t opword)
                   1162: {
                   1163:        ArrayString expr;
                   1164:        uint32_t cnt;
                   1165: 
                   1166:        if (rept_start != -1) {
                   1167:                error(".rept duplicated\n");
                   1168:        }
                   1169: 
                   1170:        /* ここを記憶しておくだけ */
                   1171:        rept_start = outbin.size();
                   1172:        /* 回数は <式> で、この時点で解決できなければいけない */
                   1173:        parse_expr(oprand[0], expr);
                   1174:        calc_expr(expr, cnt, true);
                   1175:        rept_count = cnt;
                   1176: 
                   1177:        DPRINTF(D_INOUT, ".rept start=$%x count=$%x\n",
                   1178:                rept_start, rept_count);
                   1179: }
                   1180: 
                   1181: /* .endrept 擬似命令 */
                   1182: /* XXX 最終的には HAS に合わせて endm にしたい */
                   1183: void
                   1184: op_endrept(uint16_t opword)
                   1185: {
                   1186:        String target;
                   1187:        int rept_size;
                   1188:        int total_size;
                   1189: 
                   1190:        if (rept_start == -1) {
                   1191:                error(".endrept without .rept\n");
                   1192:        }
                   1193: 
                   1194:        /* .rept の位置からここまでの内容を取得 */
                   1195:        rept_size = outbin.size() - rept_start;
                   1196:        target = outbin.substr(rept_start, rept_size);
                   1197: 
                   1198:        /* それを (rept_count-1) 回出力。1回目はすでに出力してあるから */
                   1199:        rept_count--;
                   1200:        for (int i = 0; i < rept_count; i++) {
                   1201:                outbin += target;
                   1202:        }
                   1203: 
                   1204:        total_size = rept_size * rept_count;
                   1205:        pc += total_size;
                   1206:        DPRINTF(D_INOUT, "output $%x(%d) bytes x $%x(%d) = $%x(%d) bytes\n",
                   1207:                rept_size, rept_size,
                   1208:                rept_count, rept_count,
                   1209:                total_size, total_size);
                   1210: 
                   1211:        /* パラメータをクリア */
                   1212:        rept_count = 0;
                   1213:        rept_start = -1;
                   1214: }
                   1215: 
                   1216: /* IOCS マクロ命令 */
                   1217: void
                   1218: op_iocs(uint16_t opword)
                   1219: {
                   1220:        char moveqbuf[32];
                   1221:        int num;
                   1222: 
                   1223:        num = tonumber(oprand[0]) & 0xff;
                   1224:        snprintf(moveqbuf, sizeof(moveqbuf), " moveq.l #$%x,d0", num);
                   1225:        String moveq(moveqbuf);
                   1226:        String trap(" trap #15");
                   1227: 
                   1228:        parse_asm(moveq);
                   1229:        parse_asm(trap);
                   1230: }
                   1231: 
                   1232: /* bcc */
                   1233: /* XXX Bcc.b <cond>,<label> というニーモニックにする */
                   1234: void
                   1235: op_bcc(uint16_t opword)
                   1236: {
                   1237:        int cc;
                   1238: 
                   1239:        /* bra/bcc だけ .s を .b に読み替えて認める */
                   1240:        if (size_sfx == 0 && tolower(size0[1]) == 's') {
                   1241:                size_sfx = 1;
                   1242:        }
                   1243: 
                   1244:        if (size_sfx == 1) {
                   1245:                cc = get_cc(oprand[0]);
                   1246:                add_ref(REFTYPE_BYTE, oprand[1]);
                   1247: 
                   1248:                opword |= cc << 8;
                   1249:                output_w(opword);
                   1250:        } else {
                   1251:                error("unsupported size: %s%s\n", op0.c_str(), size0.c_str());
                   1252:        }
                   1253: }
                   1254: 
                   1255: /* bra */
                   1256: void
                   1257: op_bra(uint16_t opword)
                   1258: {
                   1259:        /* bra/bcc だけ .s を .b に読み替えて認める */
                   1260:        if (size_sfx == 0 && tolower(size0[1]) == 's') {
                   1261:                size_sfx = 1;
                   1262:        }
                   1263: 
                   1264:        if (size_sfx == 1) {
                   1265:                add_ref(REFTYPE_BYTE, oprand[0]);
                   1266:                output_w(opword);
                   1267:        } else {
                   1268:                error("unsupported size: %s%s\n", op0.c_str(), size0.c_str());
                   1269:        }
                   1270: }
                   1271: 
                   1272: /* clr */
                   1273: void
                   1274: op_clr(uint16_t opword)
                   1275: {
                   1276:        EA dst;
                   1277: 
                   1278:        dst = get_ea(oprand[0]);
                   1279: 
                   1280:        opword |= dst.mode | size6[size_sfx];
                   1281: 
                   1282:        output_w(opword);
                   1283:        output_ea(dst);
                   1284: }
                   1285: 
                   1286: /* dbra */
                   1287: void
                   1288: op_dbra(uint16_t opword)
                   1289: {
                   1290:        EA src;
                   1291: 
                   1292:        src = get_ea(oprand[0]);
                   1293:        add_ref(REFTYPE_WORD, oprand[1]);
                   1294: 
                   1295:        opword |= src.num();
                   1296: 
                   1297:        output_w(opword);
                   1298:        output_w(0);
                   1299: }
                   1300: 
                   1301: /* jmp */
                   1302: void
                   1303: op_jmp(uint16_t opword)
                   1304: {
                   1305:        EA dst;
                   1306: 
                   1307:        dst = get_ea(oprand[0]);
                   1308: 
                   1309:        output_w(opword | dst.mode);
                   1310:        output_ea(dst);
                   1311: }
                   1312: 
                   1313: /* lea.l */
                   1314: void
                   1315: op_lea(uint16_t opword)
                   1316: {
                   1317:        EA src, dst;
                   1318: 
                   1319:        if (size_sfx == -1) {
                   1320:                size_sfx = 4;
                   1321:        }
                   1322:        if (size_sfx != 4) {
                   1323:                error("invalid opcode: %s%s\n", op0.c_str(), size0.c_str());
                   1324:        }
                   1325: 
                   1326:        src = get_ea(oprand[0]);
                   1327:        dst = get_ea(oprand[1]);
                   1328: 
                   1329:        if (dst.type() != 0x01) {
                   1330:                error("syntax error: LEA dst must be An\n");
                   1331:        }
                   1332: 
                   1333:        opword |= src.mode;
                   1334:        opword |= dst.num() << 9;
                   1335: 
                   1336:        output_w(opword);
                   1337:        output_ea(src);
                   1338: }
                   1339: 
                   1340: /* move */
                   1341: void
                   1342: op_move(uint16_t opword)
                   1343: {
                   1344:        EA src, dst;
                   1345: 
                   1346:        /* move an,usp */
                   1347:        if (oprand[1] == "usp") {
                   1348:                if (size_sfx == -1) {
                   1349:                        size_sfx = 4;
                   1350:                }
                   1351:                if (size_sfx != 4) {
                   1352:                        error("syntax error: MOVE An,USP must .L");
                   1353:                }
                   1354:                src = get_ea(oprand[0], EAT_An);
                   1355:                opword = 0x4e60 + src.num();
                   1356:                output_w(opword);
                   1357:                return;
                   1358:        }
                   1359:        /* move usp,an */
                   1360:        if (oprand[0] == "usp") {
                   1361:                dst = get_ea(oprand[1]);
                   1362:                if (size_sfx == -1) {
                   1363:                        size_sfx = 4;
                   1364:                }
                   1365:                if (size_sfx != 4) {
                   1366:                        error("syntax error: MOVE USP,An must .L");
                   1367:                }
                   1368:                opword = 0x4e68 + dst.num();
                   1369:                output_w(opword);
                   1370:                return;
                   1371:        }
                   1372: 
                   1373:        src = get_ea(oprand[0]);
                   1374:        dst = get_ea(oprand[1]);
                   1375: 
                   1376:        switch (size_sfx) {
                   1377:         case 1:        opword = 0x1000;        src.size = 1;   break;
                   1378:         case 2:        opword = 0x3000;        src.size = 2;   break;
                   1379:         case 4:        opword = 0x2000;        src.size = 4;   break;
                   1380:        }
                   1381:        opword |= src.mode;
                   1382:        opword |= (dst.type() | (dst.num() << 3)) << 6;
                   1383: 
                   1384:        output_w(opword);
                   1385:        output_ea(src);
                   1386:        output_ea(dst);
                   1387: }
                   1388: 
                   1389: /* movem.l */
                   1390: void
                   1391: op_movem(uint16_t opword)
                   1392: {
                   1393:        uint16_t list;
                   1394:        EA ea;
                   1395:        String errmsg;
                   1396: 
                   1397:        if (size_sfx == 4) {    /* .L */
                   1398:                opword |= 0x0040;
                   1399:        }
                   1400: 
                   1401:        if (get_reglist(oprand[0], list)
                   1402:         && try_ea(oprand[1], ea, errmsg, EAT_AI | EAT_APD | EAT_AREL | EAT_ABS))
                   1403:        {
                   1404:                /* movem.l list,ea */
                   1405:                opword |= ea.mode;
                   1406: 
                   1407:                /* -(An) の時だけビット並び順を反転 */
                   1408:                if ((ea.mode & 0x38) == EA_An_PD) {
                   1409:                        uint16_t rev = 0;
                   1410:                        for (int i = 0; i < 16; i++) {
                   1411:                                if ((list & (1 << i)) != 0) {
                   1412:                                        rev |= 0x8000 >> i;
                   1413:                                }
                   1414:                        }
                   1415:                        list = rev;
                   1416:                }
                   1417: 
                   1418:                output_w(opword);
                   1419:                output_w(list);
                   1420:                output_ea(ea);
                   1421:                return;
                   1422:        }
                   1423:        if (try_ea(oprand[0], ea, errmsg, EAT_AI | EAT_API | EAT_AREL | EAT_ABS)
                   1424:         && get_reglist(oprand[1], list))
                   1425:        {
                   1426:                /* movem.l ea,list */
                   1427:                opword |= ea.mode;
                   1428:                opword |= 0x0400;       /* ea->list */
                   1429: 
                   1430:                output_w(opword);
                   1431:                output_w(list);
                   1432:                output_ea(ea);
                   1433:                return;
                   1434:        }
                   1435: 
                   1436:        error("invalid movem oprand\n");
                   1437: }
                   1438: 
                   1439: /* moveq.l */
                   1440: void
                   1441: op_moveq(uint16_t opword)
                   1442: {
                   1443:        EA src, dst;
                   1444: 
                   1445:        if (size_sfx == -1) {
                   1446:                size_sfx = 4;
                   1447:        }
                   1448:        if (size_sfx != 4) {
                   1449:                error("invalid opcode: %s%s\n", op0.c_str(), size0.c_str());
                   1450:        }
                   1451: 
                   1452:        src = get_ea(oprand[0]);
                   1453:        dst = get_ea(oprand[1]);
                   1454:        if (src.mode != EA_IMMEDIATE) {
                   1455:                error("invalid oprand\n");
                   1456:        }
                   1457:        if (src.val > 0xff) {
                   1458:                error("moveq.l #$%x too large\n", src.val);
                   1459:        }
                   1460: 
                   1461:        opword |= src.val & 0xff;
                   1462:        opword |= dst.num() << 9;
                   1463: 
                   1464:        output_w(opword);
                   1465: }
                   1466: 
                   1467: /* sub */
                   1468: void
                   1469: op_sub(uint16_t opword)
                   1470: {
                   1471:        EA src = get_ea(oprand[0]);
                   1472:        EA dst = get_ea(oprand[1]);
                   1473: 
                   1474:        switch (size_sfx) {
                   1475:         case 1:        opword |= 0x00; break;
                   1476:         case 2:        opword |= 0x40; break;
                   1477:         case 4:        opword |= 0x80; break;
                   1478:         default:
                   1479:                error("syntax error: size?");
                   1480:        }
                   1481: 
                   1482:        if (dst.type() == 0) {
                   1483:                // SUB.S <ea>,Dn
                   1484:                // XXX src の正当性チェック
                   1485:                opword |= src.mode;
                   1486:                opword |= dst.num() << 9;
                   1487:                output_w(opword);
                   1488:                output_ea(src);
                   1489:                return;
                   1490:        }
                   1491:        if (dst.type() == 0) {
                   1492:                // SUB.S Dn,<ea>
                   1493:                // XXX dst の正当性チェック
                   1494:                opword |= 0x0100;
                   1495:                opword |= src.num() << 9;
                   1496:                opword |= dst.mode;
                   1497:                output_w(opword);
                   1498:                output_ea(dst);
                   1499:                return;
                   1500:        }
                   1501:        error("syntax error");
                   1502: }
                   1503: 
                   1504: /* suba */
                   1505: void
                   1506: op_suba(uint16_t opword)
                   1507: {
                   1508:        EA src = get_ea(oprand[0]);
                   1509:        EA dst = get_ea(oprand[1]);
                   1510:        switch (size_sfx) {
                   1511:         case -1:
                   1512:         case 2:        opword |= 0x0000;       break;
                   1513:         case 4:        opword |= 0x0100;       break;
                   1514:         default:
                   1515:                error("syntax error: .B is invalid\n");
                   1516:        }
                   1517:        opword |= src.mode;
                   1518:        opword |= dst.num() << 9;
                   1519:        output_w(opword);
                   1520:        output_ea(src);
                   1521: }
                   1522: 
                   1523: /* trap */
                   1524: void
                   1525: op_trap(uint16_t opword)
                   1526: {
                   1527:        EA src;
                   1528: 
                   1529:        src = get_ea(oprand[0]);
                   1530:        if (src.mode != EA_IMMEDIATE) {
                   1531:                error("invalid oprand\n");
                   1532:        }
                   1533:        if (src.val > 15) {
                   1534:                error("trap #$%x too large\n", src.val);
                   1535:        }
                   1536: 
                   1537:        opword |= src.val;
                   1538:        output_w(opword);
                   1539: }
                   1540: 
                   1541: /* nop、rts などオペランドを持たないやつ */
                   1542: void
                   1543: op_noarg(uint16_t opword)
                   1544: {
                   1545:        output_w(opword);
                   1546: }
                   1547: 
                   1548: /*
                   1549:  * 指定されたeatype に bit が立ってなければ、
                   1550:  * この命令でこの EA は認められていない。
                   1551:  */
                   1552: #define check_eatype(bit)      \
                   1553:        if ((eatype & (bit)) == 0) {    \
                   1554:                DPRINTF(D_EA, "EAT 0x%x not match in eatype=0x%x\n", bit, eatype);      \
                   1555:                errmsg = "invalid ea";  \
                   1556:                return false;   \
                   1557:        }
                   1558: 
                   1559: /*
                   1560:  * EA がパースできるかどうかを返す。
                   1561:  * errmes が NULL でなければ、パースできなかった時のエラーメッセージを
                   1562:  * 格納する。
                   1563:  */
                   1564: bool
                   1565: try_ea(String& eabuf, EA& ea, String& errmsg, int eatype)
                   1566: {
                   1567: #if defined(_MSC_VER)
                   1568:        char buf[BUFSIZE];
                   1569: #else
                   1570:        char buf[eabuf.size() + 1];
                   1571: #endif
                   1572:        int i;
                   1573: 
                   1574: #if defined(_MSC_VER)
                   1575:        strncpy(buf, eabuf.c_str(), sizeof(buf) - 1);
                   1576:        buf[sizeof(buf) - 1] = '\0';
                   1577: #else
                   1578:        strcpy(buf, eabuf.c_str());
                   1579: #endif
                   1580: 
                   1581:        /* 固定文字列との比較。見つかればすぐ帰れる */
                   1582:        for (i = 0; i < countof(regname); i++) {
                   1583:                if (strcasecmp(buf, regname[i]) == 0) {
                   1584:                        ea.mode = i;
                   1585:                        DPRINTF(D_EA, "ea=reg,%s -> 0x%x\n", regname[ea.mode], ea.mode);
                   1586:                        check_eatype(1 << (i / 8));
                   1587:                        return true;
                   1588:                }
                   1589:        }
                   1590: 
                   1591:        /* d16(pc) */
                   1592:        i = strlen(buf) - 4;
                   1593:        if (i > 0 && strcasecmp(buf + i, "(pc)") == 0) {
                   1594:                String label = eabuf.substr(0, i);
                   1595:                add_ref(REFTYPE_WORD, label);
                   1596:                ea.mode = EA_d16PC;
                   1597:                DPRINTF(D_EA, "ea=d16(PC) label=%s\n", label.c_str());
                   1598:                check_eatype(EAT_PCREL);
                   1599:                return true;
                   1600:        }
                   1601: 
                   1602:        /* #imm */
                   1603:        /* XXX マクロ展開後が #imm だったら解決できないこれ */
                   1604:        if (buf[0] == '#') {
                   1605:                String label = eabuf.substr(1);
                   1606:                ea.mode = EA_IMMEDIATE;
                   1607:                ea.val = tonumber(label);
                   1608:                DPRINTF(D_EA, "ea=#imm,$%x\n", ea.val);
                   1609:                check_eatype(EAT_IMM);
                   1610:                return true;
                   1611:        }
                   1612: 
                   1613:        /* XXX An間接、PC間接系は未実装 */
                   1614: 
                   1615:        /* どれでもなさそうなら? */
                   1616:        /* Abs[.WL] */
                   1617:        ea.size = 0;
                   1618:        i = strlen(buf) - 2;
                   1619:        if (i > 0) {
                   1620:                if (strcasecmp(buf + i, ".W") == 0) {
                   1621:                        ea.size = 2;
                   1622:                } else if (strcasecmp(buf + i, ".L") == 0) {
                   1623:                        ea.size = 4;
                   1624:                }
                   1625:        }
                   1626:        ea.mode = EA_ABS_W;
                   1627:        int intval;
                   1628:        if (parse_number(eabuf, &intval)) {
                   1629:                ea.val = intval;
                   1630:                if (ea.size == 0) {
                   1631:                        ea.size = (ea.val > 0xffff) ? 4 : 2;
                   1632:                }
                   1633:                ea.mode = (ea.size == 4) ? EA_ABS_L : EA_ABS_W;
                   1634:                if (ea.val > 0xffff && ea.mode == EA_ABS_W) {
                   1635:                        errmsg = "Exceed Abs.W";
                   1636:                        return false;
                   1637:                }
                   1638:                DPRINTF(D_EA, "ea=ABS.%c,$%x\n",
                   1639:                        (ea.mode==EA_ABS_W)?'W':'L', ea.val);
                   1640:                check_eatype(EAT_ABS);
                   1641:                return true;
                   1642:        }
                   1643: 
                   1644:        DPRINTF(D_EA, "unknown EA: %s\n", buf);
                   1645:        errmsg = "unknown EA: ";
                   1646:        errmsg += eabuf;
                   1647:        return false;
                   1648: }
                   1649: 
                   1650: /*
                   1651:  * EA をパースして返す。
                   1652:  * 成功すれば EA を返す。失敗すればエラー終了する。
                   1653:  */
                   1654: EA
                   1655: get_ea(String& eabuf)
                   1656: {
                   1657:        return get_ea(eabuf, EAT_ALL);
                   1658: }
                   1659: 
                   1660: /*
                   1661:  * EA をパースして返す。
                   1662:  * eatype は許可する EA タイプ。
                   1663:  * 成功すれば EA を返す。失敗すればエラー終了する。
                   1664:  */
                   1665: EA
                   1666: get_ea(String& eabuf, int eatype)
                   1667: {
                   1668:        EA ea;
                   1669:        String errmsg;
                   1670: 
                   1671:        if (try_ea(eabuf, ea, errmsg, eatype) == false) {
                   1672:                error("%s", errmsg.c_str());
                   1673:        }
                   1674:        return ea;
                   1675: }
                   1676: 
                   1677: /*
                   1678:  * reglist をパースする。
                   1679:  * reglist でなさそうならエラーを表示せず false を返す。
                   1680:  * true を返した場合の list は常に b15-b0 の順で A7-A0/D7-D0。
                   1681:  */
                   1682: bool
                   1683: get_reglist(String& inbuf, uint16_t& list)
                   1684: {
                   1685: #if defined(_MSC_VER)
                   1686:        char buf[BUFSIZE];
                   1687: #else
                   1688:        char buf[inbuf.size() + 1];
                   1689: #endif
                   1690:        char *s;
                   1691:        int num;
                   1692:        int prevnum;
                   1693:        int Aoffset;
                   1694:        enum {
                   1695:                INIT,
                   1696:                REG,
                   1697:                NUM1,
                   1698:                NUM2,
                   1699:        } state;
                   1700: 
                   1701: #if defined(_MSC_VER)
                   1702:        strncpy(buf, inbuf.c_str(), sizeof(buf) - 1);
                   1703:        buf[sizeof(buf) - 1] = '\0';
                   1704: #else
                   1705:        strcpy(buf, inbuf.c_str());
                   1706: #endif
                   1707: 
                   1708:        state = INIT;
                   1709:        num = -1;
                   1710:        prevnum = -1;
                   1711:        Aoffset = 0;
                   1712:        for (s = buf; *s; s++) {
                   1713:                char c = (int)*s;
                   1714:                if (state == INIT) {
                   1715:                        if (tolower(c) == 'd') {
                   1716:                                state = REG;
                   1717:                                Aoffset = 0;
                   1718:                                continue;
                   1719:                        }
                   1720:                        if (tolower(c) == 'a') {
                   1721:                                state = REG;
                   1722:                                Aoffset = 8;
                   1723:                                continue;
                   1724:                        }
                   1725:                        return false;
                   1726:                } else if (state == REG) {
                   1727:                        if (!isdigit(c)) {
                   1728:                                return false;
                   1729:                        }
                   1730:                        num = c - '0';
                   1731:                        num += Aoffset;
                   1732:                        if (prevnum == -1) {
                   1733:                                // 単独もしくは範囲指定の1つ目のレジスタ指定
                   1734:                                list |= (1 << num);
                   1735:                                state = NUM1;
1.1.1.2 ! root     1736:                        } else {
1.1       root     1737:                                // 範囲指定の2つ目のレジスタ
                   1738:                                for (int i = prevnum; i <= num; i++) {
                   1739:                                        list |= (1 << i);
                   1740:                                }
                   1741:                                prevnum = -1;
                   1742:                                state = NUM2;
                   1743:                        }
                   1744:                        continue;
                   1745:                } else if (state == NUM1) {
                   1746:                        // 単独もしくは範囲指定の1つ目のレジスタの後
                   1747:                        if (c == '/') {
                   1748:                                prevnum = -1;
                   1749:                                state = INIT;
                   1750:                                continue;
                   1751:                        }
                   1752:                        if (c == '-') {
                   1753:                                prevnum = num;
                   1754:                                state = INIT;
                   1755:                                continue;
                   1756:                        }
                   1757:                        return false;
                   1758:                } else if (state == NUM2) {
                   1759:                        // 範囲指定の2つ目のレジスタの後に '-' はこない
                   1760:                        if (c == '/') {
                   1761:                                state = INIT;
                   1762:                                continue;
                   1763:                        }
                   1764:                        return false;
                   1765:                }
                   1766:                return false;
                   1767:        }
                   1768: 
                   1769:        DPRINTF(D_EA, "reglist = %04X\n", list);
                   1770:        return true;
                   1771: }
                   1772: 
                   1773: /* cc をパースして返す */
                   1774: int
                   1775: get_cc(String& ccbuf)
                   1776: {
                   1777:        int i;
                   1778: 
                   1779:        for (i = 0; i < countof(ccname); i++) {
                   1780:                if (strcasecmp(ccbuf.c_str(), ccname[i]) == 0) {
                   1781:                        DPRINTF(D_EA, "cc=%s -> 0x%x\n", ccname[i], i);
                   1782:                        return i;
                   1783:                }
                   1784:        }
                   1785: 
                   1786:        error("unknown CC: %s\n", ccbuf.c_str());
                   1787:        /* NOTREACHED */
                   1788:        return 0;
                   1789: }
                   1790: 
                   1791: /* 参照をリストに追加。おもに Bcc と d16(PC) 用? */
                   1792: void
                   1793: add_ref(reftype_t type, String& label)
                   1794: {
                   1795:        /* expr = label - (pc+2) */
                   1796:        ArrayString expr;
                   1797:        expr.push_back(label);
                   1798:        expr.push_back(num2hex(::pc + 2));
                   1799:        expr.push_back(String("-"));
                   1800: 
                   1801:        /* オフセット */
                   1802:        int offset;
                   1803:        switch (type) {
                   1804:         case REFTYPE_BYTE:
                   1805:                offset = 1;
                   1806:                break;
                   1807:         case REFTYPE_WORD:
                   1808:         case REFTYPE_LONG:
                   1809:                offset = 2;
                   1810:                break;
                   1811:         default:
                   1812:                error("unknown reftype %d\n", type);
                   1813:        }
                   1814: 
                   1815:        add_expr(::outbin.size() + offset, type, expr);
                   1816: }
                   1817: 
                   1818: /* EA を出力 */
                   1819: void
                   1820: output_ea(EA& ea)
                   1821: {
                   1822:        switch (ea.mode) {
                   1823:         case EA_d16PC:
                   1824:                output_w(0);
                   1825:                break;
                   1826:         case EA_ABS_W:
                   1827:                output_w(ea.val);
                   1828:                break;
                   1829:         case EA_ABS_L:
                   1830:                output_l(ea.val);
                   1831:                break;
                   1832:         case EA_IMMEDIATE:
                   1833:                output_bin(ea.val, ea.size);
                   1834:                break;
                   1835:         default:
                   1836:                /* それ以外は何もしない */
                   1837:                break;
                   1838:        }
                   1839: }
                   1840: 
                   1841: /* nバイトを出力 */
                   1842: void
                   1843: output_bin(uint32_t data, int size)
                   1844: {
                   1845:        switch (size) {
                   1846:         case 1:
                   1847:                output_b(data);
                   1848:                break;
                   1849:         case 2:
                   1850:                output_w(data);
                   1851:                break;
                   1852:         case 4:
                   1853:                output_l(data);
                   1854:                break;
                   1855:         default:
                   1856:                error("output_bin: invalid size %d\n", size);
                   1857:                break;
                   1858:        }
                   1859: }
                   1860: 
                   1861: /* 1バイトを出力 */
                   1862: void
                   1863: output_b(uint32_t data)
                   1864: {
                   1865:        data &= 0xff;
                   1866:        DPRINTF(D_INOUT, "output: $%06X => $%02X\n", pc, data);
                   1867:        outbin.push_back(data);
                   1868:        pc += 1;
                   1869: }
                   1870: 
                   1871: /* 1ワードを出力 */
                   1872: void
                   1873: output_w(uint32_t data)
                   1874: {
                   1875:        data &= 0xffff;
                   1876:        DPRINTF(D_INOUT, "output: $%06X => $%04X\n", pc, data);
                   1877:        outbin.push_back(data >> 8);
                   1878:        outbin.push_back(data & 0xff);
                   1879:        pc += 2;
                   1880: }
                   1881: 
                   1882: /* 1ロングワードを出力 */
                   1883: void
                   1884: output_l(uint32_t data)
                   1885: {
                   1886:        DPRINTF(D_INOUT, "output: $%06X => $%08X\n", pc, data);
                   1887:        outbin.push_back(data >> 24);
                   1888:        outbin.push_back((data >> 16) & 0xff);
                   1889:        outbin.push_back((data >>  8) & 0xff);
                   1890:        outbin.push_back(data & 0xff);
                   1891:        pc += 4;
                   1892: }
                   1893: 
                   1894: /* .ds 用に指定の長さを 0 で埋める */
                   1895: void
                   1896: output_ds(int size)
                   1897: {
                   1898:        DPRINTF(D_INOUT, "output: $%X(%d)bytes\n", size, size);
                   1899:        String ds(size, '\0');
                   1900:        outbin += ds;
                   1901:        pc += size;
                   1902: }
                   1903: 
                   1904: /* 数値を String に変換 */
                   1905: String
                   1906: num2str(int num)
                   1907: {
                   1908:        char buf[16];
                   1909:        snprintf(buf, sizeof(buf), "%d", num);
                   1910:        String ret(buf);
                   1911:        return ret;
                   1912: }
                   1913: 
                   1914: /* 数値を $HHHH 形式の String に変換 */
                   1915: String
                   1916: num2hex(int num)
                   1917: {
                   1918:        char buf[16];
                   1919:        snprintf(buf, sizeof(buf), "$%x", num);
                   1920:        String ret(buf);
                   1921:        return ret;
                   1922: }
                   1923: 
                   1924: /*
                   1925:  * 文字列を数値に変換。
                   1926:  * 変換できれば true、できなければ false を返す。
                   1927:  * 変換できた場合は、numptr が NULL でなければ結果を格納して返す。
                   1928:  */
                   1929: bool
                   1930: parse_number(String& str, int *numptr)
                   1931: {
                   1932:        try {
                   1933:                /* 先頭が数字なら10進数 */
                   1934:                if (isdigit((int)str[0])) {
                   1935:                        throw (int)strtol(str.c_str(), NULL, 10);
                   1936:                }
                   1937: 
                   1938:                /* $HH 形式なら16進数 */
                   1939:                if (str[0] == '$' && str.size() > 1) {
                   1940:                        String buf = str;
                   1941:                        buf.erase(0, 1);
                   1942:                        /* エラー処理無視 */
                   1943:                        throw (int)strtol(buf.c_str(), NULL, 16);
                   1944:                }
                   1945: 
                   1946:                /* 'X'形式なら1文字 */
                   1947:                if (str[0] == '\'' && str.size() == 3 && str[2] == '\'') {
                   1948:                        throw (int)str[1];
                   1949:                }
                   1950: 
                   1951:                /* (既出の)ラベルと一致するか */
                   1952:                String val;
                   1953:                if (find_label(str, val)) {
                   1954:                        int num;
                   1955:                        if (parse_number(val, &num)) {
                   1956:                                throw num;
                   1957:                        }
                   1958:                }
                   1959:        } catch (int num) {
                   1960:                /* 見つかった時に例外でここに飛んでくる */
                   1961:                if (numptr) {
                   1962:                        *numptr = num;
                   1963:                }
                   1964:                return true;
                   1965:        }
                   1966: 
                   1967:        /* 解決できなかった */
                   1968:        return false;
                   1969: }
                   1970: 
                   1971: /* 文字列を数値に変換。変換できなければアセンブルエラーで停止する */
                   1972: int
                   1973: tonumber(String& str)
                   1974: {
                   1975:        int num;
                   1976: 
                   1977:        if (!parse_number(str, &num)) {
                   1978:                error("invalid number: %s\n", str.c_str());
                   1979:        }
                   1980:        return num;
                   1981: }
                   1982: 
                   1983: /* 式を解析する */
                   1984: bool
                   1985: parse_expr(String& expr, ArrayString& out)
                   1986: {
                   1987:        ArrayString tokens;
                   1988:        std::stack<String> stack;
                   1989: 
                   1990:        DPRINTF(D_PARSE, "parse_expr.0 expr |%s|\n", expr.c_str());
                   1991: 
                   1992:        /* トークンに分解 */
                   1993:        if (!scan_expr(expr, tokens)) {
                   1994:                error("scan error: '%s'\n", expr.c_str());
                   1995:        }
                   1996: 
                   1997:        /* 中置記法を後置記法に変換 */
                   1998:        for (int i = 0; i < tokens.size(); i++) {
                   1999:                String token = tokens[i];
                   2000:                const char *tok = token.c_str();
                   2001: 
                   2002:                if (strcmp(tok, "+") == 0 || strcmp(tok, "-") == 0) {
                   2003:                        for (; stack.size() > 0 && stack.top()[0] != '('; ) {
                   2004:                                out.push_back(stack.top());
                   2005:                                stack.pop();
                   2006:                        }
                   2007:                        stack.push(token);
                   2008: 
                   2009:                } else if (strcmp(tok, "*") == 0 || strcmp(tok, "/") == 0) {
                   2010:                        if (stack.size() > 0) {
                   2011:                                if (stack.top()[0] == '*' || stack.top()[0] == '/') {
                   2012:                                        out.push_back(stack.top());
                   2013:                                        stack.pop();
                   2014:                                }
                   2015:                        }
                   2016:                        stack.push(token);
                   2017: 
                   2018:                } else if (strcmp(tok, "(") == 0) {
                   2019:                        stack.push(token);
                   2020: 
                   2021:                } else if (strcmp(tok, ")") == 0) {
                   2022:                        for (; stack.size() > 0 && stack.top()[0] != '('; ) {
                   2023:                                out.push_back(stack.top());
                   2024:                                stack.pop();
                   2025:                        }
                   2026:                        if (stack.size() == 0) {
                   2027:                                error("expression error\n");
                   2028:                        }
                   2029:                        stack.pop();
                   2030: 
                   2031:                } else {
                   2032:                        int num;
                   2033:                        if (parse_number(token, &num)) {
                   2034:                                /* 数値に変換できたら、数値(の文字列型)を格納 */
                   2035:                                out.push_back(num2hex(num));
                   2036:                        } else {
                   2037:                                /* 数値にできなければ(たぶん)ラベルのまま格納 */
                   2038:                                out.push_back(token);
                   2039:                        }
                   2040:                }
                   2041:        }
                   2042: 
                   2043:        for (; stack.size() > 0;) {
                   2044:                out.push_back(stack.top());
                   2045:                stack.pop();
                   2046:        }
                   2047: 
                   2048:        DPRINTF(D_PARSE, "parse_expr.3 expr");
                   2049:        for (int i = 0; i < out.size(); i++) {
                   2050:                DPRINTN(D_PARSE, "%c%s", (i==0)?'=':' ', out[i].c_str());
                   2051:        }
                   2052:        DPRINTN(D_PARSE, "\n");
                   2053: 
                   2054:        return true;
                   2055: }
                   2056: 
                   2057: /*
                   2058:  * 字句解析。expr をトークンごとに分解して tokens に入れて返す。
                   2059:  */
                   2060: bool
                   2061: scan_expr(String& expr, ArrayString& tokens)
                   2062: {
                   2063: #if defined(_MSC_VER)
                   2064:        char buf[BUFSIZE];
                   2065: #else
                   2066:        char buf[expr.size() + 1];
                   2067: #endif
                   2068:        char *s = NULL; /* shut up gcc */
                   2069:        char *p;
                   2070:        int c;
                   2071:        enum {
                   2072:                INIT,
                   2073:                LABEL,
                   2074:                DIGIT,
                   2075:                HEX,
                   2076:        } state;
                   2077: 
                   2078: #if defined(_MSC_VER)
                   2079:        strncpy(buf, expr.c_str(), sizeof(buf) - 1);
                   2080:        buf[sizeof(buf) - 1] = '\0';
                   2081: #else
                   2082:        strcpy(buf, expr.c_str());
                   2083: #endif
                   2084: 
                   2085:        state = INIT;
                   2086:        for (p = buf; *p; p++) {
                   2087:                c = (int)*p;
                   2088: 
                   2089:                switch (state) {
                   2090:                 case LABEL:    /* ラベルの2文字目以降 */
                   2091:                        if (isalpha(c) || isdigit(c) || c == '_') {
                   2092:                                continue;
                   2093:                        }
                   2094:                        break;
                   2095:                 case DIGIT:    /* 数字の2文字目以降 */
                   2096:                        if (isdigit(c)) {
                   2097:                                continue;
                   2098:                        }
                   2099:                        break;
                   2100:                 case HEX:              /* 16進の2文字目以降 */
                   2101:                        if (isxdigit(c)) {
                   2102:                                continue;
                   2103:                        }
                   2104:                        break;
                   2105: 
                   2106:                 case INIT:             /* 1文字目 */
                   2107:                 init:
                   2108:                        s = p;
                   2109:                        if (isspace(c)) {
                   2110:                                continue;
                   2111:                        } else if (isalpha(c) || c == '_') {
                   2112:                                state = LABEL;
                   2113:                        } else if (isdigit(c)) {
                   2114:                                state = DIGIT;
                   2115:                        } else if (c == '$') {
                   2116:                                state = HEX;
                   2117:                        } else if (strchr("+-*/()", c)) {
                   2118:                                /* 記号は1文字で確定する */
                   2119:                                String token(s, 1);
                   2120:                                tokens.push_back(token);
                   2121:                                /* INIT状態のまま次の文字へ */
                   2122:                                continue;
                   2123:                        } else {
                   2124:                                error("syntax error\n");
                   2125:                        }
                   2126:                        continue;
                   2127:                }
                   2128: 
                   2129:                /* 1文字前までが1語句だった */
                   2130:                String token(s, p - s);
                   2131:                tokens.push_back(token);
                   2132:                /* 今指してるのは次語句の先頭なので、この文字のまま INIT へ */
                   2133:                state = INIT;
                   2134:                goto init;
                   2135:        }
                   2136: 
                   2137:        /* 状態を残したまま最後の文字まで来たら最後の語句を切り出す */
                   2138:        if (state != INIT) {
                   2139:                String token(s);
                   2140:                tokens.push_back(token);
                   2141:        }
                   2142: 
                   2143:        return true;
                   2144: }
                   2145: 
                   2146: /* 計算途中の式をリストに追加 */
                   2147: void
                   2148: add_expr(int pos, reftype_t type, ArrayString& expr)
                   2149: {
                   2150:        REF *ref = new REF;
                   2151: 
                   2152:        ref->pos = pos;
                   2153:        ref->line = ::line;
                   2154:        ref->type = type;
                   2155:        ref->expr = expr;
                   2156:        DPRINTN_ref(D_EXPR, ref);
                   2157: 
                   2158:        ref_list.push_back(ref);
                   2159: }
                   2160: 
                   2161: /* デバッグ表示 */
                   2162: void
                   2163: DPRINTN_ref(int debugflag, REF *ref)
                   2164: {
                   2165:        DPRINTF(debugflag, "REF line=%d pos=%d($%06x) type=%d ",
                   2166:                ref->line, ref->pos, origin + ref->pos, (int)ref->type);
                   2167:        DPRINTN_expr(debugflag, ref->expr);
                   2168:        DPRINTN(debugflag, "\n");
                   2169: }
                   2170: 
                   2171: /* デバッグ表示 */
                   2172: void
                   2173: DPRINTN_expr(int debugflag, ArrayString& expr)
                   2174: {
                   2175:        DPRINTN(debugflag, "expr");
                   2176:        for (int i = 0; i < expr.size(); i++) {
                   2177:                DPRINTN(debugflag, "%c%s", (i == 0)?'=':' ', expr[i].c_str());
                   2178:        }
                   2179: }
                   2180: 
                   2181: /*
                   2182:  * 式を計算する。
                   2183:  * error_stop が真ならラベルが解決できないのをエラーにする。
                   2184:  * 1st stage では false、2nd stage では true にする。
                   2185:  * false でラベルが解決できなければ false を返すだけ。
                   2186:  */
                   2187: bool
                   2188: calc_expr(ArrayString& expr, uint32_t& retval, bool error_stop)
                   2189: {
                   2190:        uint32_t val;
                   2191:        uint32_t v1, v2;
                   2192:        int i;
                   2193: 
                   2194:        DPRINTF(D_EXPR, "calc_expr.0 ");
                   2195:        DPRINTN_expr(D_EXPR, expr);
                   2196:        DPRINTN(D_EXPR, "\n");
                   2197: 
                   2198:        /* まずラベルが解決できるか */
                   2199:        for (i = 0; i < expr.size(); i++) {
                   2200:                String token = expr[i];
                   2201:                if (isalpha((int)token[0])) {
                   2202:                        int intval;
                   2203:                        if (parse_number(token, &intval)) {
                   2204:                                /* 見付かったので数値に差し替える */
                   2205:                                expr[i] = num2hex(intval);
                   2206:                                DPRINTF(D_EXPR, "calc_expr.1 '%s' is %s\n",
                   2207:                                        token.c_str(), expr[i].c_str());
                   2208:                        } else {
                   2209:                                /* 見付からなかった */
                   2210:                                if (error_stop) {
                   2211:                                        error("undefined label: %s\n", token.c_str());
                   2212:                                } else {
                   2213:                                        DPRINTF(D_EXPR, "calc_expr.1 '%s' not resolved, quit\n",
                   2214:                                                token.c_str());
                   2215:                                        return false;
                   2216:                                }
                   2217:                        }
                   2218:                }
                   2219:        }
                   2220:        DPRINTF(D_EXPR, "calc_expr.2 ");
                   2221:        DPRINTN_expr(D_EXPR, expr);
                   2222:        DPRINTN(D_EXPR, "\n");
                   2223: 
                   2224:        /* ラベルが全部解決できたので計算する */
                   2225:        std::stack<uint32_t> stack;
                   2226:        for (i = 0; i < expr.size(); i++) {
                   2227:                String token = expr[i];
                   2228:                if (token[0] == '$') {
                   2229:                        /* 取り出したのが数値ならスタックに積む */
                   2230:                        val = (uint32_t)tonumber(token);
                   2231:                        stack.push(val);
                   2232: 
                   2233:                } else {
                   2234:                        /* 取り出したのが演算子ならスタックから2つ取って.. */
                   2235:                        v2 = stack.top();
                   2236:                        stack.pop();
                   2237:                        v1 = stack.top();
                   2238:                        stack.pop();
                   2239: 
                   2240:                        /* 計算 */
                   2241:                        if (token[0] == '+') {
                   2242:                                val = v1 + v2;
                   2243:                        } else if (token[0] == '-') {
                   2244:                                val = v1 - v2;
                   2245:                        } else if (token[0] == '*') {
                   2246:                                val = v1 * v2;
                   2247:                        } else if (token[0] == '/') {
                   2248:                                val = v1 / v2;
                   2249:                        } else {
                   2250:                                error("unknown operator: %s\n", token.c_str());
                   2251:                        }
                   2252: 
                   2253:                        /* それを再び積む */
                   2254:                        stack.push(val);
                   2255:                }
                   2256:        }
                   2257: 
                   2258:        retval = stack.top();
                   2259: DPRINTF(D_EXPR, "calc_expr.3 ret=$%x\n", retval);
                   2260:        return true;
                   2261: }
                   2262: 
                   2263: /* 文字列を解析 */
                   2264: String
                   2265: parse_string(String& src)
                   2266: {
                   2267:        String dst;
                   2268:        enum {
                   2269:                OUTER = 0,
                   2270:                PLAIN,
                   2271:                ESC,
                   2272:        } state;
                   2273: 
                   2274:        state = OUTER;
                   2275:        for (int i = 0; i < src.size(); i++) {
                   2276:                int c = (int)(src[i]);
                   2277:                switch (state) {
                   2278:                 case OUTER:
                   2279:                        if (isspace(c)) {
                   2280:                                ;
                   2281:                        } else if (c == '\x22') {
                   2282:                                state = PLAIN;
                   2283:                        } else {
                   2284:                                error("syntax error around string: %s", src.c_str());
                   2285:                        }
                   2286:                        break;
                   2287: 
                   2288:                 case PLAIN:
                   2289:                        if (c == '\x22') {
                   2290:                                state = OUTER;
                   2291:                        } else if (c == '\\') {
                   2292:                                state = ESC;
                   2293:                        } else {
                   2294:                                dst.push_back(c);
                   2295:                        }
                   2296:                        break;
                   2297: 
                   2298:                 case ESC:
                   2299:                        if (c == 'n') {
                   2300:                                dst.push_back('\n');
                   2301:                        } else if (c == 't') {
                   2302:                                dst.push_back('\t');
                   2303:                        } else {
                   2304:                                dst.push_back(c);
                   2305:                        }
                   2306:                        /* XXX \xHH 追加のこと */
                   2307:                        state = PLAIN;
                   2308:                        break;
                   2309:                }
                   2310:        }
                   2311:        if (state != OUTER) {
                   2312:                error("syntax error in string: %s\n", src.c_str());
                   2313:        }
                   2314: 
                   2315:        return dst;
                   2316: }
                   2317: 
                   2318: /* 文字コードを UTF-8 から Shift_JIS に変換 */
                   2319: String
                   2320: convert_charset(String& src)
                   2321: {
                   2322: #if defined(_WIN32)
                   2323:        /*
                   2324:         * Win32 API を使う
                   2325:         */
                   2326:        int size;
                   2327:        WCHAR wsrc[BUFSIZE];
                   2328:        char mdst[BUFSIZE];
                   2329: 
                   2330:        /* まず(UTF-8の)ワイド文字列に変換 */
                   2331:        size = MultiByteToWideChar(CP_UTF8, 0, src.c_str(), -1, NULL, 0);
                   2332:        MultiByteToWideChar(CP_UTF8, 0, src.c_str(), -1, wsrc, size);
                   2333: 
                   2334:        /* Shift_JIS のマルチバイト文字に変換 */
                   2335:        size = WideCharToMultiByte(932, 0, wsrc, -1, NULL, 0, 0, NULL);
                   2336:        WideCharToMultiByte(932, 0, wsrc, -1, mdst, size, 0, NULL);
                   2337: 
                   2338:        String dst(mdst);
                   2339:        return dst;
                   2340: 
                   2341: #elif defined(IASM_USE_iconv)
                   2342:        /*
                   2343:         * iconv(3) を使う
                   2344:         */
                   2345:        iconv_t cd;
                   2346:        char dstbuf[src.size() * 2];    /* 適当 */
                   2347:        const char *srcptr;
                   2348:        char *dstptr;
                   2349:        size_t srcsize;
                   2350:        size_t dstsize;
                   2351:        size_t r;
                   2352: 
                   2353:        cd = iconv_open("Shift_JIS", "UTF-8");
                   2354:        if (cd == NULL) {
                   2355:                return src;
                   2356:        }
                   2357: 
                   2358:        srcptr = src.c_str();
                   2359:        srcsize = src.size();
                   2360:        memset(dstbuf, 0, sizeof(dstbuf));
                   2361:        dstptr = dstbuf;
                   2362:        dstsize = sizeof(dstbuf);
                   2363:        r = iconv(cd, (iconv_src_t)&srcptr, &srcsize, &dstptr, &dstsize);
                   2364:        if (r == -1) {
                   2365:                error("cannot conversion string: %s\n", srcptr);
                   2366:        }
                   2367:        if (r > 0) {
                   2368:                error("invalid charactor found: %s\n", srcptr);
                   2369:        }
                   2370: 
                   2371:        iconv_close(cd);
                   2372: 
                   2373:        String dst(dstbuf);
                   2374:        return dst;
                   2375: 
                   2376: #elif defined(IASM_USE_wxWidgets)
                   2377:        /*
                   2378:         * wxWidgets の wxCSConv を使う
                   2379:         */
                   2380:        char buf[src.size() * 2];       /* 適当 */
                   2381: 
                   2382:        wxString wstr(src.c_str(), wxConvUTF8);
                   2383:        wxCSConv conv(wxT("SHIFT_JIS"));
                   2384:        conv.WC2MB(buf, wstr.wc_str(), sizeof(buf));
                   2385: 
                   2386:        String dst(buf);
                   2387:        return dst;
                   2388: 
                   2389: #else
                   2390:        /*
                   2391:         * 文字コード変換ライブラリがない場合は何もしない
                   2392:         */
                   2393:        return src;
                   2394: #endif
                   2395: }
                   2396: 
                   2397: /* デバッグ表示 (ap版) */
                   2398: void
                   2399: DPRINTV(int flag, const char *fmt, va_list ap)
                   2400: {
                   2401:        if ((debug & flag)) {
                   2402:                vprintf(fmt, ap);
                   2403:        }
                   2404: }
                   2405: 
                   2406: /* デバッグ表示 (行頭のマークなし) */
                   2407: void
                   2408: DPRINTN(int flag, const char *fmt, ...)
                   2409: {
                   2410:        va_list ap;
                   2411: 
                   2412:        va_start(ap, fmt);
                   2413:        DPRINTV(flag, fmt, ap);
                   2414:        va_end(ap);
                   2415: }
1.1.1.2 ! root     2416: 
1.1       root     2417: /* デバッグ表示 (行頭のマーク付き) */
                   2418: void
                   2419: DPRINTF(int flag, const char *fmt, ...)
                   2420: {
                   2421:        va_list ap;
                   2422:        int ch;
                   2423: 
                   2424:        switch (flag) {
                   2425:         case D_INOUT:
                   2426:                ch = '|';
                   2427:                break;
                   2428:         case D_EA:
                   2429:                ch = 'A';
                   2430:                break;
                   2431:         case D_LABEL:
                   2432:                ch = 'L';
                   2433:                break;
                   2434:         case D_PARSE:
                   2435:                ch = 'P';
                   2436:                break;
                   2437:         case D_STAGE:
                   2438:                ch = ' ';
                   2439:                break;
                   2440:         case D_EXPR:
                   2441:                ch = 'E';
                   2442:                break;
                   2443:         case D_SCAN:
                   2444:                ch = 'S';
                   2445:                break;
                   2446:         default:
                   2447:                ch = '?';
                   2448:                break;
                   2449:        }
                   2450:        DPRINTN(flag, "%c ", ch);
                   2451: 
                   2452:        va_start(ap, fmt);
                   2453:        DPRINTV(flag, fmt, ap);
                   2454:        va_end(ap);
                   2455: }
                   2456: 
                   2457: /* アセンブルエラー */
                   2458: void
                   2459: error(const char *fmt, ...)
                   2460: {
                   2461:        char buf[1024];
                   2462:        va_list ap;
                   2463: 
                   2464:        va_start(ap, fmt);
                   2465:        vsnprintf(buf, sizeof(buf), fmt, ap);
                   2466:        va_end(ap);
                   2467: 
                   2468:        /* デバッグモードなら stdout にも出力しないと分かりづらい */
                   2469:        DPRINTN(D_STAGE, "%s:%d:%s", current_infile, line, buf);
                   2470:        fprintf(stderr, "%s:%d:%s", current_infile, line, buf);
                   2471: 
                   2472:        /* 出力しかけのファイルは消しておく (次のビルドのため) */
                   2473:        if (outfile) {
                   2474:                fclose(outfp);
                   2475:                unlink(outfile);
                   2476:                fprintf(stderr, "output file '%s' removed\n", outfile);
                   2477:        }
                   2478: 
                   2479:        exit(1);
                   2480: }
                   2481: 
                   2482: /* String の前後の空白を取り除く */
                   2483: void
                   2484: trim(String& str)
                   2485: {
                   2486:        ltrim(str);
                   2487:        rtrim(str);
                   2488: }
                   2489: 
                   2490: /* String の先頭の空白を取り除く */
                   2491: void
                   2492: ltrim(String& str)
                   2493: {
                   2494:        while (isspace((int)str[0])) {
                   2495:                str.erase(0, 1);
                   2496:        }
                   2497: }
                   2498: 
                   2499: /* String の末尾の空白を取り除く */
                   2500: void
                   2501: rtrim(String& str)
                   2502: {
                   2503:        for (int r = str.length() - 1; r >= 0; r--) {
                   2504:                if (isspace((int)str[r])) {
                   2505:                        str.erase(r);
                   2506:                } else {
                   2507:                        break;
                   2508:                }
                   2509:        }
                   2510: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.