Now that inlining works, make the return handling work properly too,
[smatch.git] / check.c
blobaae7b78ca0d735c8bbdb18d86a979bb4a01d09bb
1 /*
2 * Example trivial client program that uses the sparse library
3 * to tokenize, pre-process and parse a C file, and prints out
4 * the results.
6 * Copyright (C) 2003 Transmeta Corp.
8 * Licensed under the Open Software License version 1.1
9 */
10 #include <stdarg.h>
11 #include <stdlib.h>
12 #include <stdio.h>
13 #include <string.h>
14 #include <ctype.h>
15 #include <unistd.h>
16 #include <fcntl.h>
18 #include "lib.h"
19 #include "token.h"
20 #include "parse.h"
21 #include "symbol.h"
22 #include "expression.h"
24 static unsigned int pre_buffer_size = 0;
25 static unsigned char pre_buffer[8192];
27 static int preprocess_only;
28 static char *include = NULL;
29 static int include_fd = -1;
31 static void add_pre_buffer(const char *fmt, ...)
33 va_list args;
34 unsigned int size;
36 va_start(args, fmt);
37 size = pre_buffer_size;
38 size += vsnprintf(pre_buffer + size,
39 sizeof(pre_buffer) - size,
40 fmt, args);
41 pre_buffer_size = size;
42 va_end(args);
45 static char ** handle_switch(char *arg, char **next)
47 switch (*arg) {
48 case 'D': {
49 const char *name = arg+1;
50 const char *value = "";
51 for (;;) {
52 char c;
53 c = *++arg;
54 if (!c)
55 break;
56 if (isspace(c) || c == '=') {
57 *arg = '\0';
58 value = arg+1;
59 break;
62 add_pre_buffer("#define %s %s\n", name, value);
63 return next;
66 case 'E':
67 preprocess_only = 1;
68 return next;
69 case 'v':
70 verbose = 1;
71 return next;
72 case 'I':
73 add_pre_buffer("#add_include \"%s/\"\n", arg+1);
74 return next;
75 case 'i':
76 if (*next && !strcmp(arg, "include")) {
77 char *name = *++next;
78 int fd = open(name, O_RDONLY);
79 include_fd = fd;
80 include = name;
81 if (fd < 0)
82 perror(name);
83 return next;
85 /* Fallthrough */
86 default:
87 /* Ignore unknown command line options - they're probably gcc switches */
88 break;
90 return next;
93 static void clean_up_symbol(struct symbol *sym, void *_parent, int flags)
95 check_duplicates(sym);
96 evaluate_symbol(sym);
99 int main(int argc, char **argv)
101 int fd;
102 char *filename = NULL, **args;
103 struct token *token;
105 // Initialize symbol stream first, so that we can add defines etc
106 init_symbols();
108 add_pre_buffer("#define __i386__ 1\n");
109 add_pre_buffer("#define __linux__ 1\n");
110 add_pre_buffer("#define __STDC__ 1\n");
111 add_pre_buffer("#define linux linux\n");
112 add_pre_buffer("#define __CHECKER__ 1\n");
113 add_pre_buffer("#define cond_syscall(x)\n");
114 add_pre_buffer("#define __GNUC__ 2\n");
115 add_pre_buffer("#define __GNUC_MINOR__ 95\n");
116 add_pre_buffer("#define __func__ \"function\"\n");
117 add_pre_buffer("#define __extension__\n");
118 add_pre_buffer("#define __pragma__\n");
119 add_pre_buffer("extern void *__builtin_memcpy(void *, const void *, unsigned long);\n");
120 add_pre_buffer("extern void * __builtin_return_address(int);\n");
121 add_pre_buffer("#define __builtin_stdarg_start(a,b) ((a) = (__builtin_va_list)(&(b)))\n");
122 add_pre_buffer("#define __builtin_va_arg(arg,type) ((type)0)\n");
123 add_pre_buffer("#define __builtin_va_end(arg)\n");
125 args = argv;
126 for (;;) {
127 char *arg = *++args;
128 if (!arg)
129 break;
130 if (arg[0] == '-') {
131 args = handle_switch(arg+1, args);
132 continue;
134 filename = arg;
138 fd = open(filename, O_RDONLY);
139 if (fd < 0)
140 die("No such file: %s", filename);
142 // Tokenize the input stream
143 token = tokenize(filename, fd, NULL);
144 close(fd);
146 // Prepend any "include" file to the stream.
147 if (include_fd >= 0)
148 token = tokenize(include, include_fd, token);
150 // Prepend the initial built-in stream
151 token = tokenize_buffer(pre_buffer, pre_buffer_size, token);
153 // Pre-process the stream
154 token = preprocess(token);
156 if (preprocess_only) {
157 while (!eof_token(token)) {
158 int prec = 1;
159 struct token *next = token->next;
160 char * separator = "";
161 if (next->pos.whitespace)
162 separator = " ";
163 if (next->pos.newline) {
164 separator = "\n\t\t\t\t\t";
165 prec = next->pos.pos;
166 if (prec > 4)
167 prec = 4;
169 printf("%s%.*s", show_token(token), prec, separator);
170 token = next;
172 putchar('\n');
174 return 0;
177 // Parse the resulting C code
178 translation_unit(token, &used_list);
180 // Do type evaluation and simplify
181 symbol_iterate(used_list, clean_up_symbol, NULL);
182 return 0;