Parse errors in the intermediate XML file now cause the backend to exit
[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,       true,   CHAR_MIN,  CHAR_MAX,   sizeof(char) },
30         { "unsigned", "char",  false,  0,         UCHAR_MAX,  sizeof(unsigned char) },
31         { "short",    0,       true,   SHRT_MIN,  SHRT_MAX,   sizeof(short) },
32         { "unsigned", "short", false,  0,         USHRT_MAX,  sizeof(unsigned short) },
33         { "int",      0,       true,   INT_MIN,   INT_MAX,    sizeof(int) },
34         { "unsigned", "int",   false,  0,         UINT_MAX,   sizeof(unsigned int) },
35         { "long",     0,       true,   LONG_MIN,  LONG_MAX,   sizeof(long) },
36         { "unsigned", "long",  false,  0,         ULONG_MAX,  sizeof(unsigned long) }
37 };
38
39 HostType hostTypesD[] =
40 {
41         { "byte",     0,  true,   CHAR_MIN,  CHAR_MAX,    1 },
42         { "ubyte",    0,  false,  0,         UCHAR_MAX,   1 },
43         { "char",     0,  false,  0,         UCHAR_MAX,   1 },
44         { "short",    0,  true,   SHRT_MIN,  SHRT_MAX,    2 },
45         { "ushort",   0,  false,  0,         USHRT_MAX,   2 },
46         { "wchar",    0,  false,  0,         USHRT_MAX,   2 },
47         { "int",      0,  true,   INT_MIN,   INT_MAX,     4 },
48         { "uint",     0,  false,  0,         UINT_MAX,    4 },
49         { "dchar",    0,  false,  0,         UINT_MAX,    4 }
50 };
51
52 HostType hostTypesJava[] = 
53 {
54         { "byte",     0,  true,   CHAR_MIN,  CHAR_MAX,    1 },
55         { "short",    0,  true,   SHRT_MIN,  SHRT_MAX,    2 },
56         { "char",     0,  false,  0,         USHRT_MAX,   2 },
57         { "int",      0,  true,   INT_MIN,   INT_MAX,     4 },
58 };
59
60 HostType hostTypesRuby[] = 
61 {
62         { "byte",     0,  true,   CHAR_MIN,  CHAR_MAX,    1 },
63         { "short",    0,  true,   SHRT_MIN,  SHRT_MAX,    2 },
64         { "char",     0,  false,  0,         USHRT_MAX,   2 },
65         { "int",      0,  true,   INT_MIN,   INT_MAX,     4 },
66 };
67
68 HostLang hostLangC =    { hostTypesC,    8, hostTypesC+0,    true };
69 HostLang hostLangD =    { hostTypesD,    9, hostTypesD+2,    true };
70 HostLang hostLangJava = { hostTypesJava, 4, hostTypesJava+2, false };
71 HostLang hostLangRuby = { hostTypesRuby, 4, hostTypesRuby+2, false };
72
73 HostLang *hostLang = &hostLangC;
74 HostLangType hostLangType = CCode;
75
76 /* Construct a new parameter checker with for paramSpec. */
77 ParamCheck::ParamCheck(char *paramSpec, int argc, char **argv)
78 :
79         state(noparam),
80         argOffset(0),
81         curArg(0),
82         iCurArg(1),
83         paramSpec(paramSpec), 
84         argc(argc), 
85         argv(argv)
86 {
87 }
88
89 /* Check a single option. Returns the index of the next parameter.  Sets p to
90  * the arg character if valid, 0 otherwise.  Sets parg to the parameter arg if
91  * there is one, NULL otherwise. */
92 bool ParamCheck::check()
93 {
94         bool requiresParam;
95
96         if ( iCurArg >= argc ) {            /* Off the end of the arg list. */
97                 state = noparam;
98                 return false;
99         }
100
101         if ( argOffset != 0 && *argOffset == 0 ) {
102                 /* We are at the end of an arg string. */
103                 iCurArg += 1;
104                 if ( iCurArg >= argc ) {
105                         state = noparam;
106                         return false;
107                 }
108                 argOffset = 0;
109         }
110
111         if ( argOffset == 0 ) {
112                 /* Set the current arg. */
113                 curArg = argv[iCurArg];
114
115                 /* We are at the beginning of an arg string. */
116                 if ( argv[iCurArg] == 0 ||        /* Argv[iCurArg] is null. */
117                          argv[iCurArg][0] != '-' ||   /* Not a param. */
118                          argv[iCurArg][1] == 0 ) {    /* Only a dash. */
119                         parameter = 0;
120                         parameterArg = 0;
121
122                         iCurArg += 1;
123                         state = noparam;
124                         return true;
125                 }
126                 argOffset = argv[iCurArg] + 1;
127         }
128
129         /* Get the arg char. */
130         char argChar = *argOffset;
131         
132         /* Loop over all the parms and look for a match. */
133         char *pSpec = paramSpec;
134         while ( *pSpec != 0 ) {
135                 char pSpecChar = *pSpec;
136
137                 /* If there is a ':' following the char then
138                  * it requires a parm.  If a parm is required
139                  * then move ahead two in the parmspec. Otherwise
140                  * move ahead one in the parm spec. */
141                 if ( pSpec[1] == ':' ) {
142                         requiresParam = true;
143                         pSpec += 2;
144                 }
145                 else {
146                         requiresParam = false;
147                         pSpec += 1;
148                 }
149
150                 /* Do we have a match. */
151                 if ( argChar == pSpecChar ) {
152                         if ( requiresParam ) {
153                                 if ( argOffset[1] == 0 ) {
154                                         /* The param must follow. */
155                                         if ( iCurArg + 1 == argc ) {
156                                                 /* We are the last arg so there
157                                                  * cannot be a parameter to it. */
158                                                 parameter = argChar;
159                                                 parameterArg = 0;
160                                                 iCurArg += 1;
161                                                 argOffset = 0;
162                                                 state = invalid;
163                                                 return true;
164                                         }
165                                         else {
166                                                 /* the parameter to the arg is the next arg. */
167                                                 parameter = pSpecChar;
168                                                 parameterArg = argv[iCurArg + 1];
169                                                 iCurArg += 2;
170                                                 argOffset = 0;
171                                                 state = match;
172                                                 return true;
173                                         }
174                                 }
175                                 else {
176                                         /* The param for the arg is built in. */
177                                         parameter = pSpecChar;
178                                         parameterArg = argOffset + 1;
179                                         iCurArg += 1;
180                                         argOffset = 0;
181                                         state = match;
182                                         return true;
183                                 }
184                         }
185                         else {
186                                 /* Good, we matched the parm and no
187                                  * arg is required. */
188                                 parameter = pSpecChar;
189                                 parameterArg = 0;
190                                 argOffset += 1;
191                                 state = match;
192                                 return true;
193                         }
194                 }
195         }
196
197         /* We did not find a match. Bad Argument. */
198         parameter = argChar;
199         parameterArg = 0;
200         argOffset += 1;
201         state = invalid;
202         return true;
203 }
204
205 /* Counts newlines before sending sync. */
206 int output_filter::sync( )
207 {
208         line += 1;
209         return std::filebuf::sync();
210 }
211
212 /* Counts newlines before sending data out to file. */
213 std::streamsize output_filter::xsputn( const char *s, std::streamsize n )
214 {
215         for ( int i = 0; i < n; i++ ) {
216                 if ( s[i] == '\n' )
217                         line += 1;
218         }
219         return std::filebuf::xsputn( s, n );
220 }
221
222 /* Scans a string looking for the file extension. If there is a file
223  * extension then pointer returned points to inside the string
224  * passed in. Otherwise returns null. */
225 char *findFileExtension( char *stemFile )
226 {
227         char *ppos = stemFile + strlen(stemFile) - 1;
228
229         /* Scan backwards from the end looking for the first dot.
230          * If we encounter a '/' before the first dot, then stop the scan. */
231         while ( 1 ) {
232                 /* If we found a dot or got to the beginning of the string then
233                  * we are done. */
234                 if ( ppos == stemFile || *ppos == '.' )
235                         break;
236
237                 /* If we hit a / then there is no extension. Done. */
238                 if ( *ppos == '/' ) {
239                         ppos = stemFile;
240                         break;
241                 }
242                 ppos--;
243         } 
244
245         /* If we got to the front of the string then bail we 
246          * did not find an extension  */
247         if ( ppos == stemFile )
248                 ppos = 0;
249
250         return ppos;
251 }
252
253 /* Make a file name from a stem. Removes the old filename suffix and
254  * replaces it with a new one. Returns a newed up string. */
255 char *fileNameFromStem( char *stemFile, char *suffix )
256 {
257         long len = strlen( stemFile );
258         assert( len > 0 );
259
260         /* Get the extension. */
261         char *ppos = findFileExtension( stemFile );
262
263         /* If an extension was found, then shorten what we think the len is. */
264         if ( ppos != 0 )
265                 len = ppos - stemFile;
266
267         /* Make the return string from the stem and the suffix. */
268         char *retVal = new char[ len + strlen( suffix ) + 1 ];
269         strncpy( retVal, stemFile, len );
270         strcpy( retVal + len, suffix );
271
272         return retVal;
273 }
274
275 exit_object endp;
276
277 void operator<<( std::ostream &out, exit_object & )
278 {
279     out << std::endl;
280     exit(1);
281 }