Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

551 lines
13 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. mclex.c
  5. Abstract:
  6. This file contains the input lexer for the Win32 Message Compiler (MC)
  7. Author:
  8. Steve Wood (stevewo) 21-Aug-1991
  9. Revision History:
  10. --*/
  11. #include "mc.h"
  12. #define MAXLINELENGTH 8192
  13. WCHAR LineBuffer[ MAXLINELENGTH ];
  14. WCHAR *CurrentChar;
  15. BOOL ReturnCurrentToken;
  16. PNAME_INFO KeywordNames;
  17. typedef struct _COMMENT_INFO {
  18. struct _COMMENT_INFO *Next;
  19. WCHAR Text[ 1 ];
  20. } COMMENT_INFO, *PCOMMENT_INFO;
  21. PCOMMENT_INFO Comments, CurrentComment;
  22. BOOL
  23. McInitLexer( void )
  24. {
  25. ReturnCurrentToken = FALSE;
  26. McAddName( &KeywordNames, L"MessageIdTypedef", MCTOK_MSGIDTYPE_KEYWORD, NULL );
  27. McAddName( &KeywordNames, L"SeverityNames", MCTOK_SEVNAMES_KEYWORD, NULL );
  28. McAddName( &KeywordNames, L"FacilityNames", MCTOK_FACILITYNAMES_KEYWORD, NULL );
  29. McAddName( &KeywordNames, L"LanguageNames", MCTOK_LANGNAMES_KEYWORD, NULL );
  30. McAddName( &KeywordNames, L"MessageId", MCTOK_MESSAGEID_KEYWORD, NULL );
  31. McAddName( &KeywordNames, L"Severity", MCTOK_SEVERITY_KEYWORD, NULL );
  32. McAddName( &KeywordNames, L"Facility", MCTOK_FACILITY_KEYWORD, NULL );
  33. McAddName( &KeywordNames, L"SymbolicName", MCTOK_SYMBOLNAME_KEYWORD, NULL );
  34. McAddName( &KeywordNames, L"Language", MCTOK_LANGUAGE_KEYWORD, NULL );
  35. McAddName( &KeywordNames, L"OutputBase", MCTOK_OUTBASE_KEYWORD, NULL );
  36. McAddName( &KeywordNames, L"MessageIdTypedefMacro", MCTOK_MSGTYPEDEF_KEYWORD, NULL );
  37. return( TRUE );
  38. }
  39. BOOL
  40. McOpenInputFile( void )
  41. {
  42. char *PatchExt, *s, *FilePart;
  43. BOOL Result;
  44. PatchExt = NULL;
  45. s = MessageFileName + strlen( MessageFileName );
  46. FilePart = MessageFileName;
  47. // while (--s > MessageFileName) {
  48. while ((s = CharPrev(MessageFileName, s)) > MessageFileName) {
  49. if (*s == '.' && PatchExt == NULL) {
  50. PatchExt = s;
  51. *PatchExt = '\0';
  52. } else
  53. if (*s == ':' || *s == '\\' || *s == '/') {
  54. FilePart = s+1;
  55. break;
  56. }
  57. }
  58. MessageFileNameNoExt = malloc( strlen( FilePart ) + 1 );
  59. if (!MessageFileNameNoExt) {
  60. McInputErrorA( "Out of memory capturing file name", TRUE, NULL );
  61. return FALSE;
  62. }
  63. strcpy( MessageFileNameNoExt, FilePart );
  64. strcat( DebugFileName, MessageFileNameNoExt );
  65. strcat( DebugFileName, ".dbg" );
  66. strcat( HeaderFileName, MessageFileNameNoExt );
  67. strcat( HeaderFileName, "." );
  68. strcat( HeaderFileName, HeaderFileExt );
  69. strcat( RcInclFileName, MessageFileNameNoExt );
  70. strcat( RcInclFileName, ".rc" );
  71. if (PatchExt == NULL) {
  72. strcat( MessageFileName, ".mc" );
  73. } else {
  74. *PatchExt = '.';
  75. }
  76. MessageFileLineNumber = 0;
  77. LineBuffer[ 0 ] = L'\0';
  78. CurrentChar = NULL;
  79. Result = FALSE;
  80. MessageFile = fopen( MessageFileName, "rb" );
  81. if (MessageFile == NULL) {
  82. McInputErrorA( "unable to open input file", TRUE, NULL );
  83. } else {
  84. if (GenerateDebugFile) {
  85. DebugFile = fopen( DebugFileName, "wb" );
  86. if (DebugFile == NULL) {
  87. McInputErrorA( "unable to open output file - %s", TRUE, DebugFileName );
  88. goto fail;
  89. }
  90. }
  91. HeaderFile = fopen( HeaderFileName, "wb" );
  92. if (HeaderFile == NULL) {
  93. McInputErrorA( "unable to open output file - %s", TRUE, HeaderFileName );
  94. } else {
  95. RcInclFile = fopen( RcInclFileName, "wb" );
  96. if (RcInclFile == NULL) {
  97. McInputErrorA( "unable to open output file - %s", TRUE, RcInclFileName );
  98. } else {
  99. Result = TRUE;
  100. }
  101. }
  102. }
  103. fail:
  104. if (!Result) {
  105. McCloseInputFile();
  106. McCloseOutputFiles(Result);
  107. }
  108. return( Result );
  109. }
  110. void
  111. McCloseInputFile( void )
  112. {
  113. if (MessageFile != NULL) {
  114. fclose( MessageFile );
  115. MessageFile = NULL;
  116. CurrentChar = NULL;
  117. LineBuffer[ 0 ] = L'\0';
  118. }
  119. }
  120. void
  121. McClearArchiveBit( LPSTR Name )
  122. {
  123. DWORD Attributes;
  124. Attributes = GetFileAttributes(Name);
  125. if (Attributes != -1 && (Attributes & FILE_ATTRIBUTE_ARCHIVE)) {
  126. SetFileAttributes(Name, Attributes & ~FILE_ATTRIBUTE_ARCHIVE);
  127. }
  128. return;
  129. }
  130. void
  131. McCloseOutputFiles(
  132. BOOL Success
  133. )
  134. {
  135. if (DebugFile != NULL) {
  136. fclose( DebugFile );
  137. if (!Success) {
  138. _unlink(DebugFileName);
  139. } else {
  140. McClearArchiveBit(DebugFileName);
  141. }
  142. }
  143. if (HeaderFile != NULL) {
  144. fclose( HeaderFile );
  145. if (!Success) {
  146. _unlink(HeaderFileName);
  147. } else {
  148. McClearArchiveBit(HeaderFileName);
  149. }
  150. }
  151. if (RcInclFile != NULL) {
  152. fclose( RcInclFile );
  153. if (!Success) {
  154. _unlink(RcInclFileName);
  155. } else {
  156. McClearArchiveBit(RcInclFileName);
  157. }
  158. }
  159. }
  160. void
  161. McInputErrorA(
  162. char *Message,
  163. BOOL Error,
  164. PVOID Argument
  165. )
  166. {
  167. if (Error) {
  168. InputErrorCount += 1;
  169. }
  170. fprintf( stderr,
  171. "%s(%d) : %s : ",
  172. MessageFileName,
  173. MessageFileLineNumber,
  174. Error ? "error" : "warning"
  175. );
  176. fprintf( stderr, Message, Argument );
  177. fprintf( stderr, "\n" );
  178. }
  179. void
  180. McInputErrorW(
  181. WCHAR *Message,
  182. BOOL Error,
  183. PVOID Argument
  184. )
  185. {
  186. WCHAR buffer[ 256 * 2 ];
  187. fprintf( stderr,
  188. "%s(%d) : %s : ",
  189. MessageFileName,
  190. MessageFileLineNumber,
  191. Error ? "error" : "warning"
  192. );
  193. if (Error) {
  194. InputErrorCount += 1;
  195. }
  196. swprintf( buffer, Message, Argument );
  197. wcscat( buffer, L"\n" );
  198. if (UnicodeInput) {
  199. DWORD dwMode;
  200. DWORD cbWritten;
  201. HANDLE fh;
  202. fh = (HANDLE) _get_osfhandle( _fileno( stderr ) );
  203. if (GetConsoleMode( fh, &dwMode ))
  204. WriteConsoleW( fh, buffer, wcslen( buffer ), &cbWritten, NULL );
  205. else
  206. fwprintf( stderr, buffer );
  207. } else {
  208. BYTE chBuf[ 256 * 2 ];
  209. memset( chBuf, 0, sizeof( chBuf ) );
  210. WideCharToMultiByte( CP_OEMCP, 0, buffer, -1, chBuf, sizeof(chBuf), NULL, NULL );
  211. fprintf( stderr, chBuf );
  212. }
  213. }
  214. WCHAR *
  215. McGetLine( void )
  216. {
  217. WCHAR *s;
  218. if (MessageFile == NULL || feof( MessageFile )) {
  219. return( NULL );
  220. }
  221. if (fgetsW( LineBuffer,
  222. (sizeof( LineBuffer ) / sizeof( WCHAR )) - 1,
  223. MessageFile ) == NULL) {
  224. return( NULL );
  225. }
  226. s = LineBuffer + wcslen( LineBuffer );
  227. if (s > LineBuffer && *--s == L'\n') {
  228. if (s > LineBuffer && *--s != L'\r') {
  229. *++s = L'\r';
  230. *++s = L'\n';
  231. *++s = L'\0';
  232. }
  233. }
  234. MessageFileLineNumber++;
  235. return( CurrentChar = LineBuffer );
  236. }
  237. void
  238. McSkipLine( void )
  239. {
  240. CurrentChar = NULL;
  241. }
  242. WCHAR
  243. McGetChar(
  244. BOOL SkipWhiteSpace
  245. )
  246. {
  247. BOOL SawWhiteSpace;
  248. BOOL SawNewLine;
  249. PCOMMENT_INFO p;
  250. SawWhiteSpace = FALSE;
  251. tryagain:
  252. SawNewLine = FALSE;
  253. if (CurrentChar == NULL) {
  254. McGetLine();
  255. if (CurrentChar == NULL) {
  256. return( L'\0' );
  257. }
  258. SawNewLine = TRUE;
  259. }
  260. if (SkipWhiteSpace) {
  261. while (*CurrentChar <= L' ') {
  262. SawWhiteSpace = TRUE;
  263. if (!*CurrentChar++) {
  264. CurrentChar = NULL;
  265. break;
  266. }
  267. }
  268. }
  269. if (SawNewLine) {
  270. if (CurrentChar != NULL) {
  271. /* Check for Byte Order Mark during Unicode input */
  272. if (UnicodeInput) {
  273. if (*CurrentChar == 0xFEFF) {
  274. CurrentChar++;
  275. }
  276. }
  277. if (*CurrentChar == MCCHAR_END_OF_LINE_COMMENT) {
  278. p = malloc( sizeof( *p ) + wcslen( ++CurrentChar ) * sizeof( WCHAR ));
  279. if (!p) {
  280. McInputErrorA( "Out of memory reading chars", TRUE, NULL );
  281. return 0;
  282. }
  283. p->Next = NULL;
  284. wcscpy( p->Text, CurrentChar );
  285. if (CurrentComment == NULL) {
  286. Comments = p;
  287. } else {
  288. CurrentComment->Next = p;
  289. }
  290. CurrentComment = p;
  291. CurrentChar = NULL;
  292. }
  293. }
  294. }
  295. if (CurrentChar == NULL && SkipWhiteSpace) {
  296. goto tryagain;
  297. }
  298. if (SawWhiteSpace) {
  299. return( L' ' );
  300. } else {
  301. return( *CurrentChar++ );
  302. }
  303. }
  304. void
  305. McFlushComments( void )
  306. {
  307. PCOMMENT_INFO p;
  308. while (p = Comments) {
  309. fprintf( HeaderFile, "%ws", p->Text );
  310. Comments = Comments->Next;
  311. free( p );
  312. }
  313. Comments = NULL;
  314. CurrentComment = NULL;
  315. fflush( HeaderFile );
  316. return;
  317. }
  318. void
  319. McUnGetChar(
  320. WCHAR c
  321. )
  322. {
  323. if (CurrentChar > LineBuffer) {
  324. *--CurrentChar = c;
  325. } else {
  326. LineBuffer[ 0 ] = c;
  327. LineBuffer[ 1 ] = L'\0';
  328. CurrentChar = LineBuffer;
  329. }
  330. }
  331. unsigned int
  332. McGetToken(
  333. BOOL KeywordExpected
  334. )
  335. {
  336. WCHAR c, *dst;
  337. if (ReturnCurrentToken) {
  338. ReturnCurrentToken = FALSE;
  339. if (Token == MCTOK_NAME && KeywordExpected) {
  340. TokenKeyword = McFindName( KeywordNames, TokenCharValue );
  341. if (TokenKeyword == NULL) {
  342. McInputErrorW( L"expected keyword - %s", TRUE, TokenCharValue );
  343. Token = MCTOK_END_OF_FILE;
  344. } else {
  345. Token = (unsigned int)TokenKeyword->Id;
  346. }
  347. }
  348. return( Token );
  349. }
  350. Token = MCTOK_END_OF_FILE;
  351. dst = TokenCharValue;
  352. *dst = L'\0';
  353. TokenNumericValue = 0L;
  354. while (TRUE) {
  355. c = McGetChar( (BOOL)(Token == MCTOK_END_OF_FILE) );
  356. if (Token == MCTOK_NUMBER) {
  357. if (iswdigit( c ) ||
  358. c == L'x' ||
  359. (c >= L'a' && c <= L'f') ||
  360. (c >= L'A' && c <= L'F')
  361. ) {
  362. *dst++ = c;
  363. } else {
  364. McUnGetChar( c );
  365. *dst = L'\0';
  366. if (!McCharToInteger( TokenCharValue, 0, &TokenNumericValue )) {
  367. McInputErrorW( L"invalid number - %s", TRUE, TokenCharValue );
  368. Token = MCTOK_END_OF_FILE;
  369. } else {
  370. return( Token );
  371. }
  372. }
  373. } else
  374. if (Token == MCTOK_NAME) {
  375. if (iswcsym( c )) {
  376. *dst++ = c;
  377. } else {
  378. McUnGetChar( c );
  379. *dst = L'\0';
  380. if (KeywordExpected) {
  381. TokenKeyword = McFindName( KeywordNames, TokenCharValue );
  382. if (TokenKeyword == NULL) {
  383. McInputErrorW( L"expected keyword - %s", TRUE, TokenCharValue );
  384. Token = MCTOK_END_OF_FILE;
  385. } else {
  386. Token = (unsigned int)TokenKeyword->Id;
  387. }
  388. }
  389. return( Token );
  390. }
  391. } else
  392. if (iswdigit( c )) {
  393. *dst++ = c;
  394. Token = MCTOK_NUMBER;
  395. } else
  396. if (iswcsymf( c )) {
  397. *dst++ = c;
  398. Token = MCTOK_NAME;
  399. } else
  400. if (c == L'=') {
  401. *dst++ = c;
  402. *dst = L'\0';
  403. Token = MCTOK_EQUAL;
  404. return( Token );
  405. } else
  406. if (c == L'(') {
  407. *dst++ = c;
  408. *dst = L'\0';
  409. Token = MCTOK_LEFT_PAREN;
  410. return( Token );
  411. } else
  412. if (c == L')') {
  413. *dst++ = c;
  414. *dst = L'\0';
  415. Token = MCTOK_RIGHT_PAREN;
  416. return( Token );
  417. } else
  418. if (c == L':') {
  419. *dst++ = c;
  420. *dst = L'\0';
  421. Token = MCTOK_COLON;
  422. return( Token );
  423. } else
  424. if (c == L'+') {
  425. *dst++ = c;
  426. *dst = L'\0';
  427. Token = MCTOK_PLUS;
  428. return( Token );
  429. } else
  430. if (c == L' ') {
  431. } else
  432. if (c == MCCHAR_END_OF_LINE_COMMENT) {
  433. Token = MCTOK_END_OF_LINE_COMMENT;
  434. wcscpy( TokenCharValue, CurrentChar );
  435. CurrentChar = NULL;
  436. return( Token );
  437. } else
  438. if (c == L'\0') {
  439. return( Token );
  440. } else {
  441. McInputErrorW( L"invalid character (0x%02x)", TRUE, (PVOID)UlongToPtr((UCHAR)c) );
  442. }
  443. }
  444. }
  445. void
  446. McUnGetToken( void )
  447. {
  448. ReturnCurrentToken = TRUE;
  449. }
  450. WCHAR *
  451. McSkipWhiteSpace(
  452. WCHAR *s
  453. )
  454. {
  455. while (*s <= L' ') {
  456. if (!*s++) {
  457. s = NULL;
  458. break;
  459. }
  460. }
  461. return( s );
  462. }