2 * Copyright 2006-2007 Adrian Thurston <thurston@complang.org>
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
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
[] =
48 #define S8BIT_MIN -128
54 #define S16BIT_MIN -32768
55 #define S16BIT_MAX 32767
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
67 #define U32BIT_MAX 4294967295UL
69 #define S64BIT_MIN -9223372036854775807LL
70 #define S64BIT_MAX 9223372036854775807LL
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
;
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
;
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
;
184 /* Construct a new parameter checker with for paramSpec. */
185 ParamCheck::ParamCheck( const char *paramSpec
, int argc
, const char **argv
)
191 paramSpec(paramSpec
),
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()
204 if ( iCurArg
>= argc
) { /* Off the end of the arg list. */
209 if ( argOffset
!= 0 && *argOffset
== 0 ) {
210 /* We are at the end of an arg string. */
212 if ( iCurArg
>= argc
) {
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. */
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;
254 requiresParam
= false;
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. */
274 /* the parameter to the arg is the next arg. */
275 parameter
= pSpecChar
;
276 paramArg
= argv
[iCurArg
+ 1];
284 /* The param for the arg is built in. */
285 parameter
= pSpecChar
;
286 paramArg
= argOffset
+ 1;
294 /* Good, we matched the parm and no
295 * arg is required. */
296 parameter
= pSpecChar
;
305 /* We did not find a match. Bad Argument. */
313 /* Counts newlines before sending sync. */
314 int output_filter::sync( )
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
++ ) {
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. */
340 /* If we found a dot or got to the beginning of the string then
342 if ( ppos
== stemFile
|| *ppos
== '.' )
345 /* If we hit a / then there is no extension. Done. */
346 if ( *ppos
== '/' ) {
353 /* If we got to the front of the string then bail we
354 * did not find an extension */
355 if ( ppos
== stemFile
)
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
);
368 /* Get the extension. */
369 const char *ppos
= findFileExtension( stemFile
);
371 /* If an extension was found, then shorten what we think the len is. */
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
);
385 void operator<<( std::ostream
&out
, exit_object
& )