common.cpp 12 KB

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