Add support for evaluating builtin functions at compile time.
[smatch.git] / check.c
blob6a0999496ea4c2d1e13c39aef133922a04222b0f
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 char *include = NULL;
28 static int include_fd = -1;
30 static void add_pre_buffer(const char *fmt, ...)
32 va_list args;
33 unsigned int size;
35 va_start(args, fmt);
36 size = pre_buffer_size;
37 size += vsnprintf(pre_buffer + size,
38 sizeof(pre_buffer) - size,
39 fmt, args);
40 pre_buffer_size = size;
41 va_end(args);
44 static char ** handle_switch(char *arg, char **next)
46 switch (*arg) {
47 case 'D': {
48 const char *name = arg+1;
49 const char *value = "";
50 for (;;) {
51 char c;
52 c = *++arg;
53 if (!c)
54 break;
55 if (isspace(c) || c == '=') {
56 *arg = '\0';
57 value = arg+1;
58 break;
61 add_pre_buffer("#define %s %s\n", name, value);
62 return next;
65 case 'I':
66 add_pre_buffer("#add_include \"%s/\"\n", arg+1);
67 return next;
68 case 'i':
69 if (*next && !strcmp(arg, "include")) {
70 char *name = *++next;
71 int fd = open(name, O_RDONLY);
72 include_fd = fd;
73 include = name;
74 if (fd < 0)
75 perror(name);
76 return next;
78 /* Fallthrough */
79 default:
80 /* Ignore unknown command line options - they're probably gcc switches */
81 break;
83 return next;
86 static void clean_up_symbol(struct symbol *sym, void *_parent, int flags)
88 check_duplicates(sym);
89 evaluate_symbol(sym);
92 int main(int argc, char **argv)
94 int fd;
95 char *filename = NULL, **args;
96 struct token *token;
98 // Initialize symbol stream first, so that we can add defines etc
99 init_symbols();
101 add_pre_buffer("#define __linux__ 1\n");
102 add_pre_buffer("#define __CHECKER__ 1\n");
103 add_pre_buffer("#define cond_syscall(x)\n");
104 add_pre_buffer("#define __GNUC__ 2\n");
105 add_pre_buffer("#define __GNUC_MINOR__ 95\n");
106 add_pre_buffer("#define __builtin_constant_p(x) 0\n");
107 add_pre_buffer("#define __func__ \"function\"\n");
108 add_pre_buffer("#define __extension__\n");
109 add_pre_buffer("extern void *__builtin_memcpy(void *, const void *, unsigned long);\n");
110 add_pre_buffer("extern void * __builtin_return_address(int);\n");
111 add_pre_buffer("#define __builtin_stdarg_start(a,b) ((a) = (__builtin_va_list)(&(b)))\n");
112 add_pre_buffer("#define __builtin_va_arg(arg,type) ((type)0)\n");
113 add_pre_buffer("#define __builtin_va_end(arg)\n");
115 args = argv;
116 for (;;) {
117 char *arg = *++args;
118 if (!arg)
119 break;
120 if (arg[0] == '-') {
121 args = handle_switch(arg+1, args);
122 continue;
124 filename = arg;
128 fd = open(filename, O_RDONLY);
129 if (fd < 0)
130 die("No such file: %s", argv[1]);
132 // Tokenize the input stream
133 token = tokenize(filename, fd, NULL);
134 close(fd);
136 // Prepend any "include" file to the stream.
137 if (include_fd >= 0)
138 token = tokenize(include, include_fd, token);
140 // Prepend the initial built-in stream
141 token = tokenize_buffer(pre_buffer, pre_buffer_size, token);
143 // Pre-process the stream
144 token = preprocess(token);
146 // Parse the resulting C code
147 translation_unit(token, &used_list);
149 // Do type evaluation and simplify
150 symbol_iterate(used_list, clean_up_symbol, NULL);
151 return 0;