This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

Objective C: in @IDENTIFIER, IDENTIFER is subject to macro expansion


Since the integrated preprocessor, Objective C code has not
macro-expanded the IDENTIFIER in @IDENTIFIER.  This is a major
semantic change from the way the language used to work.

This patch restores the old behavior.  It should have minimal impact
on other code.  Note that the test case will fail despite the patch;
this is due to another bug in ObjC string handling, not the
preprocessor's fault.

I am running a bootstrap now.  OK for branch and trunk?

zw
	* c-parse.in (yylexname): New function, split out of _yylex.
	(objc_rid_sans_at): New table.
	(init_reswords): Initialize it.
	(_yylex): Give labels clearer names.  Handle CPP_ATSIGN by
	retrieving the next token and checking it for significance as
	an ObjC keyword or string constant.

	* cpplex.c (_cpp_lex_token): Just return CPP_ATSIGN for '@'.
	* cpplib.h (TTYPE_TABLE): Add CPP_ATSIGN, drop CPP_OSTRING.

	* c-lex.c, c-parse.in, cppmacro.c, cpplex.c: Remove references
	to CPP_OSTRING.

	* objc/execute/string3.m: New test.

===================================================================
Index: c-lex.c
--- c-lex.c	2001/03/03 11:32:30	1.132
+++ c-lex.c	2001/03/05 23:10:55
@@ -1014,7 +1014,6 @@ c_lex (value)
 
     case CPP_STRING:
     case CPP_WSTRING:
-    case CPP_OSTRING:
       *value = lex_string ((const char *)tok.val.str.text,
 			   tok.val.str.len, tok.type == CPP_WSTRING);
       break;
===================================================================
Index: c-parse.in
--- c-parse.in	2001/03/02 00:39:59	1.83
+++ c-parse.in	2001/03/05 23:10:56
@@ -263,6 +263,7 @@ end ifobjc
 
 static void yyprint	  PARAMS ((FILE *, int, YYSTYPE));
 static void yyerror	  PARAMS ((const char *));
+static int yylexname	  PARAMS ((void));
 static inline int _yylex  PARAMS ((void));
 static int  yylex	  PARAMS ((void));
 static void init_reswords PARAMS ((void));
@@ -3114,6 +3115,13 @@ static const short rid_to_yy[RID_MAX] =
   /* RID_AT_IMPLEMENTATION */	IMPLEMENTATION
 };
 
+ifobjc
+/* Lookup table for ObjC keywords beginning with '@'.  Crude but
+   hopefully effective.  */
+#define N_at_reswords ((int) RID_AT_IMPLEMENTATION - (int)RID_AT_ENCODE + 1)
+static tree objc_rid_sans_at[N_at_reswords];
+end ifobjc
+
 static void
 init_reswords ()
 {
@@ -3139,6 +3147,16 @@ init_reswords ()
       C_RID_CODE (id) = reswords[i].rid;
       C_IS_RESERVED_WORD (id) = 1;
       ridpointers [(int) reswords[i].rid] = id;
+
+ifobjc
+      /* Enter ObjC @-prefixed keywords into the "sans" table
+	 _without_ their leading at-sign.  Again, all these
+	 identifiers are reachable by the get_identifer table, so it's
+	 not necessary to make objc_rid_sans_at a GC root.  */
+      if (reswords[i].word[0] == '@')
+	objc_rid_sans_at[(int) reswords[i].rid - (int) RID_AT_ENCODE]
+	  = get_identifier (reswords[i].word + 1);
+end ifobjc
     }
 ifobjc
   save_and_forget_protocol_qualifiers ();
@@ -3188,8 +3206,7 @@ yyerror (msgid)
 	error ("%s before %s'\\x%x'", string, ell, val);
     }
   else if (last_token == CPP_STRING
-	   || last_token == CPP_WSTRING
-	   || last_token == CPP_OSTRING)
+	   || last_token == CPP_WSTRING)
     error ("%s before string constant", string);
   else if (last_token == CPP_NUMBER
 	   || last_token == CPP_INT
@@ -3201,12 +3218,65 @@ yyerror (msgid)
     error ("%s before '%s' token", string, NAME(last_token));
 }
 
+static int
+yylexname ()
+{
+  tree decl;
+
+  if (C_IS_RESERVED_WORD (yylval.ttype))
+    {
+      enum rid rid_code = C_RID_CODE (yylval.ttype);
+      /* Return the canonical spelling for this keyword.  */
+      yylval.ttype = ridpointers[(int) rid_code];
+      return rid_to_yy[(int) rid_code];
+    }
+
+  decl = lookup_name (yylval.ttype);
+  if (decl)
+    {
+      if (TREE_CODE (decl) == TYPE_DECL)
+	return TYPENAME;
+      /* A user-invisible read-only initialized variable
+	 should be replaced by its value.
+	 We handle only strings since that's the only case used in C.  */
+      else if (TREE_CODE (decl) == VAR_DECL
+	       && DECL_IGNORED_P (decl)
+	       && TREE_READONLY (decl)
+	       && DECL_INITIAL (decl) != 0
+	       && TREE_CODE (DECL_INITIAL (decl)) == STRING_CST)
+	{
+	  tree stringval = DECL_INITIAL (decl);
+
+	  /* Copy the string value so that we won't clobber anything
+	     if we put something in the TREE_CHAIN of this one.  */
+	  yylval.ttype = build_string (TREE_STRING_LENGTH (stringval),
+				       TREE_STRING_POINTER (stringval));
+	  return STRING;
+	}
+    }
+  else if (doing_objc_thang)
+    {
+      tree objc_interface_decl = is_class_name (yylval.ttype);
+
+      if (objc_interface_decl)
+	{
+	  yylval.ttype = objc_interface_decl;
+	  return CLASSNAME;
+	}
+    }
+
+  return IDENTIFIER;
+}
+
+
 static inline int
 _yylex ()
 {
- retry:
+ get_next:
   last_token = c_lex (&yylval.ttype);
-
+ifobjc
+ reconsider:
+end ifobjc
   switch (last_token)
     {
     case CPP_EQ:					return '=';
@@ -3263,64 +3333,11 @@ _yylex ()
     case CPP_EOF:
       if (cpp_pop_buffer (parse_in) == 0)
 	return 0;
-      goto retry;
+      goto get_next;
 
     case CPP_NAME:
-      if (C_IS_RESERVED_WORD (yylval.ttype))
-	{
-	  enum rid rid_code = C_RID_CODE (yylval.ttype);
-	  /* Return the canonical spelling for this keyword.  */
-	  yylval.ttype = ridpointers[(int) rid_code];
-	  return rid_to_yy[(int) rid_code];
-	}
-
-      if (IDENTIFIER_POINTER (yylval.ttype)[0] == '@')
-	{
-	  error ("invalid identifier `%s'", IDENTIFIER_POINTER (yylval.ttype));
-	  return IDENTIFIER;
-	}
-
-      {
-	tree decl;
-
-	decl = lookup_name (yylval.ttype);
-
-	if (decl)
-	  {
-	    if (TREE_CODE (decl) == TYPE_DECL)
-	      return TYPENAME;
-	    /* A user-invisible read-only initialized variable
-	       should be replaced by its value.
-	       We handle only strings since that's the only case used in C.  */
-	    else if (TREE_CODE (decl) == VAR_DECL
-		     && DECL_IGNORED_P (decl)
-		     && TREE_READONLY (decl)
-		     && DECL_INITIAL (decl) != 0
-		     && TREE_CODE (DECL_INITIAL (decl)) == STRING_CST)
-	      {
-		tree stringval = DECL_INITIAL (decl);
-
-		/* Copy the string value so that we won't clobber anything
-		   if we put something in the TREE_CHAIN of this one.  */
-		yylval.ttype = build_string (TREE_STRING_LENGTH (stringval),
-					     TREE_STRING_POINTER (stringval));
-		return STRING;
-	      }
-	  }
-	else if (doing_objc_thang)
-	  {
-	    tree objc_interface_decl = is_class_name (yylval.ttype);
+      return yylexname ();
 
-	    if (objc_interface_decl)
-	      {
-		yylval.ttype = objc_interface_decl;
-		return CLASSNAME;
-	      }
-	  }
-
-	return IDENTIFIER;
-      }
-
     case CPP_INT:
     case CPP_FLOAT:
     case CPP_NUMBER:
@@ -3332,9 +3349,27 @@ _yylex ()
     case CPP_WSTRING:
       return STRING;
       
-    case CPP_OSTRING:
-      return OBJC_STRING;
-
+      /* This token is Objective-C specific.  It gives the next
+	 token special significance.  */
+    case CPP_ATSIGN:
+ifobjc
+      last_token = c_lex (&yylval.ttype);
+      if (last_token == CPP_STRING)
+	return OBJC_STRING;
+      else if (last_token == CPP_NAME)
+	{
+	  int i;
+	  for (i = 0; i < N_at_reswords; i++)
+	    if (objc_rid_sans_at[i] == yylval.ttype)
+	      {
+		int rid_code = i + (int) RID_AT_ENCODE;
+		yylval.ttype = ridpointers[rid_code];
+		return rid_to_yy[rid_code];
+	      }
+	}
+      error ("syntax error at '@' token");
+      goto reconsider;
+end ifobjc
       /* These tokens are C++ specific (and will not be generated
          in C mode, but let's be cautious).  */
     case CPP_SCOPE:
@@ -3347,13 +3382,12 @@ _yylex ()
       /* These tokens should not survive translation phase 4.  */
     case CPP_HASH:
     case CPP_PASTE:
-      error ("syntax error before '%s' token", NAME(last_token));
-      goto retry;
+      error ("syntax error at '%s' token", NAME(last_token));
+      goto get_next;
 
     default:
       abort ();
     }
-
   /* NOTREACHED */
 }
 
===================================================================
Index: cpplex.c
--- cpplex.c	2001/03/04 12:02:01	1.134
+++ cpplex.c	2001/03/05 23:10:57
@@ -1241,29 +1241,8 @@ _cpp_lex_token (pfile, result)
     case '}': result->type = CPP_CLOSE_BRACE; break;
     case ';': result->type = CPP_SEMICOLON; break;
 
-    case '@':
-      if (CPP_OPTION (pfile, objc))
-	{
-	  /* In Objective C, '@' may begin keywords or strings, like
-	     @keyword or @"string".  It would be nice to call
-	     get_effective_char here and test the result.  However, we
-	     would then need to pass 2 characters to parse_identifier,
-	     making it ugly and slowing down its main loop.  Instead,
-	     we assume we have an identifier, and recover if not.  */
-	  result->type = CPP_NAME;
-	  result->val.node = parse_identifier (pfile, c);
-	  if (result->val.node->length != 1)
-	    break;
-
-	  /* OK, so it wasn't an identifier.  Maybe a string?  */
-	  if (buffer->read_ahead == '"')
-	    {
-	      c = '"';
-	      ACCEPT_CHAR (CPP_OSTRING);
-	      goto make_string;
-	    }
-	}
-      goto random_char;
+      /* @ is a punctuator in Objective C.  */
+    case '@': result->type = CPP_ATSIGN; break;
 
     random_char:
     default:
@@ -1341,7 +1320,6 @@ cpp_spell_token (pfile, token, buffer)
 	  {
 	  case CPP_STRING:	left = '"';  right = '"';  tag = '\0'; break;
 	  case CPP_WSTRING:	left = '"';  right = '"';  tag = 'L';  break;
-	  case CPP_OSTRING:	left = '"';  right = '"';  tag = '@';  break;
 	  case CPP_CHAR:	left = '\''; right = '\''; tag = '\0'; break;
     	  case CPP_WCHAR:	left = '\''; right = '\''; tag = 'L';  break;
 	  case CPP_HEADER_NAME:	left = '<';  right = '>';  tag = '\0'; break;
@@ -1432,7 +1410,6 @@ cpp_output_token (token, fp)
 	  {
 	  case CPP_STRING:	left = '"';  right = '"';  tag = '\0'; break;
 	  case CPP_WSTRING:	left = '"';  right = '"';  tag = 'L';  break;
-	  case CPP_OSTRING:	left = '"';  right = '"';  tag = '@';  break;
 	  case CPP_CHAR:	left = '\''; right = '\''; tag = '\0'; break;
     	  case CPP_WCHAR:	left = '\''; right = '\''; tag = 'L';  break;
 	  case CPP_HEADER_NAME:	left = '<';  right = '>';  tag = '\0'; break;
@@ -1579,13 +1556,6 @@ cpp_can_paste (pfile, token1, token2, di
 	  && VALID_SIGN ('+', token1->val.str.text[token1->val.str.len - 1]))
 	return CPP_NUMBER;
       break;
-
-    case CPP_OTHER:
-      if (CPP_OPTION (pfile, objc) && token1->val.c == '@')
-	{
-	  if (b == CPP_NAME)	return CPP_NAME;
-	  if (b == CPP_STRING)	return CPP_OSTRING;
-	}
 
     default:
       break;
===================================================================
Index: cpplib.h
--- cpplib.h	2001/03/04 12:02:02	1.168
+++ cpplib.h	2001/03/05 23:10:57
@@ -119,6 +119,7 @@ struct file_name_map_list;
   OP(CPP_SCOPE,		"::")			\
   OP(CPP_DEREF_STAR,	"->*")			\
   OP(CPP_DOT_STAR,	".*")			\
+  OP(CPP_ATSIGN,	"@")  /* used in Objective C */ \
 \
   TK(CPP_NAME,		SPELL_IDENT)	/* word */			\
   TK(CPP_INT,		SPELL_STRING)	/* 23 */			\
@@ -131,7 +132,6 @@ struct file_name_map_list;
 \
   TK(CPP_STRING,	SPELL_STRING)	/* "string" */			\
   TK(CPP_WSTRING,	SPELL_STRING)	/* L"string" */			\
-  TK(CPP_OSTRING,	SPELL_STRING)	/* @"string" - Objective C */	\
   TK(CPP_HEADER_NAME,	SPELL_STRING)	/* <stdio.h> in #include */	\
 \
   TK(CPP_COMMENT,	SPELL_STRING)	/* Only if output comments.  */ \
===================================================================
Index: cppmacro.c
--- cppmacro.c	2001/03/03 22:14:07	1.48
+++ cppmacro.c	2001/03/05 23:10:57
@@ -291,8 +291,7 @@ stringify_arg (pfile, arg)
       unsigned int len = cpp_token_len (token);
 
       escape_it = (token->type == CPP_STRING || token->type == CPP_WSTRING
-		   || token->type == CPP_CHAR || token->type == CPP_WCHAR
-		   || token->type == CPP_OSTRING);
+		   || token->type == CPP_CHAR || token->type == CPP_WCHAR);
 
       if (escape_it)
 	/* Worst case is each char is octal.  */
===================================================================
Index: testsuite/objc/execute/string3.m
--- testsuite/objc/execute/string3.m	Tue May  5 13:32:27 1998
+++ testsuite/objc/execute/string3.m	Mon Mar  5 15:10:57 2001
@@ -0,0 +1,12 @@
+#include <string.h>
+#include <stdlib.h>
+#include <objc/NXConstStr.h>
+
+#define STRING "this is a string"
+
+int main (int argc, void **args)
+{
+  if (strcmp ([@STRING cString], STRING))
+    abort ();
+  return 0;
+}


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]