Identifiers can start and/or contain '.' in *.S

modified version of the old one which don't allow '.'
    in #define Identifiers. This allow correctly preprocess
    the following code in *.S

        #define SRC(y...)               \
        9999: y;                        \
        .section __ex_table, "a";       \
        .long 9999b, 6001f      ;       \
        // .previous

        SRC(1: movw (%esi), %bx)
        6001:

    A test included.
master
seyko 2016-04-05 10:43:50 +03:00
parent 21665f4338
commit d3e85e80fd
8 changed files with 115 additions and 73 deletions

4
tcc.h
View File

@ -957,7 +957,9 @@ struct TCCState {
#define DEF_ASM(x) DEF(TOK_ASM_ ## x, #x) #define DEF_ASM(x) DEF(TOK_ASM_ ## x, #x)
#define TOK_ASM_int TOK_INT #define TOK_ASM_int TOK_INT
#define TOK_ASM_weak TOK_WEAK1 #define DEF_ASMDIR(x) DEF(TOK_ASMDIR_ ## x, "." #x)
#define TOK_ASMDIR_FIRST TOK_ASMDIR_byte
#define TOK_ASMDIR_LAST TOK_ASMDIR_section
#if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64 #if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64
/* only used for i386 asm opcodes definitions */ /* only used for i386 asm opcodes definitions */

View File

@ -331,24 +331,23 @@ static void asm_parse_directive(TCCState *s1)
uint8_t *ptr; uint8_t *ptr;
/* assembler directive */ /* assembler directive */
next();
sec = cur_text_section; sec = cur_text_section;
switch(tok) { switch(tok) {
case TOK_ASM_align: case TOK_ASMDIR_align:
case TOK_ASM_p2align: case TOK_ASMDIR_p2align:
case TOK_ASM_skip: case TOK_ASMDIR_skip:
case TOK_ASM_space: case TOK_ASMDIR_space:
tok1 = tok; tok1 = tok;
next(); next();
n = asm_int_expr(s1); n = asm_int_expr(s1);
if (tok1 == TOK_ASM_p2align) if (tok1 == TOK_ASMDIR_p2align)
{ {
if (n < 0 || n > 30) if (n < 0 || n > 30)
tcc_error("invalid p2align, must be between 0 and 30"); tcc_error("invalid p2align, must be between 0 and 30");
n = 1 << n; n = 1 << n;
tok1 = TOK_ASM_align; tok1 = TOK_ASMDIR_align;
} }
if (tok1 == TOK_ASM_align) { if (tok1 == TOK_ASMDIR_align) {
if (n < 0 || (n & (n-1)) != 0) if (n < 0 || (n & (n-1)) != 0)
tcc_error("alignment must be a positive power of two"); tcc_error("alignment must be a positive power of two");
offset = (ind + n - 1) & -n; offset = (ind + n - 1) & -n;
@ -372,7 +371,7 @@ static void asm_parse_directive(TCCState *s1)
} }
ind += size; ind += size;
break; break;
case TOK_ASM_quad: case TOK_ASMDIR_quad:
next(); next();
for(;;) { for(;;) {
uint64_t vl; uint64_t vl;
@ -399,15 +398,15 @@ static void asm_parse_directive(TCCState *s1)
next(); next();
} }
break; break;
case TOK_ASM_byte: case TOK_ASMDIR_byte:
size = 1; size = 1;
goto asm_data; goto asm_data;
case TOK_ASM_word: case TOK_ASMDIR_word:
case TOK_SHORT: case TOK_ASMDIR_short:
size = 2; size = 2;
goto asm_data; goto asm_data;
case TOK_LONG: case TOK_ASMDIR_long:
case TOK_INT: case TOK_ASMDIR_int:
size = 4; size = 4;
asm_data: asm_data:
next(); next();
@ -433,7 +432,7 @@ static void asm_parse_directive(TCCState *s1)
next(); next();
} }
break; break;
case TOK_ASM_fill: case TOK_ASMDIR_fill:
{ {
int repeat, size, val, i, j; int repeat, size, val, i, j;
uint8_t repeat_buf[8]; uint8_t repeat_buf[8];
@ -475,7 +474,7 @@ static void asm_parse_directive(TCCState *s1)
} }
} }
break; break;
case TOK_ASM_org: case TOK_ASMDIR_org:
{ {
unsigned long n; unsigned long n;
next(); next();
@ -488,10 +487,10 @@ static void asm_parse_directive(TCCState *s1)
goto zero_pad; goto zero_pad;
} }
break; break;
case TOK_ASM_globl: case TOK_ASMDIR_globl:
case TOK_ASM_global: case TOK_ASMDIR_global:
case TOK_ASM_weak: case TOK_ASMDIR_weak:
case TOK_ASM_hidden: case TOK_ASMDIR_hidden:
tok1 = tok; tok1 = tok;
do { do {
Sym *sym; Sym *sym;
@ -502,18 +501,18 @@ static void asm_parse_directive(TCCState *s1)
sym = label_push(&s1->asm_labels, tok, 0); sym = label_push(&s1->asm_labels, tok, 0);
sym->type.t = VT_VOID; sym->type.t = VT_VOID;
} }
if (tok1 != TOK_ASM_hidden) if (tok1 != TOK_ASMDIR_hidden)
sym->type.t &= ~VT_STATIC; sym->type.t &= ~VT_STATIC;
if (tok1 == TOK_ASM_weak) if (tok1 == TOK_ASMDIR_weak)
sym->type.t |= VT_WEAK; sym->type.t |= VT_WEAK;
else if (tok1 == TOK_ASM_hidden) else if (tok1 == TOK_ASMDIR_hidden)
sym->type.t |= STV_HIDDEN << VT_VIS_SHIFT; sym->type.t |= STV_HIDDEN << VT_VIS_SHIFT;
next(); next();
} while (tok == ','); } while (tok == ',');
break; break;
case TOK_ASM_string: case TOK_ASMDIR_string:
case TOK_ASM_ascii: case TOK_ASMDIR_ascii:
case TOK_ASM_asciz: case TOK_ASMDIR_asciz:
{ {
const uint8_t *p; const uint8_t *p;
int i, size, t; int i, size, t;
@ -525,7 +524,7 @@ static void asm_parse_directive(TCCState *s1)
expect("string constant"); expect("string constant");
p = tokc.str.data; p = tokc.str.data;
size = tokc.str.size; size = tokc.str.size;
if (t == TOK_ASM_ascii && size > 0) if (t == TOK_ASMDIR_ascii && size > 0)
size--; size--;
for(i = 0; i < size; i++) for(i = 0; i < size; i++)
g(p[i]); g(p[i]);
@ -538,9 +537,9 @@ static void asm_parse_directive(TCCState *s1)
} }
} }
break; break;
case TOK_ASM_text: case TOK_ASMDIR_text:
case TOK_ASM_data: case TOK_ASMDIR_data:
case TOK_ASM_bss: case TOK_ASMDIR_bss:
{ {
char sname[64]; char sname[64];
tok1 = tok; tok1 = tok;
@ -557,7 +556,7 @@ static void asm_parse_directive(TCCState *s1)
use_section(s1, sname); use_section(s1, sname);
} }
break; break;
case TOK_ASM_file: case TOK_ASMDIR_file:
{ {
char filename[512]; char filename[512];
@ -575,7 +574,7 @@ static void asm_parse_directive(TCCState *s1)
next(); next();
} }
break; break;
case TOK_ASM_ident: case TOK_ASMDIR_ident:
{ {
char ident[256]; char ident[256];
@ -593,7 +592,7 @@ static void asm_parse_directive(TCCState *s1)
next(); next();
} }
break; break;
case TOK_ASM_size: case TOK_ASMDIR_size:
{ {
Sym *sym; Sym *sym;
@ -614,7 +613,7 @@ static void asm_parse_directive(TCCState *s1)
} }
} }
break; break;
case TOK_ASM_type: case TOK_ASMDIR_type:
{ {
Sym *sym; Sym *sym;
const char *newtype; const char *newtype;
@ -632,7 +631,7 @@ static void asm_parse_directive(TCCState *s1)
newtype = tokc.str.data; newtype = tokc.str.data;
} else { } else {
if (tok == '@' || tok == '%') if (tok == '@' || tok == '%')
skip(tok); next();
newtype = get_tok_str(tok, NULL); newtype = get_tok_str(tok, NULL);
} }
@ -646,7 +645,7 @@ static void asm_parse_directive(TCCState *s1)
next(); next();
} }
break; break;
case TOK_SECTION1: case TOK_ASMDIR_section:
{ {
char sname[256]; char sname[256];
@ -666,12 +665,18 @@ static void asm_parse_directive(TCCState *s1)
if (tok != TOK_STR) if (tok != TOK_STR)
expect("string constant"); expect("string constant");
next(); next();
if (tok == ',') {
next();
if (tok == '@' || tok == '%')
next();
next();
}
} }
last_text_section = cur_text_section; last_text_section = cur_text_section;
use_section(s1, sname); use_section(s1, sname);
} }
break; break;
case TOK_ASM_previous: case TOK_ASMDIR_previous:
{ {
Section *sec; Section *sec;
next(); next();
@ -683,13 +688,13 @@ static void asm_parse_directive(TCCState *s1)
} }
break; break;
#ifdef TCC_TARGET_I386 #ifdef TCC_TARGET_I386
case TOK_ASM_code16: case TOK_ASMDIR_code16:
{ {
next(); next();
s1->seg_size = 16; s1->seg_size = 16;
} }
break; break;
case TOK_ASM_code32: case TOK_ASMDIR_code32:
{ {
next(); next();
s1->seg_size = 32; s1->seg_size = 32;
@ -698,7 +703,7 @@ static void asm_parse_directive(TCCState *s1)
#endif #endif
#ifdef TCC_TARGET_X86_64 #ifdef TCC_TARGET_X86_64
/* added for compatibility with GAS */ /* added for compatibility with GAS */
case TOK_ASM_code64: case TOK_ASMDIR_code64:
next(); next();
break; break;
#endif #endif
@ -763,7 +768,7 @@ static int tcc_assemble_internal(TCCState *s1, int do_preprocess)
/* horrible gas comment */ /* horrible gas comment */
while (tok != TOK_LINEFEED) while (tok != TOK_LINEFEED)
next(); next();
} else if (tok == '.') { } else if (tok >= TOK_ASMDIR_FIRST && tok <= TOK_ASMDIR_LAST) {
asm_parse_directive(s1); asm_parse_directive(s1);
} else if (tok == TOK_PPNUM) { } else if (tok == TOK_PPNUM) {
const char *p; const char *p;

12
tccpp.c
View File

@ -1328,6 +1328,8 @@ ST_FUNC void parse_define(void)
parse_flags |= PARSE_FLAG_SPACES; parse_flags |= PARSE_FLAG_SPACES;
next_nomacro_spc(); next_nomacro_spc();
if (tok == '(') { if (tok == '(') {
/* must be able to parse TOK_DOTS (in asm mode '.' can be part of identifier) */
parse_flags &= ~PARSE_FLAG_ASM_FILE;
next_nomacro(); next_nomacro();
ps = &first; ps = &first;
if (tok != ')') for (;;) { if (tok != ')') for (;;) {
@ -1355,6 +1357,7 @@ ST_FUNC void parse_define(void)
} }
next_nomacro_spc(); next_nomacro_spc();
t = MACRO_FUNC; t = MACRO_FUNC;
parse_flags |= (saved_parse_flags & PARSE_FLAG_ASM_FILE);
} }
tok_str_new(&str); tok_str_new(&str);
spc = 2; spc = 2;
@ -2460,7 +2463,8 @@ maybe_newline:
p1 = p; p1 = p;
h = TOK_HASH_INIT; h = TOK_HASH_INIT;
h = TOK_HASH_FUNC(h, c); h = TOK_HASH_FUNC(h, c);
while (c = *++p, isidnum_table[c - CH_EOF] & (IS_ID|IS_NUM)) while (c = *++p, (isidnum_table[c - CH_EOF] & (IS_ID|IS_NUM))
|| (c == '.' && (parse_flags & PARSE_FLAG_ASM_FILE)))
h = TOK_HASH_FUNC(h, c); h = TOK_HASH_FUNC(h, c);
if (c != '\\') { if (c != '\\') {
TokenSym **pts; TokenSym **pts;
@ -2492,7 +2496,9 @@ maybe_newline:
p--; p--;
PEEKC(c, p); PEEKC(c, p);
parse_ident_slow: parse_ident_slow:
while (isidnum_table[c - CH_EOF] & (IS_ID|IS_NUM)) { while ((isidnum_table[c - CH_EOF] & (IS_ID|IS_NUM))
|| (c == '.' && (parse_flags & PARSE_FLAG_ASM_FILE)))
{
cstr_ccat(&tokcstr, c); cstr_ccat(&tokcstr, c);
PEEKC(c, p); PEEKC(c, p);
} }
@ -2551,7 +2557,7 @@ maybe_newline:
cstr_reset(&tokcstr); cstr_reset(&tokcstr);
cstr_ccat(&tokcstr, '.'); cstr_ccat(&tokcstr, '.');
goto parse_num; goto parse_num;
} else if ((isidnum_table['.' - CH_EOF] & IS_ID) != 0) { /* asm mode */ } else if (parse_flags & PARSE_FLAG_ASM_FILE) {
*--p = c = '.'; *--p = c = '.';
goto parse_ident_fast; goto parse_ident_fast;
} else if (c == '.') { } else if (c == '.') {

View File

@ -301,35 +301,40 @@
#endif #endif
/* Tiny Assembler */ /* Tiny Assembler */
DEF_ASM(byte) DEF_ASMDIR(byte) /* must be first directive */
DEF_ASM(word) DEF_ASMDIR(word)
DEF_ASM(align) DEF_ASMDIR(align)
DEF_ASM(p2align) DEF_ASMDIR(p2align)
DEF_ASM(skip) DEF_ASMDIR(skip)
DEF_ASM(space) DEF_ASMDIR(space)
DEF_ASM(string) DEF_ASMDIR(string)
DEF_ASM(asciz) DEF_ASMDIR(asciz)
DEF_ASM(ascii) DEF_ASMDIR(ascii)
DEF_ASM(file) DEF_ASMDIR(file)
DEF_ASM(globl) DEF_ASMDIR(globl)
DEF_ASM(global) DEF_ASMDIR(global)
DEF_ASM(hidden) DEF_ASMDIR(weak)
DEF_ASM(ident) DEF_ASMDIR(hidden)
DEF_ASM(size) DEF_ASMDIR(ident)
DEF_ASM(type) DEF_ASMDIR(size)
DEF_ASM(text) DEF_ASMDIR(type)
DEF_ASM(data) DEF_ASMDIR(text)
DEF_ASM(bss) DEF_ASMDIR(data)
DEF_ASM(previous) DEF_ASMDIR(bss)
DEF_ASM(fill) DEF_ASMDIR(previous)
DEF_ASM(org) DEF_ASMDIR(fill)
DEF_ASM(quad) DEF_ASMDIR(org)
DEF_ASMDIR(quad)
#if defined(TCC_TARGET_I386) #if defined(TCC_TARGET_I386)
DEF_ASM(code16) DEF_ASMDIR(code16)
DEF_ASM(code32) DEF_ASMDIR(code32)
#elif defined(TCC_TARGET_X86_64) #elif defined(TCC_TARGET_X86_64)
DEF_ASM(code64) DEF_ASMDIR(code64)
#endif #endif
DEF_ASMDIR(short)
DEF_ASMDIR(long)
DEF_ASMDIR(int)
DEF_ASMDIR(section) /* must be last directive */
#if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64 #if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64
#include "i386-tok.h" #include "i386-tok.h"

View File

@ -73,7 +73,11 @@ DISAS = objdump -d
# libtcc test # libtcc test
ifdef LIBTCC1 ifdef LIBTCC1
LIBTCC1:=$(TOP)/$(LIBTCC1) ifdef CONFIG_WIN32
LIBTCC1:=$(TOP)/win32/libtcc/libtcc.a
else
LIBTCC1:=$(TOP)/$(LIBTCC1)
endif
endif endif
all test : $(TESTS) all test : $(TESTS)

8
tests/pp/12.S 100644
View File

@ -0,0 +1,8 @@
#define SRC(y...) \
9999: y; \
.section __ex_table, "a"; \
.long 9999b, 6001f ; \
// .previous
SRC(1: movw (%esi), %bx)
6001:

View File

@ -0,0 +1,2 @@
9999: 1: movw (%esi), %bx; .section __ex_table, "a"; .long 9999b, 6001f ;
6001:

View File

@ -7,6 +7,7 @@ include $(TOP)/Makefile
TCC = $(TOP)/tcc TCC = $(TOP)/tcc
TESTS = $(patsubst %.c,%.test,$(wildcard *.c)) TESTS = $(patsubst %.c,%.test,$(wildcard *.c))
TESTS += $(patsubst %.S,%.test,$(wildcard *.S))
ifdef CONFIG_WIN32 ifdef CONFIG_WIN32
TCC = $(top_srcdir)/win32/tcc TCC = $(top_srcdir)/win32/tcc
@ -20,10 +21,19 @@ all test : $(TESTS)
diff -Nu -b -B -I "^#" $(EXTRA_DIFF_OPTS) $*.expect $*.output \ diff -Nu -b -B -I "^#" $(EXTRA_DIFF_OPTS) $*.expect $*.output \
&& rm -f $*.output && rm -f $*.output
%.test: %.S %.expect
@echo PPTest $* ...
@$(TCC) -E -P $< >$*.output 2>&1 ; \
diff -Nu -b -B -I "^#" $(EXTRA_DIFF_OPTS) $*.expect $*.output \
&& rm -f $*.output
# automatically generate .expect files with gcc: # automatically generate .expect files with gcc:
%.expect : %.expect: %.c
gcc -E -P $*.c >$*.expect 2>&1 gcc -E -P $*.c >$*.expect 2>&1
%.expect: %.S
gcc -E -P $*.S >$*.expect 2>&1
# tell make not to delete # tell make not to delete
.PRECIOUS: %.expect .PRECIOUS: %.expect