]> git.rm.cloudns.org Git - xonotic/gmqcc.git/commitdiff
Merge branch 'master' into diagnostics
authorDale Weiler <killfieldengine@gmail.com>
Fri, 26 Jul 2013 16:28:57 +0000 (16:28 +0000)
committerDale Weiler <killfieldengine@gmail.com>
Fri, 26 Jul 2013 16:28:57 +0000 (16:28 +0000)
Conflicts:
gmqcc.h
parser.c

1  2 
Makefile
conout.c
diag.c
gmqcc.h
intrin.h
lexer.c
lexer.h
main.c
opts.def
parser.c
test.c

diff --cc Makefile
Simple merge
diff --cc conout.c
Simple merge
diff --cc diag.c
index 78ad7a75a177a264e71ef27a30b8f00852a11fa5,0000000000000000000000000000000000000000..e7f9c460cdeff6cfd509a6da85ef9e1b9342b9d7
mode 100644,000000..100644
--- 1/diag.c
--- /dev/null
+++ b/diag.c
@@@ -1,280 -1,0 +1,282 @@@
 +/*
 + * Copyright (C) 2012, 2013
 + *     Dale Weiler
 + *
 + * Permission is hereby granted, free of charge, to any person obtaining a copy of
 + * this software and associated documentation files (the "Software"), to deal in
 + * the Software without restriction, including without limitation the rights to
 + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
 + * of the Software, and to permit persons to whom the Software is furnished to do
 + * so, subject to the following conditions:
 + *
 + * The above copyright notice and this permission notice shall be included in all
 + * copies or substantial portions of the Software.
 + *
 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 + * SOFTWARE.
 + */
++#include <string.h>
++
 +#include "gmqcc.h"
 +#include "lexer.h"
 +
 +typedef struct {
 +    const char *line;    /* contents of the current line */
 +    size_t     *tokens;  /* stream of tokens             */
 +    char      **values;  /* stream of values for tokens  */
 +} diagnostic_data_t;
 +
 +/* map<const char *, vector<diagnostic_data_t>> */
 +static ht diagnostic_table = NULL;
 +
 +static void diagnostic_line(const char *file, size_t line, diagnostic_data_t ***read, size_t beg, size_t end) {
 +    diagnostic_data_t  **datas = NULL;
 +    size_t               feed  = 0;
 +
 +    if (!diagnostic_table)
 +         diagnostic_table = util_htnew(1024);
 +
 +    /*
 +     * Build the data one line at a time if it doesn't already exists.
 +     * We also lex one line at a time for consistency here.
 +     */
 +    if (!(datas = (diagnostic_data_t**)util_htget(diagnostic_table, file))) {
 +        lex_file          *lexer  = NULL;
 +        char              *next   = NULL;
 +        FILE              *handle = fs_file_open(file, "r");
 +        size_t             size   = 0;
 +        size_t             tok    = 0;
 +
 +        /*
 +         * Now process all data line per line from the file, while inserting
 +         * the contents of each line into data.line, the token stream for
 +         * each line into data.tokens, and the values that are associated
 +         * with that given token into data.values. Then after one line is
 +         * complete, push the data associated with it into the datas vector
 +         * which will be stored alongside the hashtable.
 +         */
 +        while (fs_file_getline(&next, &size, handle) != EOF) {
 +            diagnostic_data_t *data    = (diagnostic_data_t*)mem_a(sizeof(diagnostic_data_t));
 +            
 +            data->tokens               = NULL;
 +            data->values               = NULL;
 +            data->line                 = util_strdup(next);
 +            lexer                      = lex_open_string(next, strlen(next), file);
 +            lexer->flags.preprocessing = true; /* enable whitespace */
 +            lexer->flags.mergelines    = true;
 +            
 +            /* build token stream */
 +            while ((tok = lex_do(lexer)) != TOKEN_EOF) {
 +                char *string = NULL;
 +                char *claim  = lexer->tok.value;
 +                
 +                for (; claim && *claim; claim ++)
 +                    vec_push(string, (*claim == '\t') ? ' ' : *claim);
 +                    
 +                vec_push(string, '\0');
 +                vec_push(data->tokens, tok);
 +                vec_push(data->values, string);
 +                
 +                /* prevent duplicated entries */
 +                memset(&lexer->tok, 0, sizeof(lexer->tok));
 +            }
 +            
 +            lex_close(lexer);
 +            vec_push(datas, data);
 +        }
 +        
 +        /*mem_d(data);*/
 +        util_htset(diagnostic_table, file, datas);
 +        fs_file_close(handle);
 +    }
 +
 +    /* store the lines request back to the vector */
 +    if (line - beg + end > vec_size(datas)) {
 +        beg = 1;
 +        end = 1;
 +    }
 +
 +    for(feed = line - beg; feed < line - beg + end; ++feed)
 +        vec_push((*read), datas[feed]);
 +}
 +
 +static void diagnostic_feed(const char *file, size_t line, size_t column, size_t beg, size_t end, bool marker, size_t diagnostic) {
 +    diagnostic_data_t  **read  = NULL;
 +    size_t               feed  = 0;
 +    size_t               space = 6;
 +    size_t               len   = 0;
 +    size_t               itr   = 0;
 +    size_t               tok   = 0;
 +
 +    /* get line */
 +    diagnostic_line(file, line, &read, beg, end);
 +
 +    /* use old token stream to pretty the output */
 +    for (; feed < vec_size(read); feed++) {
 +        con_err("%4d: ", line);
 +        while ((tok = read[feed]->tokens[itr]) != TOKEN_EOL) {
 +            switch (tok) {
 +                case TOKEN_TYPENAME:
 +                case TOKEN_KEYWORD:
 +                    con_err(con_color_err() ? "\033[1;33m%s\033[0m" : "%s", read[feed]->values[itr]);
 +                    break;
 +
 +                case TOKEN_INTCONST:
 +                case TOKEN_FLOATCONST:
 +                    con_err(con_color_err() ? "\033[1;32m%s\033[0m" : "%s", read[feed]->values[itr]);
 +                    break;
 +
 +                case TOKEN_CHARCONST:
 +                case TOKEN_STRINGCONST:
 +                    con_err(con_color_err() ? "\033[1;31m%s\033[0m" : "%s", read[feed]->values[itr]);
 +                    break;
 +
 +                case TOKEN_EOF:
 +                case TOKEN_ERROR:
 +                case TOKEN_EOL:
 +                    /* ignore */
 +                    break;
 +
 +                default:
 +                    con_err("%s", read[feed]->values[itr]);
 +                    break;
 +            };
 +            itr++;
 +        }
 +        itr = 0;
 +        con_err("\n");
 +    }
 +
 +    switch (diagnostic) {
 +        case DIAGNOSTIC_EXPECTED_END:
 +            for (; len < vec_size(vec_last(read)->values); len++)
 +                space += strlen(vec_last(read)->values[len]);
 +
 +            /* +/- 1 because of the ^ */
 +            len   = space  - column - 1;
 +            space = column          + 1;
 +            break;
 +
 +        case DIAGNOSTIC_EXPRESSION_CASE:
 +        case DIAGNOSTIC_SEMICOLON:
 +            for (; len < vec_size(vec_last(read)->values); len++)
 +                space += strlen(vec_last(read)->values[len]);
 +
 +            len    = 1;
 +            space -= beg - end;
 +            break;
 +
 +        case DIAGNOSTIC_EXPECTED:
 +            /*
 +             * use the column number here, it's the EASIEST method yet
 +             * because it points to the exact space.
 +             */
 +            space += column;
 +            len    = 0;
 +            break;
 +
 +        case DIAGNOSTIC_UNEXPECTED_TOKEN:
 +            len = column;
 +            break;
 +
 +        case DIAGNOSTIC_UNEXPECTED_IDENT:
 +            /*
 +             * TODO: better way to determine the identifier. So far we
 +             * "assume" it's the first one in the token stream, the issue
 +             * with this, is it'ss possible that it isn't the first ident
 +             * in the stream. In all likely hood, the parser itself should
 +             * carry a "current token in line" count so we can simply use
 +             * it as a index into vec_last(read)->tokens. This will also
 +             * allow for other diagnostics involving unexpected tokens.
 +             */
 +            for (itr = 0; len < vec_size(vec_last(read)->tokens); len++) {
 +                if (vec_last(read)->tokens[len] == TOKEN_IDENT)
 +                    break;
 +                space += strlen(vec_last(read)->values[len]);
 +            }
 +            len = 0;
 +            break;
 +            
 +        default:
 +            break;
 +    }
 +
 +    while (space --) con_err(" ");
 +    while (len   --) con_err("~");
 +
 +    con_err((marker) ? "^\n" : "\n"); 
 +
 +    vec_free(read);
 +}
 +
 +
 +static void diagnostic_destory_data(void *data) {
 +    diagnostic_data_t **datas = (diagnostic_data_t **)data;
 +    size_t              i,j;
 +    
 +    for (i = 0; i < vec_size(datas); i++) {
 +        vec_free(datas[i]->line);
 +        
 +        /*
 +         * There is always the same number of tokens as
 +         * values, one loop suffices.
 +         */
 +        for (j = 0; i < vec_size(datas[i]->tokens); i++) {
 +            mem_d(datas[i]->tokens[j]);
 +            mem_d(datas[i]->values[j]);
 +        }
 +        
 +        vec_free(datas[i]->tokens);
 +        vec_free(datas[i]->values);
 +        
 +        mem_d(datas[i]);
 +    }
 +}
 +
 +void diagnostic_destroy() {
 +    if (!diagnostic_table)
 +        return;
 +
 +    util_htrem(diagnostic_table, diagnostic_destory_data);
 +}
 +
 +void diagnostic_calculate(const char *file, size_t line, size_t column, size_t diagnostic) {
 +    size_t linebeg = 1;
 +    size_t linecnt = 1;
 +    bool   marker  = false;
 +
 +
 +    switch (diagnostic) {
 +        /*
 +         * Semicolon reports error on nextline, which is why we need
 +         * to increment the beginning line for diagnostics, and also
 +         * enable the marker (to show where it's missing).
 +         */
 +        case DIAGNOSTIC_SEMICOLON:
 +        case DIAGNOSTIC_EXPRESSION_CASE:
 +        case DIAGNOSTIC_EXPECTED_END:
 +            linebeg++;
 +            marker = true;
 +            break;
 +
 +        case DIAGNOSTIC_UNEXPECTED_TOKEN:
 +            marker = false;
 +            break;
 +
 +        case DIAGNOSTIC_UNEXPECTED_IDENT:
 +        case DIAGNOSTIC_EXPECTED:
 +            marker = true;
 +            break;
 +
 +        /* Catches the DIAGNOSTIC_NULL and out of range case */
 +        default:
 +            return;
 +    }
 +
 +    diagnostic_feed(file, line, column, linebeg, linecnt, marker, diagnostic);
 +}
diff --cc gmqcc.h
index f7fc39b67d7200fbfc81d2462331a8d65da2b909,d6055dbeedf2d27ac8e8a9061744302027fcb515..9a073e2ea88f168f10e09454504a3c5b3458214d
+++ b/gmqcc.h
@@@ -785,9 -781,6 +781,9 @@@ int  con_vout  (const char *, va_list)
  int  con_err   (const char *, ...);
  int  con_out   (const char *, ...);
  
- bool con_color_err();
- bool con_color_out();
++bool con_color_err(void);
++bool con_color_out(void);
 +
  /* error/warning interface */
  extern size_t compile_errors;
  extern size_t compile_Werrors;
@@@ -1021,23 -1014,6 +1017,23 @@@ void            ftepp_flush            
  void            ftepp_add_define       (struct ftepp_s *ftepp, const char *source, const char *name);
  void            ftepp_add_macro        (struct ftepp_s *ftepp, const char *name,   const char *value);
  
- void diagnostic_destroy();
 +/*===================================================================*/
 +/*============================= exec.c ==============================*/
 +/*===================================================================*/
 +enum {
 +    DIAGNOSTIC_NULL,
 +    DIAGNOSTIC_SEMICOLON,
 +    DIAGNOSTIC_EXPRESSION_CASE,
 +    DIAGNOSTIC_UNEXPECTED_IDENT,
 +    DIAGNOSTIC_UNEXPECTED_TOKEN,
 +    DIAGNOSTIC_EXPECTED,
 +    DIAGNOSTIC_EXPECTED_END
 +};
 +
++void diagnostic_destroy(void);
 +void diagnostic_calculate(const char *file, size_t line, size_t column, size_t diagnostic);
 +
 +
  /*===================================================================*/
  /*======================= main.c commandline ========================*/
  /*===================================================================*/
diff --cc intrin.h
Simple merge
diff --cc lexer.c
Simple merge
diff --cc lexer.h
Simple merge
diff --cc main.c
Simple merge
diff --cc opts.def
Simple merge
diff --cc parser.c
index bb30043b34c84e3ebefc2c0e269529eea8ab4cf2,8a7cf876948e06119fa1730340f5b0be22e6742b..2a233a1dae218e8100024724d64a7bd33fbbc4d9
+++ b/parser.c
@@@ -6483,9 -6467,6 +6493,7 @@@ bool parser_finish(parser_t *parser, co
              return false;
          }
      }
 +    diagnostic_destroy();
      ir_builder_delete(ir);
      return retval;
  }
diff --cc test.c
Simple merge