Support use of NASM preprocessor with GAS parser.
authorPeter Johnson <peter@tortall.net>
Fri, 25 Apr 2008 06:50:36 +0000 (06:50 -0000)
committerPeter Johnson <peter@tortall.net>
Fri, 25 Apr 2008 06:50:36 +0000 (06:50 -0000)
Note: this combination is obviously not supported by any other assembler.

Requested by: Brian Gladman <brg@gladman.plus.com>

svn path=/trunk/yasm/; revision=2076

modules/parsers/gas/gas-parse.c
modules/parsers/gas/gas-parser.c
modules/parsers/gas/gas-parser.h
modules/parsers/gas/gas-token.re

index 583e39e0a4ab2ec04339edf219d324c3c4577042..1873521a31bb9998ab24138361a21d79f631fab7 100644 (file)
@@ -44,7 +44,8 @@ typedef struct dir_lookup {
     enum gas_parser_state newstate;
 } dir_lookup;
 
-static yasm_bytecode * cpp_line_marker(yasm_parser_gas *parser_gas);
+static void cpp_line_marker(yasm_parser_gas *parser_gas);
+static void nasm_line_marker(yasm_parser_gas *parser_gas);
 static yasm_bytecode *parse_instr(yasm_parser_gas *parser_gas);
 static int parse_dirvals(yasm_parser_gas *parser_gas, yasm_valparamhead *vps);
 static int parse_datavals(yasm_parser_gas *parser_gas, yasm_datavalhead *dvs);
@@ -248,9 +249,14 @@ parse_line(yasm_parser_gas *parser_gas)
             define_label(parser_gas, LABEL_val, 0);
             get_next_token(); /* LABEL */
             return parse_line(parser_gas);
-        case LINE_MARKER:
+        case CPP_LINE_MARKER:
             get_next_token();
-            return cpp_line_marker(parser_gas);
+            cpp_line_marker(parser_gas);
+            return NULL;
+        case NASM_LINE_MARKER:
+            get_next_token();
+            nasm_line_marker(parser_gas);
+            return NULL;
         default:
             yasm_error_set(YASM_ERROR_SYNTAX,
                 N_("label or instruction expected at start of line"));
@@ -268,10 +274,10 @@ parse_line(yasm_parser_gas *parser_gas)
     without adding a filter to the input before passing it to cpp.
 
     This function is only called if the preprocessor was 'cpp', since the
-    LINE_MARKER token isn't generated for any other preprocessor. With any other
-    preprocessor, anything after a '#' is always treated as a comment.
+    CPP_LINE_MARKER token isn't generated for any other preprocessor. With any
+    other preprocessor, anything after a '#' is always treated as a comment.
 */
-static yasm_bytecode *
+static void
 cpp_line_marker(yasm_parser_gas *parser_gas)
 {
     yasm_valparamhead vps;
@@ -285,14 +291,14 @@ cpp_line_marker(yasm_parser_gas *parser_gas)
         while (curtok != '\n')
             get_next_token();
 
-        return NULL;
+        return;
     }
 
     if (yasm_intnum_sign(INTNUM_val) < 0) {
         get_next_token(); /* INTNUM */
         yasm_error_set(YASM_ERROR_SYNTAX,
                        N_("line number is negative"));
-        return NULL;
+        return;
     }
 
     line = yasm_intnum_get_uint(INTNUM_val);
@@ -315,7 +321,7 @@ cpp_line_marker(yasm_parser_gas *parser_gas)
         while (curtok != '\n')
             get_next_token();
 
-        return NULL;
+        return;
     }
 
     filename = STRING_val.contents;
@@ -339,7 +345,8 @@ cpp_line_marker(yasm_parser_gas *parser_gas)
         yasm_object_directive(p_object, ".file", "gas", &vps, NULL, cur_line);
 
         yasm_vps_delete(&vps);
-    }
+    } else
+        yasm_xfree(filename);
 
     /* Skip flags. */
     while (1) {
@@ -348,18 +355,98 @@ cpp_line_marker(yasm_parser_gas *parser_gas)
                 break;
 
             case '\n':
-                return NULL;
+                return;
 
             default:
                 yasm_error_set(YASM_ERROR_SYNTAX,
                     N_("junk at end of cpp line marker"));
-                return NULL;
+                return;
         }
         get_next_token();
     }
+}
 
-    /* Never reached. */
-    return NULL;
+/*
+    Handle line markers generated by the nasm preproc.
+
+    We expect a positive integer (line) followed by a plus sign, followed by
+    another positive integer, followed by a string (filename).
+
+    This function is only called if the preprocessor was 'nasm', since the
+    NASM_LINE_MARKER token isn't generated for any other preprocessor.
+*/
+static void
+nasm_line_marker(yasm_parser_gas *parser_gas)
+{
+    yasm_valparamhead vps;
+    yasm_valparam *vp;
+    unsigned long line, incr;
+    char *filename;
+
+    /* Line number. */
+    if (!expect(INTNUM)) return;
+
+    if (yasm_intnum_sign(INTNUM_val) < 0) {
+        get_next_token(); /* INTNUM */
+        yasm_error_set(YASM_ERROR_SYNTAX,
+                       N_("line number is negative"));
+        return;
+    }
+
+    line = yasm_intnum_get_uint(INTNUM_val);
+
+    yasm_intnum_destroy(INTNUM_val);
+    get_next_token(); /* INTNUM */
+
+    if (!expect('+')) return;
+    get_next_token(); /* + */
+
+    /* Line number increment. */
+    if (!expect(INTNUM)) return;
+
+    if (yasm_intnum_sign(INTNUM_val) < 0) {
+        get_next_token(); /* INTNUM */
+        yasm_error_set(YASM_ERROR_SYNTAX,
+                       N_("line increment is negative"));
+        return;
+    }
+
+    incr = yasm_intnum_get_uint(INTNUM_val);
+    yasm_intnum_destroy(INTNUM_val);
+
+    /* File name is not in quotes, so need to switch to a different tokenizer
+     * state.
+     */
+    parser_gas->state = NASM_FILENAME;
+    get_next_token(); /* INTNUM */
+    if (!expect(STRING)) {
+        parser_gas->state = INITIAL;
+        return;
+    }
+
+    filename = STRING_val.contents;
+    get_next_token(); /* STRING */
+
+    /* Set linemap. */
+    yasm_linemap_set(parser_gas->linemap, filename, line, incr);
+
+    /*
+        The first line marker in the file (which should be on the first line
+        of the file) will give us the name of the source file. This information
+        needs to be passed on to the debug format module.
+    */
+    if (parser_gas->seen_line_marker == 0) {
+        parser_gas->seen_line_marker = 1;
+
+        yasm_vps_initialize(&vps);
+        vp = yasm_vp_create_string(NULL, filename);
+        yasm_vps_append(&vps, vp);
+
+        yasm_object_directive(p_object, ".file", "gas", &vps, NULL, cur_line);
+
+        yasm_vps_delete(&vps);
+    } else
+        yasm_xfree(filename);
 }
 
 /* Line directive */
index 80bd5039c0abb07f58a6a82b95d0a838cc33a6a8..1e7fb8b66cdf0720d73aac376653cb0ab3942565 100644 (file)
@@ -76,6 +76,11 @@ gas_parser_do_parse(yasm_object *object, yasm_preproc *pp,
     for (i=0; i<10; i++)
         parser_gas.local[i] = 0;
 
+    parser_gas.is_cpp_preproc =
+        yasm__strcasecmp(((yasm_preproc_base*)pp)->module->keyword, "cpp") == 0;
+    parser_gas.is_nasm_preproc =
+        yasm__strcasecmp(((yasm_preproc_base*)pp)->module->keyword, "nasm") == 0;
+
     /* yacc debugging, needs YYDEBUG set in bison.y.in to work */
     parser_gas.debug = 1;
 
@@ -114,6 +119,7 @@ gas_parser_do_parse(yasm_object *object, yasm_preproc *pp,
 static const char *gas_parser_preproc_keywords[] = {
     "raw",
     "cpp",
+    "nasm",
     NULL
 };
 
index 0a22e3e4fa67670693885b1d2f1077e16b08cea2..70704b5366de07447bfdc52cb45067a1a052c986 100644 (file)
@@ -48,7 +48,8 @@ enum tokentype {
     RIGHT_OP,
     ID,
     LABEL,
-    LINE_MARKER,
+    CPP_LINE_MARKER,
+    NASM_LINE_MARKER,
     NONE
 };
 
@@ -90,7 +91,8 @@ enum gas_parser_state {
     INITIAL,
     COMMENT,
     SECTION_DIRECTIVE,
-    INSTDIR
+    INSTDIR,
+    NASM_FILENAME
 };
 
 typedef struct yasm_parser_gas {
@@ -147,6 +149,9 @@ typedef struct yasm_parser_gas {
 
     /* Parser-handled directives HAMT lookup */
     HAMT *dirs;
+
+    int is_nasm_preproc;
+    int is_cpp_preproc;
 } yasm_parser_gas;
 
 /* shorter access names to commonly used parser_gas fields */
index c72ce901e77a3cb35a1681a050b26d82b0ae7cee..c08da11a1afeb6f22c1bfd0e0ad36c88b64dee8a 100644 (file)
@@ -302,6 +302,8 @@ gas_parser_lex(YYSTYPE *lvalp, yasm_parser_gas *parser_gas)
             goto comment;
         case SECTION_DIRECTIVE:
             goto section_directive;
+        case NASM_FILENAME:
+            goto nasm_filename;
         default:
             break;
     }
@@ -387,6 +389,11 @@ scan:
         [%][a-zA-Z0-9]+ {
             savech = s->tok[TOKLEN];
             s->tok[TOKLEN] = '\0';
+            if (parser_gas->is_nasm_preproc && strcmp(TOK+1, "line") == 0) {
+                s->tok[TOKLEN] = savech;
+                RETURN(NASM_LINE_MARKER);
+            }
+
             switch (yasm_arch_parse_check_regtmod
                     (p_object->arch, TOK+1, TOKLEN-1, &lvalp->arch_data)) {
                 case YASM_ARCH_REG:
@@ -482,10 +489,9 @@ scan:
 
         "/*"                    { parser_gas->state = COMMENT; goto comment; }
         "#"                     {
-            if (strcmp(((yasm_preproc_base*)parser_gas->preproc)->module->keyword,
-                 "cpp") == 0)
+            if (parser_gas->is_cpp_preproc)
             {
-                RETURN(LINE_MARKER);
+                RETURN(CPP_LINE_MARKER);
             } else
                 goto line_comment;
         }
@@ -569,6 +575,39 @@ section_directive:
         }
     */
 
+    /* filename portion of nasm preproc %line */
+nasm_filename:
+    strbuf = yasm_xmalloc(STRBUF_ALLOC_SIZE);
+    strbuf_size = STRBUF_ALLOC_SIZE;
+    count = 0;
+
+nasm_filename_scan:
+    SCANINIT();
+
+    /*!re2c
+        "\n" {
+            strbuf_append(count++, cursor, s, '\0');
+            lvalp->str.contents = (char *)strbuf;
+            lvalp->str.len = count;
+            parser_gas->state = INITIAL;
+            RETURN(STRING);
+        }
+
+        ws+ { goto nasm_filename_scan; }
+
+        any {
+            if (cursor == s->eof) {
+                strbuf_append(count++, cursor, s, '\0');
+                lvalp->str.contents = (char *)strbuf;
+                lvalp->str.len = count;
+                parser_gas->state = INITIAL;
+                RETURN(STRING);
+            }
+            strbuf_append(count++, cursor, s, s->tok[0]);
+            goto nasm_filename_scan;
+        }
+    */
+
     /* character constant values */
 charconst:
     /*TODO*/