tagged release 0.7.1
[parrot.git] / compilers / pirc / new / main.c
blob2d5e4d71b4df58f42c7bc6af026d7ecc051a922c
1 /*
2 * $Id$
3 * Copyright (C) 2007-2008, The Perl Foundation.
4 */
7 #include <string.h>
8 #include <assert.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <stdarg.h>
12 #include "pirparser.h"
13 #include "pircompiler.h"
16 /* use pthreads library to test thread safety.
17 does not work currently on windows.
18 The check for _MSC_VER is not correct but works for me.
20 #ifndef _MSC_VER
21 # define TEST_THREAD_SAFETY
22 #endif
25 #ifdef TEST_THREAD_SAFETY
26 # include <pthread.h>
27 # define NUM_THREADS 1
28 #endif
31 /* before including the lexer's header file, make sure to define this: */
32 #ifndef YY_NO_UNISTD_H
33 # define YY_NO_UNISTD_H
34 #endif
36 #include "pirlexer.h"
37 /* include this after "pirlexer.h", as C<yyscan_t> structure must be defined first
38 * which is done in "pirlexer.h"
40 #include "piryy.h"
45 =head1 FUNCTIONS
47 =over 4
50 =item C<static void
51 print_help(char const * const program_name)>
53 Routine to print usage of this program.
55 =cut
58 static void
59 print_help(char const * const program_name)
61 fprintf(stderr, "Usage: %s [options] <file>\n", program_name);
62 fprintf(stderr, "Options:\n\n");
63 /*fprintf(stderr, " -E pre-process\n"); */
64 fprintf(stderr, " -d show debug messages of parser\n");
65 fprintf(stderr, " -h show this help message\n");
66 fprintf(stderr, " -o <file> write output to the specified file. "
67 "Currently only works in combination with '-E' option\n");
73 =item C<static FILE *
74 open_file(char const * const filename, char const * const mode)>
76 Function to open the file given by C<filename>, in the mode given by C<mode>
77 Microsoft visual studio provides a "safer" variant of fopen(); this
78 function hides the selection of the appropriate variant.
80 =cut
83 static FILE *
84 open_file(char const * const filename, char const * const mode) {
85 FILE *fp = NULL;
87 #ifdef _MSC_VER
88 fopen_s(&fp, filename, mode);
89 #else
90 fp = fopen(filename, mode);
91 #endif
92 return fp;
96 static void
97 print_data_sizes(void) {
98 printf("size of symbol: %u\n", sizeof(symbol));
99 printf("size of target: %u\n", sizeof(target));
100 printf("size of sub: %u\n", sizeof(subroutine));
101 printf("size of stat: %u\n", sizeof(statement));
105 typedef struct parser_args {
106 int flexdebug;
107 FILE *infile;
108 char *filename;
109 int thr_id;
111 } parser_args;
116 This will be the proper declaration after testing for thread-safety:
118 void parse_file(int flexdebug, FILE *infile, char * const filename)
121 void *
122 parse_file(void *a) {
123 yyscan_t yyscanner;
124 lexer_state *lexer = NULL;
126 /* unpack the arguments from the structure parser_args */
127 parser_args *args = (parser_args *)a;
128 int flexdebug = args->flexdebug;
129 FILE *infile = args->infile;
130 char *filename = args->filename;
131 int thr_id = args->thr_id;
133 /* create a yyscan_t object */
134 yylex_init(&yyscanner);
135 /* set debug flag */
136 yyset_debug(flexdebug, yyscanner);
137 /* set the input file */
138 yyset_in(infile, yyscanner);
139 /* set the extra parameter in the yyscan_t structure */
140 lexer = new_lexer(filename);
141 yyset_extra(lexer, yyscanner);
142 /* go parse */
143 yyparse(yyscanner, lexer);
145 if (lexer->parse_errors == 0) {
146 char outfile[20];
147 sprintf(outfile, "output_thr_%d", thr_id);
148 lexer->outfile = open_file(outfile, "w");
149 if (lexer->outfile == NULL)
150 fprintf(stderr, "Failed to open file %s\n", outfile);
152 fprintf(stderr, "Parse successful!\n");
153 print_subs(lexer);
154 fclose(lexer->outfile);
156 check_unused_symbols(lexer);
157 free_subs(lexer);
159 else
160 fprintf(stderr, "There were %d errors\n", lexer->parse_errors);
162 fclose(infile);
166 /* clean up after playing */
167 release_resources(lexer);
168 yylex_destroy(yyscanner);
170 return NULL;
178 =item C<int main(int argc, char *argv[])>
180 Main compiler driver.
182 =cut
186 main(int argc, char *argv[]) {
187 char const * const program_name = argv[0];
188 int flexdebug = 0;
189 char *filename = NULL;
190 char *outputfile = NULL;
192 /* skip program name */
193 argc--;
194 argv++;
197 /* very basic argument handling; I'm too lazy to check out
198 * the standard funtion for that, right now. This is a TODO. */
199 while (argc > 0 && argv[0][0] == '-') {
200 switch (argv[0][1]) {
201 /* Only allow for debug flag if the generated parser supports it */
202 #ifdef YYDEBUG
203 case 'd':
204 yydebug = 1;
205 break;
206 #endif
207 case 'f':
208 flexdebug = 1;
209 break;
210 case 'h':
211 print_help(program_name);
212 exit(EXIT_SUCCESS); /* asking for help doesn't make you a failure */
213 /* break; */
214 case 'o':
215 if (argc > 1) { /* there must be at least 2 more args,
216 the output file, and an input */
217 argc--;
218 argv++;
219 outputfile = argv[0];
221 else {
222 fprintf(stderr, "Missing argument for option '-o'\n");
223 exit(EXIT_FAILURE);
225 break;
226 default:
227 fprintf(stderr, "Unknown option: '%c'\n", argv[0][1]);
228 exit(EXIT_FAILURE);
230 /* goto next command line argument */
231 argv++;
232 argc--;
235 /* The following code is to test thread safety. If TEST_THREAD_SAFETY
236 * is false, no threads are started; only the main thread will do
237 * a parse.
238 * For thread safety testing, the pthreads library is used.
240 #ifdef TEST_THREAD_SAFETY
242 pthread_t threads[NUM_THREADS];
243 int i;
244 for (i = 0; i < NUM_THREADS; i++) {
245 FILE *infile = NULL;
246 parser_args args;
249 if (argc < 1) { /* no file specified, read from stdin */
250 infile = stdin;
251 filename = NULL;
253 else {
254 /* done handling arguments, open the file */
255 infile = open_file(argv[0], "r");
256 filename = argv[0];
258 if (infile == NULL) {
259 fprintf(stderr, "Failed to open file '%s'\n", argv[0]);
260 exit(EXIT_FAILURE);
263 args.flexdebug = flexdebug;
264 args.infile = infile;
265 args.filename = filename;
266 args.thr_id = i;
268 pthread_create(&threads[i], NULL, parse_file, &args);
272 /* wait for all threads to finish */
273 for (i = 0; i < NUM_THREADS; i++)
274 pthread_join(threads[i], NULL);
276 #else
278 parser_args args;
279 FILE *infile = NULL;
281 if (argc < 1) { /* no file specified, read from stdin */
282 infile = stdin;
283 filename = NULL;
285 else {
286 /* done handling arguments, open the file */
287 infile = open_file(argv[0], "r");
288 filename = argv[0];
290 if (infile == NULL) {
291 fprintf(stderr, "Failed to open file '%s'\n", argv[0]);
292 exit(EXIT_FAILURE);
295 /* pack all args for parse_file() */
296 args.flexdebug = flexdebug;
297 args.infile = infile;
298 args.filename = filename;
299 args.thr_id = 0;
301 parse_file(&args);
303 #endif
305 return 0;
312 =item C<int
313 yyerror(yyscan_t yyscanner, lexer_state * const lexer, char const * const message, ...)>
315 Default parse error handling routine, that is invoked when the bison-generated
316 parser finds a syntax error.
318 =cut
322 yyerror(yyscan_t yyscanner, lexer_state * const lexer, char const * const message, ...) {
323 char const * const current_token = yyget_text(yyscanner);
324 va_list arg_ptr;
326 fprintf(stderr, "\nError in file '%s' (line %d)\n\n", lexer->filename, yyget_lineno(yyscanner));
328 va_start(arg_ptr, message);
329 vfprintf(stderr, message, arg_ptr);
330 va_end(arg_ptr);
332 ++lexer->parse_errors;
334 /* print current token if it doesn't contain a newline token. */
335 if (!strstr(current_token, "\n"))
336 fprintf(stderr, "\ncurrent token: '%s'", current_token);
338 fprintf(stderr, "\n\n");
340 return 0;
346 =back
348 =cut
353 * Local variables:
354 * c-file-style: "parrot"
355 * End:
356 * vim: expandtab shiftwidth=4: