1*357f1050SThomas Veerman /*
2*357f1050SThomas Veerman  * This file is part of flex.
3*357f1050SThomas Veerman  *
4*357f1050SThomas Veerman  * Redistribution and use in source and binary forms, with or without
5*357f1050SThomas Veerman  * modification, are permitted provided that the following conditions
6*357f1050SThomas Veerman  * are met:
7*357f1050SThomas Veerman  *
8*357f1050SThomas Veerman  * 1. Redistributions of source code must retain the above copyright
9*357f1050SThomas Veerman  *    notice, this list of conditions and the following disclaimer.
10*357f1050SThomas Veerman  * 2. Redistributions in binary form must reproduce the above copyright
11*357f1050SThomas Veerman  *    notice, this list of conditions and the following disclaimer in the
12*357f1050SThomas Veerman  *    documentation and/or other materials provided with the distribution.
13*357f1050SThomas Veerman  *
14*357f1050SThomas Veerman  * Neither the name of the University nor the names of its contributors
15*357f1050SThomas Veerman  * may be used to endorse or promote products derived from this software
16*357f1050SThomas Veerman  * without specific prior written permission.
17*357f1050SThomas Veerman  *
18*357f1050SThomas Veerman  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
19*357f1050SThomas Veerman  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
20*357f1050SThomas Veerman  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21*357f1050SThomas Veerman  * PURPOSE.
22*357f1050SThomas Veerman  */
23*357f1050SThomas Veerman 
24*357f1050SThomas Veerman %{
25*357f1050SThomas Veerman /* A scanner file to build "scanner.c".
26*357f1050SThomas Veerman    Input language is any text made of spaces, newlines, and alphanumerics.
27*357f1050SThomas Veerman 
28*357f1050SThomas Veerman    We create N_THREADS number of threads. Each thread has it's own scanner.
29*357f1050SThomas Veerman    Each thread selects one of the files specified in ARGV, scans it, then
30*357f1050SThomas Veerman    closes it. This is repeated N_SCANS numebr of times for each thread.
31*357f1050SThomas Veerman 
32*357f1050SThomas Veerman    The idea is to press the scanner to break under threads.
33*357f1050SThomas Veerman    If we see  "Scanner Jammed", then we know
34*357f1050SThomas Veerman 
35*357f1050SThomas Veerman */
36*357f1050SThomas Veerman #include <stdio.h>
37*357f1050SThomas Veerman #include <stdlib.h>
38*357f1050SThomas Veerman #include <config.h>
39*357f1050SThomas Veerman 
40*357f1050SThomas Veerman #ifdef HAVE_PTHREAD_H
41*357f1050SThomas Veerman #include <pthread.h>
42*357f1050SThomas Veerman #endif
43*357f1050SThomas Veerman 
44*357f1050SThomas Veerman /* A naive test for segfaults when accessing yytext. */
45*357f1050SThomas Veerman static int process_text(char* s, yyscan_t  scanner);
46*357f1050SThomas Veerman 
47*357f1050SThomas Veerman %}
48*357f1050SThomas Veerman 
49*357f1050SThomas Veerman %option 8bit outfile="scanner.c" prefix="test"
50*357f1050SThomas Veerman %option nounput nomain nodefault
51*357f1050SThomas Veerman %option yywrap
52*357f1050SThomas Veerman %option reentrant
53*357f1050SThomas Veerman %option warn
54*357f1050SThomas Veerman 
55*357f1050SThomas Veerman     /* Arbitrary states.*/
56*357f1050SThomas Veerman %x STATE_1
57*357f1050SThomas Veerman %x STATE_2
58*357f1050SThomas Veerman 
59*357f1050SThomas Veerman %%
60*357f1050SThomas Veerman 
61*357f1050SThomas Veerman     #define NUMBER 200
62*357f1050SThomas Veerman     #define WORD   201
63*357f1050SThomas Veerman 
64*357f1050SThomas Veerman <INITIAL>[[:digit:]]+ { BEGIN(STATE_1); process_text(yytext,yyscanner); return NUMBER; }
65*357f1050SThomas Veerman <INITIAL>[[:alpha:]]+ { BEGIN(STATE_2); process_text(yytext,yyscanner); return WORD; }
66*357f1050SThomas Veerman 
67*357f1050SThomas Veerman <STATE_1>[[:alpha:]]+ { BEGIN(0); process_text(yytext,yyscanner); return WORD; }
68*357f1050SThomas Veerman <STATE_1>[[:digit:]]+ { BEGIN(0); process_text(yytext,yyscanner); return NUMBER; }
69*357f1050SThomas Veerman 
70*357f1050SThomas Veerman <STATE_2>[[:alpha:]]+ { BEGIN(0); process_text(yytext,yyscanner); return WORD; }
71*357f1050SThomas Veerman <STATE_2>[[:digit:]]+ { BEGIN(0); process_text(yytext,yyscanner); return NUMBER; }
72*357f1050SThomas Veerman 
73*357f1050SThomas Veerman <INITIAL,STATE_1,STATE_2>" "|\t|\r|\n { process_text(yytext,yyscanner); }
74*357f1050SThomas Veerman <INITIAL,STATE_1,STATE_2>[^[:alnum:][:space:]\t\r\n] {
75*357f1050SThomas Veerman         /*fprintf(stderr,"*** Error: bad input char '%c'.\n", yytext[0]); */
76*357f1050SThomas Veerman         yyterminate();
77*357f1050SThomas Veerman     }
78*357f1050SThomas Veerman <INITIAL,STATE_1,STATE_2>[[:space:]\r\n]+  { }
79*357f1050SThomas Veerman %%
80*357f1050SThomas Veerman 
81*357f1050SThomas Veerman int yywrap( yyscan_t  scanner) { return 1; }
process_text(char * s,yyscan_t scanner)82*357f1050SThomas Veerman static int process_text(char* s, yyscan_t  scanner)
83*357f1050SThomas Veerman {
84*357f1050SThomas Veerman     return (int)(*s) + (int) *(s + yyget_leng(scanner)-1);
85*357f1050SThomas Veerman }
86*357f1050SThomas Veerman 
87*357f1050SThomas Veerman int main(int ARGC, char *ARGV[]);
88*357f1050SThomas Veerman 
89*357f1050SThomas Veerman #ifndef HAVE_LIBPTHREAD
main(int ARGC,char * ARGV[])90*357f1050SThomas Veerman   int main (int ARGC, char *ARGV[]) {
91*357f1050SThomas Veerman     printf(
92*357f1050SThomas Veerman        "TEST ABORTED because pthread library not available \n"
93*357f1050SThomas Veerman        "-- This is expected on some systems. It is not a flex error.\n" );
94*357f1050SThomas Veerman     return 0;
95*357f1050SThomas Veerman   }
96*357f1050SThomas Veerman #else
97*357f1050SThomas Veerman 
98*357f1050SThomas Veerman #define N_THREADS 4
99*357f1050SThomas Veerman #define N_SCANS   20
100*357f1050SThomas Veerman #define INPUT_FILE "test.input"
101*357f1050SThomas Veerman 
102*357f1050SThomas Veerman /* Each thread selects the next file to scan in round-robin fashion.
103*357f1050SThomas Veerman    If there are less files than threads, some threads may block. */
104*357f1050SThomas Veerman 
105*357f1050SThomas Veerman static pthread_mutex_t next_lock = PTHREAD_MUTEX_INITIALIZER;
106*357f1050SThomas Veerman static pthread_mutex_t go_ahead  = PTHREAD_MUTEX_INITIALIZER;
107*357f1050SThomas Veerman static int n_files, next_file;
108*357f1050SThomas Veerman 
109*357f1050SThomas Veerman static pthread_mutex_t *file_locks;
110*357f1050SThomas Veerman static char **filenames;
111*357f1050SThomas Veerman 
112*357f1050SThomas Veerman 
thread_func(void * arg)113*357f1050SThomas Veerman void * thread_func ( void* arg )
114*357f1050SThomas Veerman {
115*357f1050SThomas Veerman     int i;
116*357f1050SThomas Veerman 
117*357f1050SThomas Veerman     /* Wait for go-ahead. */
118*357f1050SThomas Veerman     pthread_mutex_lock( &go_ahead);
119*357f1050SThomas Veerman     pthread_mutex_unlock(&go_ahead);
120*357f1050SThomas Veerman 
121*357f1050SThomas Veerman     for( i =0 ; i < N_SCANS ; i++ )
122*357f1050SThomas Veerman     {
123*357f1050SThomas Veerman         int main(int ARGC, char *ARGV[]);
124*357f1050SThomas Veerman 
125*357f1050SThomas Veerman         int next;
126*357f1050SThomas Veerman         yyscan_t  scanner;
127*357f1050SThomas Veerman         FILE * fp;
128*357f1050SThomas Veerman 
129*357f1050SThomas Veerman         pthread_mutex_lock ( &next_lock );
130*357f1050SThomas Veerman         next = (next_file++) % n_files;
131*357f1050SThomas Veerman         pthread_mutex_unlock ( &next_lock );
132*357f1050SThomas Veerman 
133*357f1050SThomas Veerman         pthread_mutex_lock ( &file_locks[ next ] );
134*357f1050SThomas Veerman 
135*357f1050SThomas Veerman         yylex_init( &scanner );
136*357f1050SThomas Veerman         /*printf("Scanning file %s  #%d\n",filenames[next],i); fflush(stdout); */
137*357f1050SThomas Veerman         if((fp = fopen(filenames[next],"r"))==NULL) {
138*357f1050SThomas Veerman             perror("fopen");
139*357f1050SThomas Veerman             return NULL;
140*357f1050SThomas Veerman         }
141*357f1050SThomas Veerman         yyset_in(fp,scanner);
142*357f1050SThomas Veerman 
143*357f1050SThomas Veerman         while( yylex( scanner) != 0)
144*357f1050SThomas Veerman         {
145*357f1050SThomas Veerman         }
146*357f1050SThomas Veerman         fclose(fp);
147*357f1050SThomas Veerman         yylex_destroy(scanner);
148*357f1050SThomas Veerman         pthread_mutex_unlock ( &file_locks[ next ] );
149*357f1050SThomas Veerman     }
150*357f1050SThomas Veerman     return NULL;
151*357f1050SThomas Veerman }
152*357f1050SThomas Veerman 
main(int ARGC,char * ARGV[])153*357f1050SThomas Veerman int main (int ARGC, char *ARGV[])
154*357f1050SThomas Veerman {
155*357f1050SThomas Veerman     int i;
156*357f1050SThomas Veerman     pthread_t threads[N_THREADS];
157*357f1050SThomas Veerman 
158*357f1050SThomas Veerman     if( ARGC < 2 ) {
159*357f1050SThomas Veerman         fprintf(stderr,"*** Error: No filenames specified.\n");
160*357f1050SThomas Veerman         exit(-1);
161*357f1050SThomas Veerman     }
162*357f1050SThomas Veerman 
163*357f1050SThomas Veerman     /* Allocate and initialize the locks. One for each filename in ARGV. */
164*357f1050SThomas Veerman     file_locks = (pthread_mutex_t*)malloc( (ARGC-1) * sizeof(pthread_mutex_t));
165*357f1050SThomas Veerman     for( i = 0; i < ARGC-1; i++)
166*357f1050SThomas Veerman         pthread_mutex_init( &file_locks[i], NULL );
167*357f1050SThomas Veerman 
168*357f1050SThomas Veerman     n_files = ARGC -1;
169*357f1050SThomas Veerman     filenames = ARGV + 1;
170*357f1050SThomas Veerman     next_file = 0;
171*357f1050SThomas Veerman 
172*357f1050SThomas Veerman     /* prevent threads from starting until all threads have been created. */
173*357f1050SThomas Veerman     pthread_mutex_lock(&go_ahead);
174*357f1050SThomas Veerman 
175*357f1050SThomas Veerman     /* Create N threads then wait for them. */
176*357f1050SThomas Veerman     for(i =0; i < N_THREADS ; i++ ) {
177*357f1050SThomas Veerman         if( pthread_create( &threads[i], NULL, thread_func, NULL) != 0)
178*357f1050SThomas Veerman         {
179*357f1050SThomas Veerman             fprintf(stderr, "*** Error: pthread_create failed.\n");
180*357f1050SThomas Veerman             exit(-1);
181*357f1050SThomas Veerman         }
182*357f1050SThomas Veerman         printf("Created thread %d.\n",i); fflush(stdout);
183*357f1050SThomas Veerman     }
184*357f1050SThomas Veerman 
185*357f1050SThomas Veerman     /* Tell threads to begin. */
186*357f1050SThomas Veerman     pthread_mutex_unlock(&go_ahead);
187*357f1050SThomas Veerman 
188*357f1050SThomas Veerman     for(i =0; i < N_THREADS ; i++ ) {
189*357f1050SThomas Veerman         pthread_join ( threads[i], NULL );
190*357f1050SThomas Veerman         printf("Thread %d done.\n", i ); fflush(stdout);
191*357f1050SThomas Veerman     }
192*357f1050SThomas Veerman 
193*357f1050SThomas Veerman     for( i = 0; i < ARGC-1; i++)
194*357f1050SThomas Veerman         pthread_mutex_destroy( &file_locks[i] );
195*357f1050SThomas Veerman 
196*357f1050SThomas Veerman     pthread_mutex_destroy( &next_lock );
197*357f1050SThomas Veerman     pthread_mutex_destroy( &go_ahead );
198*357f1050SThomas Veerman     free( file_locks );
199*357f1050SThomas Veerman     printf("TEST RETURNING OK.\n");
200*357f1050SThomas Veerman     return 0;
201*357f1050SThomas Veerman }
202*357f1050SThomas Veerman 
203*357f1050SThomas Veerman #endif /* HAVE_LIBPTHREAD */
204*357f1050SThomas Veerman 
205