4 * Ullrich von Bassewitz, 07.06.1998
34 /*****************************************************************************/
36 /*****************************************************************************/
40 Token CurTok; /* The current token */
41 Token NextTok; /* The next token */
46 #define TT_C 0 /* ANSI C token */
47 #define TT_EXT 1 /* cc65 extension */
50 static const struct Keyword {
51 char* Key; /* Keyword name */
52 unsigned char Tok; /* The token */
53 unsigned char Type; /* Token type */
55 { "__A__", TOK_A, TT_C },
56 { "__AX__", TOK_AX, TT_C },
57 { "__EAX__", TOK_EAX, TT_C },
58 { "__X__", TOK_X, TT_C },
59 { "__Y__", TOK_Y, TT_C },
60 { "__asm__", TOK_ASM, TT_C },
61 { "__attribute__", TOK_ATTRIBUTE, TT_C },
62 { "__far__", TOK_FAR, TT_C },
63 { "__fastcall__", TOK_FASTCALL, TT_C },
64 { "asm", TOK_ASM, TT_EXT },
65 { "auto", TOK_AUTO, TT_C },
66 { "break", TOK_BREAK, TT_C },
67 { "case", TOK_CASE, TT_C },
68 { "char", TOK_CHAR, TT_C },
69 { "const", TOK_CONST, TT_C },
70 { "continue", TOK_CONTINUE, TT_C },
71 { "default", TOK_DEFAULT, TT_C },
72 { "do", TOK_DO, TT_C },
73 { "double", TOK_DOUBLE, TT_C },
74 { "else", TOK_ELSE, TT_C },
75 { "enum", TOK_ENUM, TT_C },
76 { "extern", TOK_EXTERN, TT_C },
77 { "far", TOK_FAR, TT_EXT },
78 { "fastcall", TOK_FASTCALL, TT_EXT },
79 { "float", TOK_FLOAT, TT_C },
80 { "for", TOK_FOR, TT_C },
81 { "goto", TOK_GOTO, TT_C },
82 { "if", TOK_IF, TT_C },
83 { "int", TOK_INT, TT_C },
84 { "long", TOK_LONG, TT_C },
85 { "register", TOK_REGISTER, TT_C },
86 { "return", TOK_RETURN, TT_C },
87 { "short", TOK_SHORT, TT_C },
88 { "signed", TOK_SIGNED, TT_C },
89 { "sizeof", TOK_SIZEOF, TT_C },
90 { "static", TOK_STATIC, TT_C },
91 { "struct", TOK_STRUCT, TT_C },
92 { "switch", TOK_SWITCH, TT_C },
93 { "typedef", TOK_TYPEDEF, TT_C },
94 { "union", TOK_UNION, TT_C },
95 { "unsigned", TOK_UNSIGNED, TT_C },
96 { "void", TOK_VOID, TT_C },
97 { "volatile", TOK_VOLATILE, TT_C },
98 { "while", TOK_WHILE, TT_C },
100 #define KEY_COUNT (sizeof (Keywords) / sizeof (Keywords [0]))
104 /* Stuff for determining the type of an integer constant */
108 #define IT_ULONG 0x08
112 /*****************************************************************************/
114 /*****************************************************************************/
118 static int CmpKey (const void* Key, const void* Elem)
119 /* Compare function for bsearch */
121 return strcmp ((const char*) Key, ((const struct Keyword*) Elem)->Key);
126 static int FindKey (const char* Key)
127 /* Find a keyword and return the token. Return IDENT if the token is not a
132 K = bsearch (Key, Keywords, KEY_COUNT, sizeof (Keywords [0]), CmpKey);
133 if (K && (K->Type != TT_EXT || ANSI == 0)) {
142 static int SkipWhite (void)
143 /* Skip white space in the input stream, reading and preprocessing new lines
144 * if necessary. Return 0 if end of file is reached, return 1 otherwise.
149 if (NextLine () == 0) {
154 if (CurC == ' ' || CurC == '\r') {
164 void SymName (char* s)
165 /* Get symbol from input stream */
169 if (k != MAX_IDENTLEN) {
174 } while (IsIdent (CurC) || IsDigit (CurC));
181 /* Get symbol from input stream or return 0 if not a symbol. */
183 if (IsIdent (CurC)) {
193 static void unknown (char C)
194 /* Error message for unknown character */
196 Error ("Invalid input character with code %02X", C & 0xFF);
197 NextChar (); /* Skip */
202 static unsigned hexval (int c)
203 /* Convert a hex digit into a value */
206 Error ("Invalid hexadecimal digit: `%c'", c);
211 return toupper (c) - 'A' + 10;
217 static void SetTok (int tok)
218 /* set nxttok and bump line ptr */
226 static int SignExtendChar (int C)
227 /* Do correct sign extension of a character */
229 if (SignedChars && (C & 0x80) != 0) {
238 static int ParseChar (void)
239 /* Parse a character. Converts \n into EOL, etc. */
245 /* Check for escape chars */
275 /* Hex character constant */
277 val = hexval (CurC) << 4;
279 C = val | hexval (CurC); /* Do not translate */
286 while (NextC >= '0' && NextC <= '7' && i++ < 4) {
288 C = (C << 3) | (CurC - '0');
292 Error ("Illegal character constant");
300 /* Skip the character read */
303 /* Do correct sign extension */
304 return SignExtendChar (C);
309 static void CharConst (void)
310 /* Parse a character constant. */
320 /* Check for closing quote */
322 Error ("`\'' expected");
328 /* Setup values and attributes */
331 /* Translate into target charset */
332 nxtval = SignExtendChar (TgtTranslateChar (C));
334 /* Character constants have type int */
340 static void StringConst (void)
341 /* Parse a quoted string */
343 nxtval = GetLiteralOffs ();
346 /* Be sure to concatenate strings */
347 while (CurC == '\"') {
349 /* Skip the quote char */
352 while (CurC != '\"') {
354 Error ("Unexpected newline");
357 AddLiteralChar (ParseChar ());
360 /* Skip closing quote char if there was one */
363 /* Skip white space, read new input */
368 /* Terminate the string */
369 AddLiteralChar ('\0');
374 void NextToken (void)
375 /* Get next token from input stream */
379 /* Current token is the lookahead token */
382 /* Remember the starting position of the next token */
383 NextTok.Pos = GetCurrentLine();
385 /* Skip spaces and read the next line if needed */
386 if (SkipWhite () == 0) {
387 /* End of file reached */
392 /* Determine the next token from the lookahead */
393 if (IsDigit (CurC)) {
396 int HaveSuffix; /* True if we have a type suffix */
397 unsigned types; /* Possible types */
399 unsigned long k; /* Value */
403 types = IT_INT | IT_LONG | IT_ULONG;
406 /* Octal or hex constants may also be of type unsigned int */
407 types = IT_INT | IT_UINT | IT_LONG | IT_ULONG;
408 /* gobble 0 and examin next char */
410 if (toupper (CurC) == 'X') {
413 NextChar (); /* gobble "x" */
419 if (IsDigit (CurC)) {
420 k = k * base + (CurC - '0');
421 } else if (base == 16 && IsXDigit (CurC)) {
422 k = (k << 4) + hexval (CurC);
424 break; /* not digit */
426 NextChar (); /* gobble char */
429 /* Check for a suffix */
431 if (CurC == 'u' || CurC == 'U') {
434 if (toupper (CurC) != 'L') {
435 types = IT_UINT | IT_ULONG;
440 } else if (CurC == 'l' || CurC == 'L') {
443 if (toupper (CurC) != 'U') {
444 types = IT_LONG | IT_ULONG;
453 /* Check the range to determine the type */
455 /* Out of range for int */
457 /* If the value is in the range 0x8000..0xFFFF, unsigned int is not
458 * allowed, and we don't have a type specifying suffix, emit a
461 if (k <= 0xFFFF && (types & IT_UINT) == 0 && !HaveSuffix) {
462 Warning ("Constant is long");
466 /* Out of range for unsigned int */
469 if (k > 0x7FFFFFFF) {
470 /* Out of range for long int */
474 /* Now set the type string to the smallest type in types */
475 if (types & IT_INT) {
477 } else if (types & IT_UINT) {
479 } else if (types & IT_LONG) {
482 nxttype = type_ulong;
485 /* Set the value and the token */
493 /* Check for a keyword */
494 if ((nxttok = FindKey (token)) != TOK_IDENT) {
495 /* Reserved word found */
498 /* No reserved word, check for special symbols */
499 if (token [0] == '_') {
500 /* Special symbols */
501 if (strcmp (token, "__FILE__") == 0) {
502 nxtval = AddLiteral (GetCurrentFile());
505 } else if (strcmp (token, "__LINE__") == 0) {
507 nxtval = GetCurrentLine();
510 } else if (strcmp (token, "__fixargs__") == 0) {
512 nxtval = GetParamSize (CurrentFunc);
515 } else if (strcmp (token, "__func__") == 0) {
516 /* __func__ is only defined in functions */
518 nxtval = AddLiteral (GetFuncName (CurrentFunc));
525 /* No reserved word but identifier */
526 strcpy (NextTok.Ident, token);
527 NextTok.Tok = TOK_IDENT;
531 /* Monstrous switch statement ahead... */
539 nxttok = TOK_BOOL_NOT;
550 SetTok (TOK_MOD_ASSIGN);
560 SetTok (TOK_BOOL_AND);
563 SetTok (TOK_AND_ASSIGN);
585 SetTok (TOK_MUL_ASSIGN);
598 SetTok (TOK_PLUS_ASSIGN);
616 SetTok (TOK_MINUS_ASSIGN);
619 SetTok (TOK_PTR_REF);
631 SetTok (TOK_ELLIPSIS);
643 SetTok (TOK_DIV_ASSIGN);
666 SetTok (TOK_SHL_ASSIGN);
694 SetTok (TOK_SHR_ASSIGN);
719 SetTok (TOK_XOR_ASSIGN);
733 SetTok (TOK_BOOL_OR);
736 SetTok (TOK_OR_ASSIGN);
752 /* Skip it and following whitespace */
755 } while (CurC == ' ');
756 if (!IsSym (token) || strcmp (token, "pragma") != 0) {
757 /* OOPS - should not happen */
758 Error ("Preprocessor directive expected");
772 void Consume (token_t Token, const char* ErrorMsg)
773 /* Eat token if it is the next in the input stream, otherwise print an error
777 if (curtok == Token) {
786 void ConsumeColon (void)
787 /* Check for a colon and skip it. */
789 Consume (TOK_COLON, "`:' expected");
794 void ConsumeSemi (void)
795 /* Check for a semicolon and skip it. */
797 /* Try do be smart about typos... */
798 if (curtok == TOK_SEMI) {
801 Error ("`;' expected");
802 if (curtok == TOK_COLON || curtok == TOK_COMMA) {
810 void ConsumeComma (void)
811 /* Check for a comma and skip it. */
813 /* Try do be smart about typos... */
814 if (CurTok.Tok == TOK_COMMA) {
817 Error ("`,' expected");
818 if (CurTok.Tok == TOK_SEMI) {
826 void ConsumeLParen (void)
827 /* Check for a left parenthesis and skip it */
829 Consume (TOK_LPAREN, "`(' expected");
834 void ConsumeRParen (void)
835 /* Check for a right parenthesis and skip it */
837 Consume (TOK_RPAREN, "`)' expected");
842 void ConsumeLBrack (void)
843 /* Check for a left bracket and skip it */
845 Consume (TOK_LBRACK, "`[' expected");
850 void ConsumeRBrack (void)
851 /* Check for a right bracket and skip it */
853 Consume (TOK_RBRACK, "`]' expected");
858 void ConsumeLCurly (void)
859 /* Check for a left curly brace and skip it */
861 Consume (TOK_LCURLY, "`{' expected");
866 void ConsumeRCurly (void)
867 /* Check for a right curly brace and skip it */
869 Consume (TOK_RCURLY, "`}' expected");