From 6a49afb3ed134240f64bc219e2fb73ffb72ed326 Mon Sep 17 00:00:00 2001
From: seyko <seyko2@gmail.com>
Date: Wed, 13 Apr 2016 10:23:46 +0300
Subject: [PATCH] correct version of "Identifiers can start and/or contain"

    A problem was in TOK_ASMDIR_text:
    -    sprintf(sname, ".%s", get_tok_str(tok1, NULL));
    +    sprintf(sname, "%s", get_tok_str(tok1, NULL));
    When tok1 is '.text', then sname is '..text'
---
 tcc.h    |  4 ++-
 tccasm.c | 91 ++++++++++++++++++++++++++++++--------------------------
 tccpp.c  | 14 +++++++--
 tcctok.h | 57 +++++++++++++++++++----------------
 4 files changed, 94 insertions(+), 72 deletions(-)

diff --git a/tcc.h b/tcc.h
index 831c145d..8e904961 100644
--- a/tcc.h
+++ b/tcc.h
@@ -974,7 +974,9 @@ struct TCCState {
 
 #define DEF_ASM(x) DEF(TOK_ASM_ ## x, #x)
 #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
 /* only used for i386 asm opcodes definitions */
diff --git a/tccasm.c b/tccasm.c
index 28e07fda..f6fe369d 100644
--- a/tccasm.c
+++ b/tccasm.c
@@ -331,24 +331,23 @@ static void asm_parse_directive(TCCState *s1)
     uint8_t *ptr;
 
     /* assembler directive */
-    next();
     sec = cur_text_section;
     switch(tok) {
-    case TOK_ASM_align:
-    case TOK_ASM_p2align:
-    case TOK_ASM_skip:
-    case TOK_ASM_space:
+    case TOK_ASMDIR_align:
+    case TOK_ASMDIR_p2align:
+    case TOK_ASMDIR_skip:
+    case TOK_ASMDIR_space:
         tok1 = tok;
         next();
         n = asm_int_expr(s1);
-        if (tok1 == TOK_ASM_p2align)
+        if (tok1 == TOK_ASMDIR_p2align)
         {
             if (n < 0 || n > 30)
                 tcc_error("invalid p2align, must be between 0 and 30");
             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)
                 tcc_error("alignment must be a positive power of two");
             offset = (ind + n - 1) & -n;
@@ -372,7 +371,7 @@ static void asm_parse_directive(TCCState *s1)
         }
         ind += size;
         break;
-    case TOK_ASM_quad:
+    case TOK_ASMDIR_quad:
         next();
         for(;;) {
             uint64_t vl;
@@ -399,15 +398,15 @@ static void asm_parse_directive(TCCState *s1)
             next();
         }
         break;
-    case TOK_ASM_byte:
+    case TOK_ASMDIR_byte:
         size = 1;
         goto asm_data;
-    case TOK_ASM_word:
-    case TOK_SHORT:
+    case TOK_ASMDIR_word:
+    case TOK_ASMDIR_short:
         size = 2;
         goto asm_data;
-    case TOK_LONG:
-    case TOK_INT:
+    case TOK_ASMDIR_long:
+    case TOK_ASMDIR_int:
         size = 4;
     asm_data:
         next();
@@ -433,7 +432,7 @@ static void asm_parse_directive(TCCState *s1)
             next();
         }
         break;
-    case TOK_ASM_fill:
+    case TOK_ASMDIR_fill:
         {
             int repeat, size, val, i, j;
             uint8_t repeat_buf[8];
@@ -475,7 +474,7 @@ static void asm_parse_directive(TCCState *s1)
             }
         }
         break;
-    case TOK_ASM_org:
+    case TOK_ASMDIR_org:
         {
             unsigned long n;
             next();
@@ -488,10 +487,10 @@ static void asm_parse_directive(TCCState *s1)
             goto zero_pad;
         }
         break;
-    case TOK_ASM_globl:
-    case TOK_ASM_global:
-    case TOK_ASM_weak:
-    case TOK_ASM_hidden:
+    case TOK_ASMDIR_globl:
+    case TOK_ASMDIR_global:
+    case TOK_ASMDIR_weak:
+    case TOK_ASMDIR_hidden:
     tok1 = tok;
 	do { 
             Sym *sym;
@@ -502,18 +501,18 @@ static void asm_parse_directive(TCCState *s1)
                 sym = label_push(&s1->asm_labels, tok, 0);
                 sym->type.t = VT_VOID;
             }
-	    if (tok1 != TOK_ASM_hidden)
+	    if (tok1 != TOK_ASMDIR_hidden)
                 sym->type.t &= ~VT_STATIC;
-            if (tok1 == TOK_ASM_weak)
+            if (tok1 == TOK_ASMDIR_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;
             next();
 	} while (tok == ',');
 	break;
-    case TOK_ASM_string:
-    case TOK_ASM_ascii:
-    case TOK_ASM_asciz:
+    case TOK_ASMDIR_string:
+    case TOK_ASMDIR_ascii:
+    case TOK_ASMDIR_asciz:
         {
             const uint8_t *p;
             int i, size, t;
@@ -525,7 +524,7 @@ static void asm_parse_directive(TCCState *s1)
                     expect("string constant");
                 p = tokc.str.data;
                 size = tokc.str.size;
-                if (t == TOK_ASM_ascii && size > 0)
+                if (t == TOK_ASMDIR_ascii && size > 0)
                     size--;
                 for(i = 0; i < size; i++)
                     g(p[i]);
@@ -538,9 +537,9 @@ static void asm_parse_directive(TCCState *s1)
             }
 	}
 	break;
-    case TOK_ASM_text:
-    case TOK_ASM_data:
-    case TOK_ASM_bss:
+    case TOK_ASMDIR_text:
+    case TOK_ASMDIR_data:
+    case TOK_ASMDIR_bss:
 	{ 
             char sname[64];
             tok1 = tok;
@@ -551,13 +550,13 @@ static void asm_parse_directive(TCCState *s1)
 		next();
             }
             if (n)
-                sprintf(sname, ".%s%d", get_tok_str(tok1, NULL), n);
+                sprintf(sname, "%s%d", get_tok_str(tok1, NULL), n);
             else
-                sprintf(sname, ".%s", get_tok_str(tok1, NULL));
+                sprintf(sname, "%s", get_tok_str(tok1, NULL));
             use_section(s1, sname);
 	}
 	break;
-    case TOK_ASM_file:
+    case TOK_ASMDIR_file:
         {
             char filename[512];
 
@@ -575,7 +574,7 @@ static void asm_parse_directive(TCCState *s1)
             next();
         }
         break;
-    case TOK_ASM_ident:
+    case TOK_ASMDIR_ident:
         {
             char ident[256];
 
@@ -593,7 +592,7 @@ static void asm_parse_directive(TCCState *s1)
             next();
         }
         break;
-    case TOK_ASM_size:
+    case TOK_ASMDIR_size:
         { 
             Sym *sym;
 
@@ -614,7 +613,7 @@ static void asm_parse_directive(TCCState *s1)
             }
         }
         break;
-    case TOK_ASM_type:
+    case TOK_ASMDIR_type:
         { 
             Sym *sym;
             const char *newtype;
@@ -632,7 +631,7 @@ static void asm_parse_directive(TCCState *s1)
                 newtype = tokc.str.data;
             } else {
                 if (tok == '@' || tok == '%')
-                    skip(tok);
+                    next();
                 newtype = get_tok_str(tok, NULL);
             }
 
@@ -646,7 +645,7 @@ static void asm_parse_directive(TCCState *s1)
             next();
         }
         break;
-    case TOK_SECTION1:
+    case TOK_ASMDIR_section:
         {
             char sname[256];
 
@@ -666,12 +665,18 @@ static void asm_parse_directive(TCCState *s1)
                 if (tok != TOK_STR)
                     expect("string constant");
                 next();
+                if (tok == ',') {
+                    next();
+                    if (tok == '@' || tok == '%')
+                        next();
+                    next();
+                }
             }
             last_text_section = cur_text_section;
             use_section(s1, sname);
         }
         break;
-    case TOK_ASM_previous:
+    case TOK_ASMDIR_previous:
         { 
             Section *sec;
             next();
@@ -683,13 +688,13 @@ static void asm_parse_directive(TCCState *s1)
         }
         break;
 #ifdef TCC_TARGET_I386
-    case TOK_ASM_code16:
+    case TOK_ASMDIR_code16:
         {
             next();
             s1->seg_size = 16;
         }
         break;
-    case TOK_ASM_code32:
+    case TOK_ASMDIR_code32:
         {
             next();
             s1->seg_size = 32;
@@ -698,7 +703,7 @@ static void asm_parse_directive(TCCState *s1)
 #endif
 #ifdef TCC_TARGET_X86_64
     /* added for compatibility with GAS */
-    case TOK_ASM_code64:
+    case TOK_ASMDIR_code64:
         next();
         break;
 #endif
@@ -763,7 +768,7 @@ static int tcc_assemble_internal(TCCState *s1, int do_preprocess)
             /* horrible gas comment */
             while (tok != TOK_LINEFEED)
                 next();
-        } else if (tok == '.') {
+        } else if (tok >= TOK_ASMDIR_FIRST && tok <= TOK_ASMDIR_LAST) {
             asm_parse_directive(s1);
         } else if (tok == TOK_PPNUM) {
             const char *p;
diff --git a/tccpp.c b/tccpp.c
index 603a65e8..c8687e37 100644
--- a/tccpp.c
+++ b/tccpp.c
@@ -1328,6 +1328,9 @@ ST_FUNC void parse_define(void)
     parse_flags |= PARSE_FLAG_SPACES;
     next_nomacro_spc();
     if (tok == '(') {
+        /* must be able to parse TOK_DOTS (in asm mode '.' can be part of identifier) */
+        parse_flags &= ~PARSE_FLAG_ASM_FILE;
+        isidnum_table['.' - CH_EOF] = 0;
         next_nomacro();
         ps = &first;
         if (tok != ')') for (;;) {
@@ -1355,6 +1358,9 @@ ST_FUNC void parse_define(void)
         }
         next_nomacro_spc();
         t = MACRO_FUNC;
+        parse_flags |= (saved_parse_flags & PARSE_FLAG_ASM_FILE);
+        isidnum_table['.' - CH_EOF] =
+            (parse_flags & PARSE_FLAG_ASM_FILE) ? IS_ID : 0;
     }
     tok_str_new(&str);
     spc = 2;
@@ -2508,7 +2514,8 @@ maybe_newline:
             p--;
             PEEKC(c, p);
         parse_ident_slow:
-            while (isidnum_table[c - CH_EOF] & (IS_ID|IS_NUM)) {
+            while (isidnum_table[c - CH_EOF] & (IS_ID|IS_NUM))
+            {
                 cstr_ccat(&tokcstr, c);
                 PEEKC(c, p);
             }
@@ -2567,7 +2574,7 @@ maybe_newline:
             cstr_reset(&tokcstr);
             cstr_ccat(&tokcstr, '.');
             goto parse_num;
-        } else if ((isidnum_table['.' - CH_EOF] & IS_ID) != 0) { /* asm mode */
+        } else if (parse_flags & PARSE_FLAG_ASM_FILE) {
             *--p = c = '.';
             goto parse_ident_fast;
         } else if (c == '.') {
@@ -3364,6 +3371,9 @@ ST_FUNC void preprocess_init(TCCState *s1)
 
     isidnum_table['$' - CH_EOF] =
         tcc_state->dollars_in_identifiers ? IS_ID : 0;
+
+    isidnum_table['.' - CH_EOF] =
+        (parse_flags & PARSE_FLAG_ASM_FILE) ? IS_ID : 0;
 }
 
 ST_FUNC void preprocess_new(void)
diff --git a/tcctok.h b/tcctok.h
index 31b6dae2..b2fbebf6 100644
--- a/tcctok.h
+++ b/tcctok.h
@@ -301,35 +301,40 @@
 #endif
 
 /* Tiny Assembler */
- DEF_ASM(byte)
- DEF_ASM(word)
- DEF_ASM(align)
- DEF_ASM(p2align)
- DEF_ASM(skip)
- DEF_ASM(space)
- DEF_ASM(string)
- DEF_ASM(asciz)
- DEF_ASM(ascii)
- DEF_ASM(file)
- DEF_ASM(globl)
- DEF_ASM(global)
- DEF_ASM(hidden)
- DEF_ASM(ident)
- DEF_ASM(size)
- DEF_ASM(type)
- DEF_ASM(text)
- DEF_ASM(data)
- DEF_ASM(bss)
- DEF_ASM(previous)
- DEF_ASM(fill)
- DEF_ASM(org)
- DEF_ASM(quad)
+ DEF_ASMDIR(byte)              /* must be first directive */
+ DEF_ASMDIR(word)
+ DEF_ASMDIR(align)
+ DEF_ASMDIR(p2align)
+ DEF_ASMDIR(skip)
+ DEF_ASMDIR(space)
+ DEF_ASMDIR(string)
+ DEF_ASMDIR(asciz)
+ DEF_ASMDIR(ascii)
+ DEF_ASMDIR(file)
+ DEF_ASMDIR(globl)
+ DEF_ASMDIR(global)
+ DEF_ASMDIR(weak)
+ DEF_ASMDIR(hidden)
+ DEF_ASMDIR(ident)
+ DEF_ASMDIR(size)
+ DEF_ASMDIR(type)
+ DEF_ASMDIR(text)
+ DEF_ASMDIR(data)
+ DEF_ASMDIR(bss)
+ DEF_ASMDIR(previous)
+ DEF_ASMDIR(fill)
+ DEF_ASMDIR(org)
+ DEF_ASMDIR(quad)
 #if defined(TCC_TARGET_I386)
- DEF_ASM(code16)
- DEF_ASM(code32)
+ DEF_ASMDIR(code16)
+ DEF_ASMDIR(code32)
 #elif defined(TCC_TARGET_X86_64)
- DEF_ASM(code64)
+ DEF_ASMDIR(code64)
 #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
 #include "i386-tok.h"