3 * Copyright (C) 2007-2008, The Perl Foundation.
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.
21 # define TEST_THREAD_SAFETY
25 #ifdef TEST_THREAD_SAFETY
27 # define NUM_THREADS 1
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
37 /* include this after "pirlexer.h", as C<yyscan_t> structure must be defined first
38 * which is done in "pirlexer.h"
51 print_help(char const * const program_name)>
53 Routine to print usage of this program.
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");
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.
84 open_file(char const * const filename
, char const * const mode
) {
88 fopen_s(&fp
, filename
, mode
);
90 fp
= fopen(filename
, mode
);
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
{
116 This will be the proper declaration after testing for thread-safety:
118 void parse_file(int flexdebug, FILE *infile, char * const filename)
122 parse_file(void *a
) {
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
);
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
);
143 yyparse(yyscanner
, lexer
);
145 if (lexer
->parse_errors
== 0) {
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");
154 fclose(lexer
->outfile
);
156 check_unused_symbols(lexer
);
160 fprintf(stderr
, "There were %d errors\n", lexer
->parse_errors
);
166 /* clean up after playing */
167 release_resources(lexer
);
168 yylex_destroy(yyscanner
);
178 =item C<int main(int argc, char *argv[])>
180 Main compiler driver.
186 main(int argc
, char *argv
[]) {
187 char const * const program_name
= argv
[0];
189 char *filename
= NULL
;
190 char *outputfile
= NULL
;
192 /* skip program name */
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 */
211 print_help(program_name
);
212 exit(EXIT_SUCCESS
); /* asking for help doesn't make you a failure */
215 if (argc
> 1) { /* there must be at least 2 more args,
216 the output file, and an input */
219 outputfile
= argv
[0];
222 fprintf(stderr
, "Missing argument for option '-o'\n");
227 fprintf(stderr
, "Unknown option: '%c'\n", argv
[0][1]);
230 /* goto next command line argument */
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
238 * For thread safety testing, the pthreads library is used.
240 #ifdef TEST_THREAD_SAFETY
242 pthread_t threads
[NUM_THREADS
];
244 for (i
= 0; i
< NUM_THREADS
; i
++) {
249 if (argc
< 1) { /* no file specified, read from stdin */
254 /* done handling arguments, open the file */
255 infile
= open_file(argv
[0], "r");
258 if (infile
== NULL
) {
259 fprintf(stderr
, "Failed to open file '%s'\n", argv
[0]);
263 args
.flexdebug
= flexdebug
;
264 args
.infile
= infile
;
265 args
.filename
= filename
;
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
);
281 if (argc
< 1) { /* no file specified, read from stdin */
286 /* done handling arguments, open the file */
287 infile
= open_file(argv
[0], "r");
290 if (infile
== NULL
) {
291 fprintf(stderr
, "Failed to open file '%s'\n", argv
[0]);
295 /* pack all args for parse_file() */
296 args
.flexdebug
= flexdebug
;
297 args
.infile
= infile
;
298 args
.filename
= filename
;
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.
322 yyerror(yyscan_t yyscanner
, lexer_state
* const lexer
, char const * const message
, ...) {
323 char const * const current_token
= yyget_text(yyscanner
);
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
);
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");
354 * c-file-style: "parrot"
356 * vim: expandtab shiftwidth=4: