123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493 |
- /*
- * 'sparse' library helper routines.
- *
- * Copyright (C) 2003 Transmeta Corp.
- * 2003-2004 Linus Torvalds
- *
- * 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 <ctype.h>
- #include <errno.h>
- #include <fcntl.h>
- #include <stdarg.h>
- #include <stddef.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <unistd.h>
- #include <assert.h>
- #include <sys/types.h>
- #include "lib.h"
- #include "allocate.h"
- #include "token.h"
- #include "parse.h"
- #include "symbol.h"
- #include "expression.h"
- #include "evaluate.h"
- #include "scope.h"
- #include "linearize.h"
- #include "target.h"
- #include "machine.h"
- #include "version.h"
- #include "bits.h"
- static int prettify(const char **fnamep)
- {
- const char *name = *fnamep;
- int len = strlen(name);
- if (len > 2 && !memcmp(name, "./", 2)) {
- name += 2;
- len -= 2;
- }
- *fnamep = name;
- return len;
- }
- static const char *show_include_chain(int stream, const char *base)
- {
- static char buffer[200];
- int len = 0;
- while ((stream = stream_prev(stream)) >= 0) {
- const char *p = stream_name(stream);
- int pretty_len;
- if (p == base)
- break;
- pretty_len = prettify(&p);
- if (pretty_len <= 0)
- break;
- /*
- * At worst, we'll need " (through %s, ...)" in addition to the
- * new filename
- */
- if (pretty_len + len + 20 > sizeof(buffer)) {
- if (!len)
- return "";
- memcpy(buffer+len, ", ...", 5);
- len += 5;
- break;
- }
- if (!len) {
- memcpy(buffer, " (through ", 10);
- len = 10;
- } else {
- buffer[len++] = ',';
- buffer[len++] = ' ';
- }
- memcpy(buffer+len, p, pretty_len);
- len += pretty_len;
- }
- if (!len)
- return "";
- buffer[len] = ')';
- buffer[len+1] = 0;
- return buffer;
- }
- static const char *show_stream_name(struct position pos)
- {
- const char *name = stream_name(pos.stream);
- static const char *last;
- if (name == base_filename)
- return name;
- if (name == last)
- return name;
- last = name;
- fprintf(stderr, "%s: note: in included file%s:\n",
- base_filename,
- show_include_chain(pos.stream, base_filename));
- return name;
- }
- static void do_warn(const char *type, struct position pos, const char * fmt, va_list args)
- {
- static char buffer[512];
- /* Shut up warnings if position is bad_token.pos */
- if (pos.type == TOKEN_BAD)
- return;
- vsprintf(buffer, fmt, args);
- fflush(stdout);
- fprintf(stderr, "%s:%d:%d: %s%s%s\n",
- show_stream_name(pos), pos.line, pos.pos,
- diag_prefix, type, buffer);
- }
- static int show_info = 1;
- void info(struct position pos, const char * fmt, ...)
- {
- va_list args;
- if (!show_info)
- return;
- va_start(args, fmt);
- do_warn("", pos, fmt, args);
- va_end(args);
- }
- static void do_error(struct position pos, const char * fmt, va_list args)
- {
- static int errors = 0;
- die_if_error = 1;
- show_info = 1;
- /* Shut up warnings if position is bad_token.pos */
- if (pos.type == TOKEN_BAD)
- return;
- /* Shut up warnings after an error */
- has_error |= ERROR_CURR_PHASE;
- if (errors > fmax_errors) {
- static int once = 0;
- show_info = 0;
- if (once)
- return;
- fmt = "too many errors";
- once = 1;
- }
- do_warn("error: ", pos, fmt, args);
- errors++;
- }
- void warning(struct position pos, const char * fmt, ...)
- {
- va_list args;
- if (Wsparse_error) {
- va_start(args, fmt);
- do_error(pos, fmt, args);
- va_end(args);
- return;
- }
- if (!fmax_warnings || has_error) {
- show_info = 0;
- return;
- }
- if (!--fmax_warnings) {
- show_info = 0;
- fmt = "too many warnings";
- }
- va_start(args, fmt);
- do_warn("warning: ", pos, fmt, args);
- va_end(args);
- }
- void sparse_error(struct position pos, const char * fmt, ...)
- {
- va_list args;
- va_start(args, fmt);
- do_error(pos, fmt, args);
- va_end(args);
- }
- void expression_error(struct expression *expr, const char *fmt, ...)
- {
- va_list args;
- va_start(args, fmt);
- do_error(expr->pos, fmt, args);
- va_end(args);
- expr->ctype = &bad_ctype;
- }
- NORETURN_ATTR
- void error_die(struct position pos, const char * fmt, ...)
- {
- va_list args;
- va_start(args, fmt);
- do_warn("error: ", pos, fmt, args);
- va_end(args);
- exit(1);
- }
- NORETURN_ATTR
- void die(const char *fmt, ...)
- {
- va_list args;
- static char buffer[512];
- va_start(args, fmt);
- vsnprintf(buffer, sizeof(buffer), fmt, args);
- va_end(args);
- fprintf(stderr, "%s%s\n", diag_prefix, buffer);
- exit(1);
- }
- ////////////////////////////////////////////////////////////////////////////////
- static struct token *pre_buffer_begin = NULL;
- static struct token **pre_buffer_next = &pre_buffer_begin;
- void add_pre_buffer(const char *fmt, ...)
- {
- va_list args;
- unsigned int size;
- struct token *begin, *end;
- char buffer[4096];
- va_start(args, fmt);
- size = vsnprintf(buffer, sizeof(buffer), fmt, args);
- va_end(args);
- begin = tokenize_buffer(buffer, size, &end);
- *pre_buffer_next = begin;
- pre_buffer_next = &end->next;
- }
- static void create_builtin_stream(void)
- {
- // Temporary hack
- add_pre_buffer("#define _Pragma(x)\n");
- /* add the multiarch include directories, if any */
- if (multiarch_dir && *multiarch_dir) {
- add_pre_buffer("#add_system \"/usr/include/%s\"\n", multiarch_dir);
- add_pre_buffer("#add_system \"/usr/local/include/%s\"\n", multiarch_dir);
- }
- /* We add compiler headers path here because we have to parse
- * the arguments to get it, falling back to default. */
- add_pre_buffer("#add_system \"%s/include\"\n", gcc_base_dir);
- add_pre_buffer("#add_system \"%s/include-fixed\"\n", gcc_base_dir);
- add_pre_buffer("#define __builtin_stdarg_start(a,b) ((a) = (__builtin_va_list)(&(b)))\n");
- add_pre_buffer("#define __builtin_va_start(a,b) ((a) = (__builtin_va_list)(&(b)))\n");
- add_pre_buffer("#define __builtin_ms_va_start(a,b) ((a) = (__builtin_ms_va_list)(&(b)))\n");
- add_pre_buffer("#define __builtin_va_arg(arg,type) ({ type __va_arg_ret = *(type *)(arg); arg += sizeof(type); __va_arg_ret; })\n");
- add_pre_buffer("#define __builtin_va_alist (*(void *)0)\n");
- add_pre_buffer("#define __builtin_va_arg_incr(x) ((x) + 1)\n");
- add_pre_buffer("#define __builtin_va_copy(dest, src) ({ dest = src; (void)0; })\n");
- add_pre_buffer("#define __builtin_ms_va_copy(dest, src) ({ dest = src; (void)0; })\n");
- add_pre_buffer("#define __builtin_va_end(arg)\n");
- add_pre_buffer("#define __builtin_ms_va_end(arg)\n");
- add_pre_buffer("#define __builtin_va_arg_pack()\n");
- }
- static struct symbol_list *sparse_tokenstream(struct token *token)
- {
- int builtin = token && !token->pos.stream;
- // Preprocess the stream
- token = preprocess(token);
- if (dump_macro_defs || dump_macros_only) {
- if (!builtin)
- dump_macro_definitions();
- if (dump_macros_only)
- return NULL;
- }
- if (preprocess_only) {
- while (!eof_token(token)) {
- int prec = 1;
- struct token *next = token->next;
- const char *separator = "";
- if (next->pos.whitespace)
- separator = " ";
- if (next->pos.newline) {
- separator = "\n\t\t\t\t\t";
- prec = next->pos.pos;
- if (prec > 4)
- prec = 4;
- }
- printf("%s%.*s", show_token(token), prec, separator);
- token = next;
- }
- putchar('\n');
- return NULL;
- }
- // Parse the resulting C code
- while (!eof_token(token))
- token = external_declaration(token, &translation_unit_used_list, NULL);
- return translation_unit_used_list;
- }
- static struct symbol_list *sparse_file(const char *filename)
- {
- int fd;
- struct token *token;
- if (strcmp(filename, "-") == 0) {
- fd = 0;
- } else {
- fd = open(filename, O_RDONLY);
- if (fd < 0)
- die("No such file: %s", filename);
- }
- base_filename = filename;
- // Tokenize the input stream
- token = tokenize(NULL, filename, fd, NULL, includepath);
- close(fd);
- return sparse_tokenstream(token);
- }
- /*
- * This handles the "-include" directive etc: we're in global
- * scope, and all types/macros etc will affect all the following
- * files.
- *
- * NOTE NOTE NOTE! "#undef" of anything in this stage will
- * affect all subsequent files too, i.e. we can have non-local
- * behaviour between files!
- */
- static struct symbol_list *sparse_initial(void)
- {
- int i;
- // Prepend any "include" file to the stream.
- // We're in global scope, it will affect all files!
- for (i = 0; i < cmdline_include_nr; i++)
- add_pre_buffer("#argv_include \"%s\"\n", cmdline_include[i]);
- return sparse_tokenstream(pre_buffer_begin);
- }
- struct symbol_list *sparse_initialize(int argc, char **argv, struct string_list **filelist)
- {
- char **args;
- struct symbol_list *list;
- base_filename = "command-line";
- // Initialize symbol stream first, so that we can add defines etc
- init_symbols();
- // initialize the default target to the native 'machine'
- target_config(MACH_NATIVE);
- args = argv;
- for (;;) {
- char *arg = *++args;
- if (!arg)
- break;
- if (arg[0] == '-' && arg[1]) {
- args = handle_switch(arg+1, args);
- continue;
- }
- add_ptr_list(filelist, arg);
- }
- handle_switch_finalize();
- // Redirect stdout if needed
- if (dump_macro_defs || preprocess_only)
- do_output = 1;
- if (do_output && outfile && strcmp(outfile, "-")) {
- if (!freopen(outfile, "w", stdout))
- die("error: cannot open %s: %s", outfile, strerror(errno));
- }
- if (fdump_ir == 0)
- fdump_ir = PASS_FINAL;
- list = NULL;
- if (filelist) {
- // Initialize type system
- target_init();
- init_ctype();
- predefined_macros();
- create_builtin_stream();
- init_builtins(0);
- list = sparse_initial();
- /*
- * Protect the initial token allocations, since
- * they need to survive all the others
- */
- protect_token_alloc();
- }
- /*
- * Evaluate the complete symbol list
- * Note: This is not needed for normal cases.
- * These symbols should only be predefined defines and
- * declaratons which will be evaluated later, when needed.
- * This is also the case when a file is directly included via
- * '-include <file>' on the command line *AND* the file only
- * contains defines, declarations and inline definitions.
- * However, in the rare cases where the given file should
- * contain some definitions, these will never be evaluated
- * and thus won't be able to be linearized correctly.
- * Hence the evaluate_symbol_list() here under.
- */
- evaluate_symbol_list(list);
- return list;
- }
- struct symbol_list * sparse_keep_tokens(char *filename)
- {
- struct symbol_list *res;
- /* Clear previous symbol list */
- translation_unit_used_list = NULL;
- new_file_scope();
- res = sparse_file(filename);
- /* And return it */
- return res;
- }
- struct symbol_list * __sparse(char *filename)
- {
- struct symbol_list *res;
- res = sparse_keep_tokens(filename);
- /* Drop the tokens for this file after parsing */
- clear_token_alloc();
- /* And return it */
- return res;
- }
- struct symbol_list * sparse(char *filename)
- {
- struct symbol_list *res = __sparse(filename);
- if (has_error & ERROR_CURR_PHASE)
- has_error = ERROR_PREV_PHASE;
- /* Evaluate the complete symbol list */
- evaluate_symbol_list(res);
- return res;
- }
|