Use portable types in the C/C++ code generator
[ragel-jkt.git] / ragel / common.cpp
blob05e9eccd02d23887a0500b13048b9fc2eebdc158
1 /*
2 * Copyright 2006-2007 Adrian Thurston <thurston@complang.org>
3 */
5 /* This file is part of Ragel.
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.
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.
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
22 // The standard-sized types were introduced in C++11. That's too new to require
23 // here, so let's use the fallback from plain C.
24 // However, in the C++ mode, the INT<num>_MAX etc macros are only defined when
25 // explicitly asked for.
26 // Which is also why we absolutely have to include this header first.
27 #define __STDC_LIMIT_MACROS
28 #include "stdint.h"
30 #include "pcheck.h"
31 #include "common.h"
32 #include "stdlib.h"
33 #include <string.h>
34 #include <assert.h>
36 #define HOST_TYPE_C(BITS) \
37 { "int" #BITS "_t", 0, "int" #BITS "_t", true, true, false, INT##BITS##_MIN, INT##BITS##_MAX, sizeof(int##BITS##_t) }, \
38 { "uint" #BITS "_t", 0, "uint" #BITS "_t", false, true, false, 0, UINT##BITS##_MAX, sizeof(uint##BITS##_t) }
40 HostType hostTypesC[] =
42 HOST_TYPE_C(8),
43 HOST_TYPE_C(16),
44 HOST_TYPE_C(32),
45 HOST_TYPE_C(64)
48 #define S8BIT_MIN -128
49 #define S8BIT_MAX 127
51 #define U8BIT_MIN 0
52 #define U8BIT_MAX 255
54 #define S16BIT_MIN -32768
55 #define S16BIT_MAX 32767
57 #define U16BIT_MIN 0
58 #define U16BIT_MAX 65535
60 #define S31BIT_MIN -1073741824L
61 #define S31BIT_MAX 1073741823L
63 #define S32BIT_MIN -2147483648L
64 #define S32BIT_MAX 2147483647L
66 #define U32BIT_MIN 0
67 #define U32BIT_MAX 4294967295UL
69 #define S64BIT_MIN -9223372036854775807LL
70 #define S64BIT_MAX 9223372036854775807LL
72 #define U64BIT_MIN 0
73 #define U64BIT_MAX 18446744073709551615ULL
75 HostType hostTypesD[] =
77 { "byte", 0, "byte", true, true, false, CHAR_MIN, CHAR_MAX, 1 },
78 { "ubyte", 0, "ubyte", false, true, false, 0, UCHAR_MAX, 1 },
79 { "char", 0, "char", false, true, false, 0, UCHAR_MAX, 1 },
80 { "short", 0, "short", true, true, false, SHRT_MIN, SHRT_MAX, 2 },
81 { "ushort", 0, "ushort", false, true, false, 0, USHRT_MAX, 2 },
82 { "wchar", 0, "wchar", false, true, false, 0, USHRT_MAX, 2 },
83 { "int", 0, "int", true, true, false, INT_MIN, INT_MAX, 4 },
84 { "uint", 0, "uint", false, true, false, 0, UINT_MAX, 4 },
85 { "dchar", 0, "dchar", false, true, false, 0, UINT_MAX, 4 }
88 HostType hostTypesGo[] =
90 { "byte", 0, "uint8", false, true, false, U8BIT_MIN, U8BIT_MAX, 1 },
91 { "int8", 0, "int8", true, true, false, S8BIT_MIN, S8BIT_MAX, 1 },
92 { "uint8", 0, "uint8", false, true, false, U8BIT_MIN, U8BIT_MAX, 1 },
93 { "int16", 0, "int16", true, true, false, S16BIT_MIN, S16BIT_MAX, 2 },
94 { "uint16", 0, "uint16", false, true, false, U16BIT_MIN, U16BIT_MAX, 2 },
95 { "int32", 0, "int32", true, true, false, S32BIT_MIN, S32BIT_MAX, 4 },
96 { "uint32", 0, "uint32", false, true, false, U32BIT_MIN, U32BIT_MAX, 4 },
97 { "int64", 0, "int64", true, true, false, S64BIT_MIN, S64BIT_MAX, 8 },
98 { "uint64", 0, "uint64", false, true, false, U64BIT_MIN, U64BIT_MAX, 8 },
99 { "rune", 0, "int32", true, true, true, S32BIT_MIN, S32BIT_MAX, 4 }
102 HostType hostTypesJava[] =
104 { "byte", 0, "byte", true, true, false, CHAR_MIN, CHAR_MAX, 1 },
105 { "short", 0, "short", true, true, false, SHRT_MIN, SHRT_MAX, 2 },
106 { "char", 0, "char", false, true, false, 0, USHRT_MAX, 2 },
107 { "int", 0, "int", true, true, false, INT_MIN, INT_MAX, 4 },
110 /* What are the appropriate types for ruby? */
111 HostType hostTypesRuby[] =
113 { "char", 0, "char", true, true, false, CHAR_MIN, CHAR_MAX, 1 },
114 { "int", 0, "int", true, true, false, INT_MIN, INT_MAX, 4 },
117 HostType hostTypesCSharp[] =
119 { "sbyte", 0, "sbyte", true, true, false, CHAR_MIN, CHAR_MAX, 1 },
120 { "byte", 0, "byte", false, true, false, 0, UCHAR_MAX, 1 },
121 { "short", 0, "short", true, true, false, SHRT_MIN, SHRT_MAX, 2 },
122 { "ushort", 0, "ushort", false, true, false, 0, USHRT_MAX, 2 },
123 { "char", 0, "char", false, true, true, 0, USHRT_MAX, 2 },
124 { "int", 0, "int", true, true, false, INT_MIN, INT_MAX, 4 },
125 { "uint", 0, "uint", false, true, false, 0, UINT_MAX, 4 },
126 { "long", 0, "long", true, true, false, LONG_MIN, LONG_MAX, 8 },
127 { "ulong", 0, "ulong", false, true, false, 0, ULONG_MAX, 8 }
130 HostType hostTypesOCaml[] =
132 // { "char", 0, "char", false, true, false, 0, UCHAR_MAX, 1 },
133 { "int", 0, "int", true, true, false, S31BIT_MIN, S31BIT_MAX, 4 },
136 HostLang hostLangC = { HostLang::C, hostTypesC, 8, hostTypesC+0, true };
137 HostLang hostLangD = { HostLang::D, hostTypesD, 9, hostTypesD+2, true };
138 HostLang hostLangD2 = { HostLang::D2, hostTypesD, 9, hostTypesD+2, true };
139 HostLang hostLangGo = { HostLang::Go, hostTypesGo, 10, hostTypesGo+0, false };
140 HostLang hostLangJava = { HostLang::Java, hostTypesJava, 4, hostTypesJava+2, false };
141 HostLang hostLangRuby = { HostLang::Ruby, hostTypesRuby, 2, hostTypesRuby+0, false };
142 HostLang hostLangCSharp = { HostLang::CSharp, hostTypesCSharp, 9, hostTypesCSharp+4, true };
143 HostLang hostLangOCaml = { HostLang::OCaml, hostTypesOCaml, 1, hostTypesOCaml+0, false };
145 HostLang *hostLang = &hostLangC;
147 HostType *findAlphType( const char *s1 )
149 for ( int i = 0; i < hostLang->numHostTypes; i++ ) {
150 if ( strcmp( s1, hostLang->hostTypes[i].data1 ) == 0 &&
151 hostLang->hostTypes[i].data2 == 0 )
153 return hostLang->hostTypes + i;
157 return 0;
160 HostType *findAlphType( const char *s1, const char *s2 )
162 for ( int i = 0; i < hostLang->numHostTypes; i++ ) {
163 if ( strcmp( s1, hostLang->hostTypes[i].data1 ) == 0 &&
164 hostLang->hostTypes[i].data2 != 0 &&
165 strcmp( s2, hostLang->hostTypes[i].data2 ) == 0 )
167 return hostLang->hostTypes + i;
171 return 0;
174 HostType *findAlphTypeInternal( const char *s1 )
176 for ( int i = 0; i < hostLang->numHostTypes; i++ ) {
177 if ( strcmp( s1, hostLang->hostTypes[i].internalName ) == 0 )
178 return hostLang->hostTypes + i;
181 return 0;
184 /* Construct a new parameter checker with for paramSpec. */
185 ParamCheck::ParamCheck( const char *paramSpec, int argc, const char **argv )
187 state(noparam),
188 argOffset(0),
189 curArg(0),
190 iCurArg(1),
191 paramSpec(paramSpec),
192 argc(argc),
193 argv(argv)
197 /* Check a single option. Returns the index of the next parameter. Sets p to
198 * the arg character if valid, 0 otherwise. Sets parg to the parameter arg if
199 * there is one, NULL otherwise. */
200 bool ParamCheck::check()
202 bool requiresParam;
204 if ( iCurArg >= argc ) { /* Off the end of the arg list. */
205 state = noparam;
206 return false;
209 if ( argOffset != 0 && *argOffset == 0 ) {
210 /* We are at the end of an arg string. */
211 iCurArg += 1;
212 if ( iCurArg >= argc ) {
213 state = noparam;
214 return false;
216 argOffset = 0;
219 if ( argOffset == 0 ) {
220 /* Set the current arg. */
221 curArg = argv[iCurArg];
223 /* We are at the beginning of an arg string. */
224 if ( argv[iCurArg] == 0 || /* Argv[iCurArg] is null. */
225 argv[iCurArg][0] != '-' || /* Not a param. */
226 argv[iCurArg][1] == 0 ) { /* Only a dash. */
227 parameter = 0;
228 paramArg = 0;
230 iCurArg += 1;
231 state = noparam;
232 return true;
234 argOffset = argv[iCurArg] + 1;
237 /* Get the arg char. */
238 char argChar = *argOffset;
240 /* Loop over all the parms and look for a match. */
241 const char *pSpec = paramSpec;
242 while ( *pSpec != 0 ) {
243 char pSpecChar = *pSpec;
245 /* If there is a ':' following the char then
246 * it requires a parm. If a parm is required
247 * then move ahead two in the parmspec. Otherwise
248 * move ahead one in the parm spec. */
249 if ( pSpec[1] == ':' ) {
250 requiresParam = true;
251 pSpec += 2;
253 else {
254 requiresParam = false;
255 pSpec += 1;
258 /* Do we have a match. */
259 if ( argChar == pSpecChar ) {
260 if ( requiresParam ) {
261 if ( argOffset[1] == 0 ) {
262 /* The param must follow. */
263 if ( iCurArg + 1 == argc ) {
264 /* We are the last arg so there
265 * cannot be a parameter to it. */
266 parameter = argChar;
267 paramArg = 0;
268 iCurArg += 1;
269 argOffset = 0;
270 state = invalid;
271 return true;
273 else {
274 /* the parameter to the arg is the next arg. */
275 parameter = pSpecChar;
276 paramArg = argv[iCurArg + 1];
277 iCurArg += 2;
278 argOffset = 0;
279 state = match;
280 return true;
283 else {
284 /* The param for the arg is built in. */
285 parameter = pSpecChar;
286 paramArg = argOffset + 1;
287 iCurArg += 1;
288 argOffset = 0;
289 state = match;
290 return true;
293 else {
294 /* Good, we matched the parm and no
295 * arg is required. */
296 parameter = pSpecChar;
297 paramArg = 0;
298 argOffset += 1;
299 state = match;
300 return true;
305 /* We did not find a match. Bad Argument. */
306 parameter = argChar;
307 paramArg = 0;
308 argOffset += 1;
309 state = invalid;
310 return true;
313 /* Counts newlines before sending sync. */
314 int output_filter::sync( )
316 line += 1;
317 return std::filebuf::sync();
320 /* Counts newlines before sending data out to file. */
321 std::streamsize output_filter::xsputn( const char *s, std::streamsize n )
323 for ( int i = 0; i < n; i++ ) {
324 if ( s[i] == '\n' )
325 line += 1;
327 return std::filebuf::xsputn( s, n );
330 /* Scans a string looking for the file extension. If there is a file
331 * extension then pointer returned points to inside the string
332 * passed in. Otherwise returns null. */
333 const char *findFileExtension( const char *stemFile )
335 const char *ppos = stemFile + strlen(stemFile) - 1;
337 /* Scan backwards from the end looking for the first dot.
338 * If we encounter a '/' before the first dot, then stop the scan. */
339 while ( 1 ) {
340 /* If we found a dot or got to the beginning of the string then
341 * we are done. */
342 if ( ppos == stemFile || *ppos == '.' )
343 break;
345 /* If we hit a / then there is no extension. Done. */
346 if ( *ppos == '/' ) {
347 ppos = stemFile;
348 break;
350 ppos--;
353 /* If we got to the front of the string then bail we
354 * did not find an extension */
355 if ( ppos == stemFile )
356 ppos = 0;
358 return ppos;
361 /* Make a file name from a stem. Removes the old filename suffix and
362 * replaces it with a new one. Returns a newed up string. */
363 const char *fileNameFromStem( const char *stemFile, const char *suffix )
365 long len = strlen( stemFile );
366 assert( len > 0 );
368 /* Get the extension. */
369 const char *ppos = findFileExtension( stemFile );
371 /* If an extension was found, then shorten what we think the len is. */
372 if ( ppos != 0 )
373 len = ppos - stemFile;
375 /* Make the return string from the stem and the suffix. */
376 char *retVal = new char[ len + strlen( suffix ) + 1 ];
377 strncpy( retVal, stemFile, len );
378 strcpy( retVal + len, suffix );
380 return retVal;
383 exit_object endp;
385 void operator<<( std::ostream &out, exit_object & )
387 out << std::endl;
388 exit(1);