/* * Copyright (c) 2002 - 2005 Magnus Lind. * * This software is provided 'as-is', without any express or implied warranty. * In no event will the authors be held liable for any damages arising from * the use of this software. * * Permission is granted to anyone to use this software, alter it and re- * distribute it freely for any non-commercial, non-profit purpose subject to * the following restrictions: * * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software in a * product, an acknowledgment in the product documentation would be * appreciated but is not required. * * 2. Altered source versions must be plainly marked as such, and must not * be misrepresented as being the original software. * * 3. This notice may not be removed or altered from any distribution. * * 4. The names of this software and/or it's copyright holders may not be * used to endorse or promote products derived from this software without * specific prior written permission. * */ /* scanner for a simple assembler */ %{ #include #include #include "int.h" #include "membuf.h" #include "parse.h" #include "asm.tab.h" #define MAX_SRC_BUFFER_DEPTH 10 static YY_BUFFER_STATE src_buffers[MAX_SRC_BUFFER_DEPTH]; static int src_buffer_depth = 0; static char *strdupped_get(char *text); static int strdupped_cmp(const void *a, const void *b); static void strdupped_free(void *a); int num_lines = 1; int push_state_skip = 0; int push_state_init = 0; int push_state_macro = 0; struct vec strdupped[1]; %} %x SKIP SKIP_ALL QUOTED_STRING SKIP_LINE MACROO %option noyywrap %option case-insensitive %option stack %% if(push_state_init) {push_state_init = 0; yy_push_state(INITIAL); } if(push_state_skip) {push_state_skip = 0; yy_push_state(SKIP); } if(push_state_macro) {push_state_macro = 0; yy_push_state(MACROO); } \.if return IF; \.elif BEGIN(SKIP_ALL); \.else BEGIN(SKIP); \.endif yy_pop_state(); \.include return INCLUDE; \.macro return MACRO; \.defined return DEFINED; \.org return ORG; \.error return ERROR; \.echo return ECHO1; \.incbin return INCBIN; \.inclen return INCLEN; \.incword return INCWORD; \.res return RES; \.word return WORD; \.byte return BYTE; \" BEGIN(QUOTED_STRING); \; BEGIN(SKIP_LINE); lda return LDA; ldx return LDX; ldy return LDY; sta return STA; stx return STX; sty return STY; and return AND; ora return ORA; eor return EOR; adc return ADC; sbc return SBC; cmp return CMP; cpx return CPX; cpy return CPY; tsx return TSX; txs return TXS; pha return PHA; pla return PLA; php return PHP; plp return PLP; sei return SEI; cli return CLI; nop return NOP; tya return TYA; tay return TAY; txa return TXA; tax return TAX; clc return CLC; sec return SEC; rts return RTS; jsr return JSR; jmp return JMP; beq return BEQ; bne return BNE; bcc return BCC; bcs return BCS; bpl return BPL; bmi return BMI; bvc return BVC; bvs return BCS; inx return INX; dex return DEX; iny return INY; dey return DEY; inc return INC; dec return DEC; lsr return LSR; asl return ASL; ror return ROR; rol return ROL; bit return BIT; [0-9]+ { yylval.num = atoi(yytext); return NUMBER; } $[0-9a-f]+ { yylval.num = strtol(yytext + 1, NULL, 16); return NUMBER; } \< return LT; \> return GT; == return EQ; != return NEQ; ! return LNOT; \&\& return LAND; \|\| return LOR; \( return LPAREN; \) return RPAREN; \, return COMMA; \: return COLON; \# return HASH; \+ return PLUS; \- return MINUS; \* return MULT; \/ return DIV; \% return MOD; \= return ASSIGN; \?= return GUESS; x return X; y return Y; [a-z][_a-z0-9]*/: { yylval.str = strdupped_get(yytext); return LABEL; } [a-z][_a-z0-9]* { yylval.str = strdupped_get(yytext); return SYMBOL; } \r\n|\n ++num_lines; [ \t] /* eat whitespace */ . printf("unknown character found %s\n", yytext); \.if yy_push_state(SKIP_ALL); \.elif { yy_pop_state(); return IF; } \.else BEGIN(INITIAL); \.endif yy_pop_state(); \r\n|\n ++num_lines; . \.endmacro yy_pop_state(); \.+ { yylval.str = yytext; return MACRO_STRING; } [^\.]+ { yylval.str = yytext; return MACRO_STRING; } \.if yy_push_state(SKIP_ALL); \.endif yy_pop_state(); \r\n|\n ++num_lines; . [^\"]* { /* multi-line string with correct line count */ char *p = strdupped_get(yytext); yylval.str = p; while (*p != '\0') { if (*p++ == '\n') { ++num_lines; } } return STRING; } \" BEGIN(INITIAL); \r\n|\n { ++num_lines; BEGIN(INITIAL); } . <> { if(--src_buffer_depth == 0) { yyterminate(); } else { yy_delete_buffer(YY_CURRENT_BUFFER); yy_switch_to_buffer(src_buffers[src_buffer_depth]); } } %% void scanner_init(void) { vec_init(strdupped, sizeof(char*)); } void asm_src_buffer_push(struct membuf *buffer) { if(src_buffer_depth == MAX_SRC_BUFFER_DEPTH) { fprintf(stderr, "source buffers nested too deep\n"); exit(1); } src_buffers[src_buffer_depth++] = YY_CURRENT_BUFFER; yy_scan_bytes(membuf_get(buffer), membuf_memlen(buffer)); } static char *strdupped_get(char *text) { char **pp; /*printf("get \"%s\" => ", text);*/ if(vec_insert_uniq(strdupped, strdupped_cmp, &text, (void*)&pp)) { /* replace the pointer to since will be reused */ *pp = strdup(text); } /*printf("%p\n", *pp);*/ return *pp; } static void strdupped_free(void *a) { char *b = *(char**)a; /*printf("free => %p \"%s\"\n", b, b);*/ free(b); } static int strdupped_cmp(const void *a, const void *b) { char *c = *(char**)a; char *d = *(char**)b; return strcmp(c, d); } void scanner_free(void) { vec_free(strdupped, strdupped_free); } void silence_warnings_about_unused_functions(void) { yyunput(0, NULL); input(); yy_top_state(); }