The alphabet type is now communicated from the frontend to the backend using a
[external/ragel.git] / common / common.cpp
1 /*
2  *  Copyright 2006-2007 Adrian Thurston <thurston@cs.queensu.ca>
3  */
4
5 /*  This file is part of Ragel.
6  *
7  *  Ragel is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License as published by
9  *  the Free Software Foundation; either version 2 of the License, or
10  *  (at your option) any later version.
11  * 
12  *  Ragel is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *  GNU General Public License for more details.
16  * 
17  *  You should have received a copy of the GNU General Public License
18  *  along with Ragel; if not, write to the Free Software
19  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
20  */
21
22 #include "pcheck.h"
23 #include "common.h"
24 #include "stdlib.h"
25 #include <assert.h>
26
27 HostType hostTypesC[] =
28 {
29         { "char",     0,       "char",    true,   CHAR_MIN,  CHAR_MAX,   sizeof(char) },
30         { "unsigned", "char",  "uchar",   false,  0,         UCHAR_MAX,  sizeof(unsigned char) },
31         { "short",    0,       "short",   true,   SHRT_MIN,  SHRT_MAX,   sizeof(short) },
32         { "unsigned", "short", "ushort",  false,  0,         USHRT_MAX,  sizeof(unsigned short) },
33         { "int",      0,       "int",     true,   INT_MIN,   INT_MAX,    sizeof(int) },
34         { "unsigned", "int",   "uint",    false,  0,         UINT_MAX,   sizeof(unsigned int) },
35         { "long",     0,       "long",    true,   LONG_MIN,  LONG_MAX,   sizeof(long) },
36         { "unsigned", "long",  "ulong",   false,  0,         ULONG_MAX,  sizeof(unsigned long) }
37 };
38
39 HostType hostTypesD[] =
40 {
41         { "byte",    0,  "byte",    true,   CHAR_MIN,  CHAR_MAX,    1 },
42         { "ubyte",   0,  "ubyte",   false,  0,         UCHAR_MAX,   1 },
43         { "char",    0,  "char",    false,  0,         UCHAR_MAX,   1 },
44         { "short",   0,  "short",   true,   SHRT_MIN,  SHRT_MAX,    2 },
45         { "ushort",  0,  "ushort",  false,  0,         USHRT_MAX,   2 },
46         { "wchar",   0,  "wchar",   false,  0,         USHRT_MAX,   2 },
47         { "int",     0,  "int",     true,   INT_MIN,   INT_MAX,     4 },
48         { "uint",    0,  "uint",    false,  0,         UINT_MAX,    4 },
49         { "dchar",   0,  "dchar",   false,  0,         UINT_MAX,    4 }
50 };
51
52 HostType hostTypesJava[] = 
53 {
54         { "byte",    0,  "byte",   true,   CHAR_MIN,  CHAR_MAX,    1 },
55         { "short",   0,  "short",  true,   SHRT_MIN,  SHRT_MAX,    2 },
56         { "char",    0,  "char",   false,  0,         USHRT_MAX,   2 },
57         { "int",     0,  "int",    true,   INT_MIN,   INT_MAX,     4 },
58 };
59
60 /* What are the appropriate types for ruby? */
61 HostType hostTypesRuby[] = 
62 {
63         { "char",    0,  "char",   true,   CHAR_MIN,  CHAR_MAX,    1 },
64         { "int",     0,  "int",    true,   INT_MIN,   INT_MAX,     4 },
65 };
66
67 HostLang hostLangC =    { HostLang::C,    hostTypesC,    8, hostTypesC+0,    true };
68 HostLang hostLangD =    { HostLang::D,    hostTypesD,    9, hostTypesD+2,    true };
69 HostLang hostLangJava = { HostLang::Java, hostTypesJava, 4, hostTypesJava+2, false };
70 HostLang hostLangRuby = { HostLang::Ruby, hostTypesRuby, 2, hostTypesRuby+0, false };
71
72 HostLang *hostLang = &hostLangC;
73
74 HostType *findAlphType( char *s1 )
75 {
76         for ( int i = 0; i < hostLang->numHostTypes; i++ ) {
77                 if ( strcmp( s1, hostLang->hostTypes[i].data1 ) == 0 && 
78                                 hostLang->hostTypes[i].data2 == 0 )
79                 {
80                         return hostLang->hostTypes + i;
81                 }
82         }
83
84         return 0;
85 }
86
87 HostType *findAlphType( char *s1, char *s2 )
88 {
89         for ( int i = 0; i < hostLang->numHostTypes; i++ ) {
90                 if ( strcmp( s1, hostLang->hostTypes[i].data1 ) == 0 && 
91                                 hostLang->hostTypes[i].data2 != 0 && 
92                                 strcmp( s2, hostLang->hostTypes[i].data2 ) == 0 )
93                 {
94                         return hostLang->hostTypes + i;
95                 }
96         }
97
98         return 0;
99 }
100
101 HostType *findAlphTypeInternal( char *s1 )
102 {
103         for ( int i = 0; i < hostLang->numHostTypes; i++ ) {
104                 if ( strcmp( s1, hostLang->hostTypes[i].internalName ) == 0 )
105                         return hostLang->hostTypes + i;
106         }
107
108         return 0;
109 }
110
111 /* Construct a new parameter checker with for paramSpec. */
112 ParamCheck::ParamCheck(char *paramSpec, int argc, char **argv)
113 :
114         state(noparam),
115         argOffset(0),
116         curArg(0),
117         iCurArg(1),
118         paramSpec(paramSpec), 
119         argc(argc), 
120         argv(argv)
121 {
122 }
123
124 /* Check a single option. Returns the index of the next parameter.  Sets p to
125  * the arg character if valid, 0 otherwise.  Sets parg to the parameter arg if
126  * there is one, NULL otherwise. */
127 bool ParamCheck::check()
128 {
129         bool requiresParam;
130
131         if ( iCurArg >= argc ) {            /* Off the end of the arg list. */
132                 state = noparam;
133                 return false;
134         }
135
136         if ( argOffset != 0 && *argOffset == 0 ) {
137                 /* We are at the end of an arg string. */
138                 iCurArg += 1;
139                 if ( iCurArg >= argc ) {
140                         state = noparam;
141                         return false;
142                 }
143                 argOffset = 0;
144         }
145
146         if ( argOffset == 0 ) {
147                 /* Set the current arg. */
148                 curArg = argv[iCurArg];
149
150                 /* We are at the beginning of an arg string. */
151                 if ( argv[iCurArg] == 0 ||        /* Argv[iCurArg] is null. */
152                          argv[iCurArg][0] != '-' ||   /* Not a param. */
153                          argv[iCurArg][1] == 0 ) {    /* Only a dash. */
154                         parameter = 0;
155                         parameterArg = 0;
156
157                         iCurArg += 1;
158                         state = noparam;
159                         return true;
160                 }
161                 argOffset = argv[iCurArg] + 1;
162         }
163
164         /* Get the arg char. */
165         char argChar = *argOffset;
166         
167         /* Loop over all the parms and look for a match. */
168         char *pSpec = paramSpec;
169         while ( *pSpec != 0 ) {
170                 char pSpecChar = *pSpec;
171
172                 /* If there is a ':' following the char then
173                  * it requires a parm.  If a parm is required
174                  * then move ahead two in the parmspec. Otherwise
175                  * move ahead one in the parm spec. */
176                 if ( pSpec[1] == ':' ) {
177                         requiresParam = true;
178                         pSpec += 2;
179                 }
180                 else {
181                         requiresParam = false;
182                         pSpec += 1;
183                 }
184
185                 /* Do we have a match. */
186                 if ( argChar == pSpecChar ) {
187                         if ( requiresParam ) {
188                                 if ( argOffset[1] == 0 ) {
189                                         /* The param must follow. */
190                                         if ( iCurArg + 1 == argc ) {
191                                                 /* We are the last arg so there
192                                                  * cannot be a parameter to it. */
193                                                 parameter = argChar;
194                                                 parameterArg = 0;
195                                                 iCurArg += 1;
196                                                 argOffset = 0;
197                                                 state = invalid;
198                                                 return true;
199                                         }
200                                         else {
201                                                 /* the parameter to the arg is the next arg. */
202                                                 parameter = pSpecChar;
203                                                 parameterArg = argv[iCurArg + 1];
204                                                 iCurArg += 2;
205                                                 argOffset = 0;
206                                                 state = match;
207                                                 return true;
208                                         }
209                                 }
210                                 else {
211                                         /* The param for the arg is built in. */
212                                         parameter = pSpecChar;
213                                         parameterArg = argOffset + 1;
214                                         iCurArg += 1;
215                                         argOffset = 0;
216                                         state = match;
217                                         return true;
218                                 }
219                         }
220                         else {
221                                 /* Good, we matched the parm and no
222                                  * arg is required. */
223                                 parameter = pSpecChar;
224                                 parameterArg = 0;
225                                 argOffset += 1;
226                                 state = match;
227                                 return true;
228                         }
229                 }
230         }
231
232         /* We did not find a match. Bad Argument. */
233         parameter = argChar;
234         parameterArg = 0;
235         argOffset += 1;
236         state = invalid;
237         return true;
238 }
239
240 /* Counts newlines before sending sync. */
241 int output_filter::sync( )
242 {
243         line += 1;
244         return std::filebuf::sync();
245 }
246
247 /* Counts newlines before sending data out to file. */
248 std::streamsize output_filter::xsputn( const char *s, std::streamsize n )
249 {
250         for ( int i = 0; i < n; i++ ) {
251                 if ( s[i] == '\n' )
252                         line += 1;
253         }
254         return std::filebuf::xsputn( s, n );
255 }
256
257 /* Scans a string looking for the file extension. If there is a file
258  * extension then pointer returned points to inside the string
259  * passed in. Otherwise returns null. */
260 char *findFileExtension( char *stemFile )
261 {
262         char *ppos = stemFile + strlen(stemFile) - 1;
263
264         /* Scan backwards from the end looking for the first dot.
265          * If we encounter a '/' before the first dot, then stop the scan. */
266         while ( 1 ) {
267                 /* If we found a dot or got to the beginning of the string then
268                  * we are done. */
269                 if ( ppos == stemFile || *ppos == '.' )
270                         break;
271
272                 /* If we hit a / then there is no extension. Done. */
273                 if ( *ppos == '/' ) {
274                         ppos = stemFile;
275                         break;
276                 }
277                 ppos--;
278         } 
279
280         /* If we got to the front of the string then bail we 
281          * did not find an extension  */
282         if ( ppos == stemFile )
283                 ppos = 0;
284
285         return ppos;
286 }
287
288 /* Make a file name from a stem. Removes the old filename suffix and
289  * replaces it with a new one. Returns a newed up string. */
290 char *fileNameFromStem( char *stemFile, char *suffix )
291 {
292         long len = strlen( stemFile );
293         assert( len > 0 );
294
295         /* Get the extension. */
296         char *ppos = findFileExtension( stemFile );
297
298         /* If an extension was found, then shorten what we think the len is. */
299         if ( ppos != 0 )
300                 len = ppos - stemFile;
301
302         /* Make the return string from the stem and the suffix. */
303         char *retVal = new char[ len + strlen( suffix ) + 1 ];
304         strncpy( retVal, stemFile, len );
305         strcpy( retVal + len, suffix );
306
307         return retVal;
308 }
309
310 exit_object endp;
311
312 void operator<<( std::ostream &out, exit_object & )
313 {
314     out << std::endl;
315     exit(1);
316 }