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