1 #include "../adlib/lib.h"
2 #include "parser.h"
3
Error(const char * message)4 void Error(const char *message) {
5 printf("ppcc: %s\n", message);
6 exit(1);
7 }
8
9 #define LINK 1
10 #define COMP 2
11 #define CPP 4
12 #define DEP 8
13 #define ALL (LINK | COMP | CPP)
14
15 typedef enum {
16 NoArg,
17 IntegralArg,
18 FollowArg,
19 IntegralOrFollowArg
20 } OptArgType;
21
22 typedef void (*OptFunc)(Str *, const char *);
23
24 struct OptSpec {
25 const char *name;
26 int mode;
27 OptArgType argtype;
28 OptFunc handler;
29 };
30
31 int debug = 0;
32 int mode = LINK;
33 bool depend = false;
34 StrArr *CPPArgs, *CompArgs, *LinkArgs, *DepArgs, *ExtraArgs;
35 Str *Language = NULL;
36 Str *Compiler = NULL;
37 Str *Output = NULL;
38 StrArr *CInput = NULL;
39 StrArr *CCInput = NULL;
40 StrArr *ObjInput = NULL;
41 StrArr *AsmInput = NULL;
42
AddArg(int mode,Str * arg)43 void AddArg(int mode, Str *arg) {
44 if (mode & CPP) CPPArgs->add(arg);
45 if (mode & COMP) CompArgs->add(arg);
46 if (mode & LINK) LinkArgs->add(arg);
47 }
48
ModeCPP(Str * opt,const char * arg)49 void ModeCPP(Str *opt, const char *arg) {
50 mode = CPP;
51 }
52
ModeComp(Str * opt,const char * arg)53 void ModeComp(Str *opt, const char *arg) {
54 mode = COMP;
55 }
56
ModeDepend(Str * opt,const char * arg)57 void ModeDepend(Str *opt, const char *arg) {
58 depend = true;
59 }
60
SelectLang(Str * opt,const char * arg)61 void SelectLang(Str *opt, const char *arg) {
62 Language = new Str(arg);
63 AddArg(ALL, opt);
64 AddArg(ALL, Language);
65 }
66
SaveOutput(Str * opt,const char * arg)67 void SaveOutput(Str *opt, const char *arg) {
68 Output = new Str(arg);
69 AddArg(COMP|LINK, opt);
70 AddArg(COMP|LINK, Output);
71 }
72
73
74 OptSpec optspecs[] = {
75 { "-E", 0, NoArg, ModeCPP },
76 { "-c", 0, NoArg, ModeComp },
77 { "-S", 0, NoArg, ModeComp },
78 { "-x", ALL, FollowArg, SelectLang },
79 { "-f", ALL, IntegralArg },
80 { "-O", COMP, IntegralArg },
81 { "-g", COMP|LINK, IntegralArg },
82 { "-W", ALL, IntegralArg },
83 { "-X", ALL, IntegralArg },
84 { "-w", ALL, IntegralArg },
85 { "-D", CPP, IntegralArg },
86 { "-U", CPP, IntegralArg },
87 { "-MM", CPP, NoArg },
88 { "-MD", CPP, NoArg },
89 { "-MMD", CPP, NoArg },
90 { "-MG", CPP, NoArg },
91 { "-MP", CPP, NoArg },
92 { "-MF", CPP, FollowArg },
93 { "-MT", CPP, FollowArg },
94 { "-MQ", CPP, FollowArg },
95 { "-M", CPP, NoArg },
96 { "-o", COMP|LINK, FollowArg, SaveOutput },
97 { "-I", CPP, IntegralOrFollowArg },
98 { "-I-", CPP, IntegralOrFollowArg },
99 { "-I", CPP, IntegralOrFollowArg },
100 { "-include", CPP, FollowArg },
101 { "-idirafter", CPP, FollowArg },
102 { "-imacros", CPP, FollowArg },
103 { "-iquote", CPP, FollowArg },
104 { "-isystem", CPP, FollowArg },
105 { NULL }
106 };
107
ParseOpt(Str * opt,char * arg)108 int ParseOpt(Str *opt, char *arg) {
109 for (OptSpec *spec = optspecs; spec->name; spec++) {
110 Word len = strlen(spec->name);
111 if (len <= opt->len()) {
112 if (strncmp(spec->name, opt->c_str(), len) == 0) {
113 OptFunc handler = spec->handler;
114 switch (spec->argtype) {
115 case NoArg:
116 case IntegralArg:
117 if (handler) {
118 handler(opt, NULL);
119 } else {
120 AddArg(spec->mode, opt);
121 }
122 return 0;
123 case FollowArg:
124 if (!arg)
125 Error("missing argument");
126 if (handler) {
127 handler(opt, arg);
128 } else {
129 AddArg(spec->mode, opt);
130 AddArg(spec->mode, new Str(arg));
131 }
132 return 1;
133 case IntegralOrFollowArg:
134 if (len == opt->len()) {
135 if (!arg)
136 Error("missing argument");
137 if (handler) {
138 handler(opt, arg);
139 } else {
140 AddArg(spec->mode, opt);
141 AddArg(spec->mode, new Str(arg));
142 }
143 return 1;
144 } else {
145 if (handler) {
146 handler(opt, arg);
147 } else {
148 AddArg(spec->mode, opt);
149 }
150 return 0;
151 }
152 }
153 }
154 }
155 }
156 AddArg(ALL, opt);
157 return 0;
158 }
159
TestOutputExecutable()160 void TestOutputExecutable() {
161 if (mode == LINK) {
162 if (Output && FileExtension(Output)->len() != 0) {
163 return;
164 }
165 Str *path = DirName(ProgramPath());
166 if (path) {
167 path->add("/../Singular/threadsupport.cc");
168 path = NormalizePath(path);
169 }
170 if (path && FileStat(path)) {
171 ExtraArgs->add(path);
172 } else {
173 PrintLn(path);
174 Error("cannot locate ppcc directory");
175 }
176 }
177 }
178
ParseArgs()179 void ParseArgs() {
180 if (ArgC <= 1) {
181 Error("no arguments");
182 }
183 Compiler = new Str(ArgV[1]);
184 for (int i = 2; i < ArgC; i++) {
185 char *p = ArgV[i];
186 if (p[0] == '-') {
187 i += ParseOpt(new Str(p), ArgV[i+1]);
188 } else {
189 Str *arg = new Str(p);
190 if (arg->ends_with(".c")) {
191 CInput->add(arg);
192 } else if (arg->ends_with(".cc") || arg->ends_with(".cpp")) {
193 CCInput->add(arg);
194 } else if (arg->ends_with(".o")) {
195 ObjInput->add(arg);
196 } else if (arg->ends_with(".s")) {
197 AsmInput->add(arg);
198 } else {
199 AddArg(ALL, arg);
200 }
201 }
202 }
203 }
204
RunCPP()205 Str *RunCPP() {
206 Str *input;
207 if (CInput->len())
208 input = CInput->at(0);
209 else
210 input = CCInput->at(0);
211 StrArr *args = A("-E", "-DPSINGULAR");
212 args->add(CPPArgs)->add(input);
213 if (debug) {
214 printf("Preprocessor: %s %s\n",
215 Compiler->c_str(),
216 StrJoin(args, " ")->c_str());
217 }
218 Str *result = ReadProcess(Compiler, args);
219 if (!result)
220 Error("preprocessor failed");
221 if (debug >= 3)
222 Print(result);
223 result = RunPreProcessor(input, result);
224 return result;
225 }
226
PassThroughCompiler()227 void PassThroughCompiler() {
228 if (debug)
229 PrintLn(S("Pass through: ")->
230 add(StrJoin(Args->clone()->add(ExtraArgs), S(" "))));
231 if (ArgC <= 1) {
232 Error("no arguments");
233 }
234 Compiler = new Str(ArgV[1]);
235 StrArr *args = new StrArr(ArgC);
236 for (int i = 2; i < ArgC; i++) {
237 args->add(S(ArgV[i]));
238 }
239 args->add(ExtraArgs);
240 int exitcode = System(Compiler, args);
241 exit(exitcode);
242 }
243
ExecCompiler()244 void ExecCompiler() {
245 int exitcode;
246 Int inputs;
247 StrArr *args = new StrArr(1);
248 switch (inputs = CInput->len() + CCInput->len()) {
249 case 0:
250 if (mode == COMP)
251 Error("no input files");;
252 break;
253 case 1:
254 break;
255 default:
256 Error("too many C/C++ input files");
257 break;
258 }
259 switch (mode) {
260 case CPP:
261 PassThroughCompiler();
262 break;
263 case COMP:
264 args->add(S("-c"))->add(CompArgs);
265 break;
266 case LINK:
267 args->add(LinkArgs);
268 break;
269 }
270 if (inputs) {
271 Str *cppOutput = RunCPP();
272 const char *lang = CInput->len() == 1 ? "c" : "c++";
273 args->add(S("-x"))->add(S(lang))->add(S("-"));
274 if (debug) {
275 printf("%s: %s %s\n",
276 mode == COMP ? "Compiler" : "Linker",
277 Compiler->c_str(),
278 StrJoin(args, " ")->c_str());
279 if (debug >= 2)
280 Print(cppOutput);
281 fflush(stdout);
282 }
283 int success = WriteProcess(Compiler, args, cppOutput);
284 if (!success)
285 exit(1);
286 } else {
287 TestOutputExecutable();
288 PassThroughCompiler();
289 }
290 }
291
292 INIT(Args, {
293 GCVar(Language);
294 GCVar(Output);
295 GCVar(Compiler);
296
297 GCVar(CPPArgs, new StrArr());
298 GCVar(CompArgs, new StrArr());
299 GCVar(LinkArgs, new StrArr());
300 GCVar(DepArgs, new StrArr());
301 GCVar(ExtraArgs, new StrArr());
302
303 GCVar(CInput, new StrArr());
304 GCVar(CCInput, new StrArr());
305 GCVar(ObjInput, new StrArr());
306 GCVar(AsmInput, new StrArr());
307 });
308
Main()309 void Main() {
310 char *envDebug = getenv("DEBUG_PPCC");
311 if (envDebug) {
312 switch (envDebug[0]) {
313 case '0': debug = 0; break;
314 case '1': debug = 1; break;
315 case '2': debug = 2; break;
316 default:
317 Error("invalid DEBUG_PPCC value, must be 0, 1, or 2");
318 break;
319 }
320 }
321 if (Args->len() >= 1 && Args->at(0)->eq(S("--test"))) {
322 for (Int i = 1; i < Args->len(); i++) {
323 Str *filename = Args->at(i);
324 PrintLn(S("=== ")->add(filename));
325 Print(TestPreProcessor(filename));
326 }
327 return;
328 }
329 if (getenv("RUN_PPCC")) {
330 if (debug) {
331 PrintLn(S("Args: ")->add(StrJoin(Args, " ")));
332 }
333 ParseArgs();
334 ExecCompiler();
335 } else {
336 PassThroughCompiler();
337 }
338 }
339