2 * This file is part of flex.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * Neither the name of the University nor the names of its contributors
15 * may be used to endorse or promote products derived from this software
16 * without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
25 /* A scanner file to build "scanner.c".
26 Input language is any text made of spaces, newlines, and alphanumerics.
28 We create N_THREADS number of threads. Each thread has it's own scanner.
29 Each thread selects one of the files specified in ARGV, scans it, then
30 closes it. This is repeated N_SCANS numebr of times for each thread.
32 The idea is to press the scanner to break under threads.
33 If we see "Scanner Jammed", then we know
44 /* A naive test for segfaults when accessing yytext. */
45 static int process_text(char* s, yyscan_t scanner);
49 %option 8bit outfile="scanner.c" prefix="test"
50 %option nounput nomain nodefault
55 /* Arbitrary states.*/
64 <INITIAL>[[:digit:]]+ { BEGIN(STATE_1); process_text(yytext,yyscanner); return NUMBER; }
65 <INITIAL>[[:alpha:]]+ { BEGIN(STATE_2); process_text(yytext,yyscanner); return WORD; }
67 <STATE_1>[[:alpha:]]+ { BEGIN(0); process_text(yytext,yyscanner); return WORD; }
68 <STATE_1>[[:digit:]]+ { BEGIN(0); process_text(yytext,yyscanner); return NUMBER; }
70 <STATE_2>[[:alpha:]]+ { BEGIN(0); process_text(yytext,yyscanner); return WORD; }
71 <STATE_2>[[:digit:]]+ { BEGIN(0); process_text(yytext,yyscanner); return NUMBER; }
73 <INITIAL,STATE_1,STATE_2>" "|\t|\r|\n { process_text(yytext,yyscanner); }
74 <INITIAL,STATE_1,STATE_2>[^[:alnum:][:space:]\t\r\n] {
75 /*fprintf(stderr,"*** Error: bad input char '%c'.\n", yytext[0]); */
78 <INITIAL,STATE_1,STATE_2>[[:space:]\r\n]+ { }
81 int yywrap( yyscan_t scanner) { return 1; }
82 static int process_text(char* s, yyscan_t scanner)
84 return (int)(*s) + (int) *(s + yyget_leng(scanner)-1);
87 int main(int ARGC, char *ARGV[]);
89 #ifndef HAVE_LIBPTHREAD
90 int main (int ARGC, char *ARGV[]) {
92 "TEST ABORTED because pthread library not available \n"
93 "-- This is expected on some systems. It is not a flex error.\n" );
100 #define INPUT_FILE "test.input"
102 /* Each thread selects the next file to scan in round-robin fashion.
103 If there are less files than threads, some threads may block. */
105 static pthread_mutex_t next_lock = PTHREAD_MUTEX_INITIALIZER;
106 static pthread_mutex_t go_ahead = PTHREAD_MUTEX_INITIALIZER;
107 static int n_files, next_file;
109 static pthread_mutex_t *file_locks;
110 static char **filenames;
113 void * thread_func ( void* arg )
117 /* Wait for go-ahead. */
118 pthread_mutex_lock( &go_ahead);
119 pthread_mutex_unlock(&go_ahead);
121 for( i =0 ; i < N_SCANS ; i++ )
123 int main(int ARGC, char *ARGV[]);
129 pthread_mutex_lock ( &next_lock );
130 next = (next_file++) % n_files;
131 pthread_mutex_unlock ( &next_lock );
133 pthread_mutex_lock ( &file_locks[ next ] );
135 yylex_init( &scanner );
136 /*printf("Scanning file %s #%d\n",filenames[next],i); fflush(stdout); */
137 if((fp = fopen(filenames[next],"r"))==NULL) {
141 yyset_in(fp,scanner);
143 while( yylex( scanner) != 0)
147 yylex_destroy(scanner);
148 pthread_mutex_unlock ( &file_locks[ next ] );
153 int main (int ARGC, char *ARGV[])
156 pthread_t threads[N_THREADS];
159 fprintf(stderr,"*** Error: No filenames specified.\n");
163 /* Allocate and initialize the locks. One for each filename in ARGV. */
164 file_locks = (pthread_mutex_t*)malloc( (ARGC-1) * sizeof(pthread_mutex_t));
165 for( i = 0; i < ARGC-1; i++)
166 pthread_mutex_init( &file_locks[i], NULL );
169 filenames = ARGV + 1;
172 /* prevent threads from starting until all threads have been created. */
173 pthread_mutex_lock(&go_ahead);
175 /* Create N threads then wait for them. */
176 for(i =0; i < N_THREADS ; i++ ) {
177 if( pthread_create( &threads[i], NULL, thread_func, NULL) != 0)
179 fprintf(stderr, "*** Error: pthread_create failed.\n");
182 printf("Created thread %d.\n",i); fflush(stdout);
185 /* Tell threads to begin. */
186 pthread_mutex_unlock(&go_ahead);
188 for(i =0; i < N_THREADS ; i++ ) {
189 pthread_join ( threads[i], NULL );
190 printf("Thread %d done.\n", i ); fflush(stdout);
193 for( i = 0; i < ARGC-1; i++)
194 pthread_mutex_destroy( &file_locks[i] );
196 pthread_mutex_destroy( &next_lock );
197 pthread_mutex_destroy( &go_ahead );
199 printf("TEST RETURNING OK.\n");
203 #endif /* HAVE_LIBPTHREAD */