/* Interface to LUCID Cadillac system for GNU compiler. Copyright (C) 1988, 1992, 1993 Free Software Foundation, Inc. This file is part of GNU CC. GNU CC is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNU CC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU CC; see the file COPYING. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "config.h" #include "tree.h" #include "flags.h" #include #include "cp-tree.h" #include "obstack.h" #ifdef CADILLAC #include #include #include #include #include #include #define obstack_chunk_alloc xmalloc #define obstack_chunk_free free void init_cadillac (); extern char *input_filename; extern int lineno; /* Put random information we might want to get back from Cadillac here. */ typedef struct { /* The connection to the Cadillac kernel. */ Connection *conn; /* Input and output file descriptors for Cadillac. */ short fd_input, fd_output; /* #include nesting of current file. */ short depth; /* State variables for the connection. */ char messages; char conversion; char emission; char process_until; /* #if level of current file. */ int iflevel; /* Line number that starts current source file. */ int lineno; /* Name of current file. */ char *filename; /* Where to stop processing (if process_until is set). */ char *end_filename; int end_position; } cadillac_struct; static cadillac_struct cadillacObj; /* Nonzero if in the process of exiting. */ static int exiting; void cadillac_note_source (); static void CWriteLanguageDecl (); static void CWriteLanguageType (); static void CWriteTopLevel (); static void cadillac_note_filepos (); static void cadillac_process_request (), cadillac_process_requests (); static void cadillac_switch_source (); static void exit_cadillac (); /* Blocking test. */ static int readable_p (fd) int fd; { fd_set f; FD_ZERO (&f); FD_SET (fd, &f); return select (32, &f, NULL, NULL, 0) == 1; } static CObjectType *tree_to_cadillac_map; struct obstack cadillac_obstack; #include "stack.h" struct context_level { struct stack_level base; tree context; }; /* Stack for maintaining contexts (in case functions or types are nested). When defining a struct type, the `context' field is the RECORD_TYPE. When defining a function, the `context' field is the FUNCTION_DECL. */ static struct context_level *context_stack; static struct context_level * push_context_level (stack, obstack) struct stack_level *stack; struct obstack *obstack; { struct context_level tem; tem.base.prev = stack; return (struct context_level *)push_stack_level (obstack, &tem, sizeof (tem)); } /* Discard a level of search allocation. */ static struct context_level * pop_context_level (stack) struct context_level *stack; { stack = (struct context_level *)pop_stack_level (stack); return stack; } void init_cadillac () { extern FILE *finput; extern int errno; CCompilerMessage* req; cadillac_struct *cp = &cadillacObj; int i; if (! flag_cadillac) return; tree_to_cadillac_map = (CObjectType*) xmalloc (sizeof (CObjectType) * LAST_CPLUS_TREE_CODE); for (i = 0; i < LAST_CPLUS_TREE_CODE; i++) tree_to_cadillac_map[i] = MiscOType; tree_to_cadillac_map[RECORD_TYPE] = StructOType; tree_to_cadillac_map[UNION_TYPE] = UnionOType; tree_to_cadillac_map[ENUMERAL_TYPE] = EnumTypeOType; tree_to_cadillac_map[TYPE_DECL] = TypedefOType; tree_to_cadillac_map[VAR_DECL] = VariableOType; tree_to_cadillac_map[CONST_DECL] = EnumConstantOType; tree_to_cadillac_map[FUNCTION_DECL] = FunctionOType; tree_to_cadillac_map[FIELD_DECL] = FieldOType; #ifdef sun on_exit (&exit_cadillac, 0); #endif gcc_obstack_init (&cadillac_obstack); /* Yow! This is the way Cadillac was designed to deal with Oregon C++ compiler! */ cp->fd_input = flag_cadillac; cp->fd_output = flag_cadillac; /* Start in "turned-on" state. */ cp->messages = 1; cp->conversion = 1; cp->emission = 1; /* Establish a connection with Cadillac here. */ cp->conn = NewConnection (cp, cp->fd_input, cp->fd_output); CWriteHeader (cp->conn, WaitingMType, 0); CWriteRequestBuffer (cp->conn); if (!readable_p (cp->fd_input)) ; req = CReadCompilerMessage (cp->conn); if (!req) switch (errno) { case EWOULDBLOCK: sleep (5); return; case 0: fatal ("init_cadillac: EOF on connection to kernel, exiting\n"); break; default: perror ("Editor to kernel connection"); exit (0); } } static void cadillac_process_requests (conn) Connection *conn; { CCompilerMessage *req; while (req = (CCompilerMessage*) CPeekNextRequest (conn)) { req = CReadCompilerMessage (conn); cadillac_process_request (&cadillacObj, req); } } static void cadillac_process_request (cp, req) cadillac_struct *cp; CCompilerMessage *req; { if (! req) return; switch (req->reqType) { case ProcessUntilMType: if (cp->process_until) my_friendly_abort (23); cp->process_until = 1; /* This is not really right. */ cp->end_position = ((CCompilerCommand*)req)->processuntil.position; #if 0 cp->end_filename = req->processuntil.filename; #endif break; case CommandMType: switch (req->header.data) { case MessagesOnCType: cp->messages = 1; break; case MessagesOffCType: cp->messages = 0; break; case ConversionOnCType: cp->conversion = 1; break; case ConversionOffCType: cp->conversion = 0; break; case EmissionOnCType: cp->emission = 1; break; case EmissionOffCType: cp->emission = 0; break; case FinishAnalysisCType: return; case PuntAnalysisCType: case ContinueAnalysisCType: case GotoFileposCType: case OpenSucceededCType: case OpenFailedCType: fprintf (stderr, "request type %d not implemented\n", req->reqType); return; case DieCType: if (! exiting) my_friendly_abort (24); return; } break; default: fatal ("unknown request type %d", req->reqType); } } void cadillac_start () { Connection *conn = cadillacObj.conn; CCompilerMessage *req; /* Let Cadillac know that we start in C++ language scope. */ CWriteHeader (conn, ForeignLinkageMType, LinkCPlus); CWriteLength (conn); CWriteRequestBuffer (conn); cadillac_process_requests (conn); } static void cadillac_printf (msg, name) { if (cadillacObj.messages) printf ("[%s,%4d] %s `%s'\n", input_filename, lineno, msg, name); } void cadillac_start_decl (decl) tree decl; { Connection *conn = cadillacObj.conn; CObjectType object_type = tree_to_cadillac_map [TREE_CODE (decl)]; if (context_stack) switch (TREE_CODE (context_stack->context)) { case FUNCTION_DECL: /* Currently, cadillac only implements top-level forms. */ return; case RECORD_TYPE: case UNION_TYPE: cadillac_printf ("start class-level decl", IDENTIFIER_POINTER (DECL_NAME (decl))); break; default: my_friendly_abort (25); } else { cadillac_printf ("start top-level decl", IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl))); CWriteTopLevel (conn, StartMType); } CWriteLanguageDecl (conn, decl, tree_to_cadillac_map[TREE_CODE (decl)]); CWriteRequestBuffer (conn); cadillac_process_requests (conn); } void cadillac_finish_decl (decl) tree decl; { Connection *conn = cadillacObj.conn; if (context_stack) switch (TREE_CODE (context_stack->context)) { case FUNCTION_DECL: return; case RECORD_TYPE: case UNION_TYPE: cadillac_printf ("end class-level decl", IDENTIFIER_POINTER (DECL_NAME (decl))); CWriteHeader (conn, EndDefMType, 0); CWriteLength (conn); break; default: my_friendly_abort (26); } else { cadillac_printf ("end top-level decl", IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl))); CWriteHeader (conn, EndDefMType, 0); CWriteLength (conn); CWriteTopLevel (conn, StopMType); } CWriteRequestBuffer (conn); cadillac_process_requests (conn); } void cadillac_start_function (fndecl) tree fndecl; { Connection *conn = cadillacObj.conn; if (context_stack) /* nested functions not yet handled. */ my_friendly_abort (27); cadillac_printf ("start top-level function", lang_printable_name (fndecl)); context_stack = push_context_level (context_stack, &cadillac_obstack); context_stack->context = fndecl; CWriteTopLevel (conn, StartMType); my_friendly_assert (TREE_CODE (fndecl) == FUNCTION_DECL, 202); CWriteLanguageDecl (conn, fndecl, (TREE_CODE (TREE_TYPE (fndecl)) == METHOD_TYPE ? MemberFnOType : FunctionOType)); CWriteRequestBuffer (conn); cadillac_process_requests (conn); } void cadillac_finish_function (fndecl) tree fndecl; { Connection *conn = cadillacObj.conn; cadillac_printf ("end top-level function", lang_printable_name (fndecl)); context_stack = pop_context_level (context_stack); if (context_stack) /* nested functions not yet implemented. */ my_friendly_abort (28); CWriteHeader (conn, EndDefMType, 0); CWriteLength (conn); CWriteTopLevel (conn, StopMType); CWriteRequestBuffer (conn); cadillac_process_requests (conn); } void cadillac_finish_anon_union (decl) tree decl; { Connection *conn = cadillacObj.conn; if (! global_bindings_p ()) return; cadillac_printf ("finish top-level anon union", ""); CWriteHeader (conn, EndDefMType, 0); CWriteLength (conn); CWriteTopLevel (conn, StopMType); CWriteRequestBuffer (conn); cadillac_process_requests (conn); } void cadillac_start_enum (type) tree type; { Connection *conn = cadillacObj.conn; tree name = TYPE_NAME (type); if (TREE_CODE (name) == TYPE_DECL) name = DECL_NAME (name); if (context_stack) switch (TREE_CODE (context_stack->context)) { case FUNCTION_DECL: return; case RECORD_TYPE: case UNION_TYPE: break; default: my_friendly_abort (29); } else { cadillac_printf ("start top-level enum", IDENTIFIER_POINTER (name)); CWriteTopLevel (conn, StartMType); } CWriteLanguageType (conn, type, tree_to_cadillac_map[ENUMERAL_TYPE]); } void cadillac_finish_enum (type) tree type; { Connection *conn = cadillacObj.conn; tree name = TYPE_NAME (type); if (TREE_CODE (name) == TYPE_DECL) name = DECL_NAME (name); if (context_stack) switch (TREE_CODE (context_stack->context)) { case FUNCTION_DECL: return; case RECORD_TYPE: case UNION_TYPE: CWriteHeader (conn, EndDefMType, 0); CWriteLength (conn); break; default: my_friendly_abort (30); } else { CWriteHeader (conn, EndDefMType, 0); CWriteLength (conn); cadillac_printf ("finish top-level enum", IDENTIFIER_POINTER (name)); CWriteTopLevel (conn, StopMType); } CWriteRequestBuffer (conn); cadillac_process_requests (conn); } void cadillac_start_struct (type) tree type; { Connection *conn = cadillacObj.conn; tree name = TYPE_NAME (type); if (TREE_CODE (name) == TYPE_DECL) name = DECL_NAME (name); if (context_stack) switch (TREE_CODE (context_stack->context)) { case FUNCTION_DECL: return; case RECORD_TYPE: case UNION_TYPE: return; default: my_friendly_abort (31); } else { cadillac_printf ("start struct", IDENTIFIER_POINTER (name)); CWriteTopLevel (conn, StartMType); } context_stack = push_context_level (context_stack, &cadillac_obstack); context_stack->context = type; CWriteLanguageType (conn, type, TYPE_LANG_SPECIFIC (type) && CLASSTYPE_DECLARED_CLASS (type) ? ClassOType : tree_to_cadillac_map[TREE_CODE (type)]); } void cadillac_finish_struct (type) tree type; { Connection *conn = cadillacObj.conn; tree name = TYPE_NAME (type); if (TREE_CODE (name) == TYPE_DECL) name = DECL_NAME (name); context_stack = pop_context_level (context_stack); if (context_stack) return; cadillac_printf ("finish struct", IDENTIFIER_POINTER (name)); CWriteHeader (conn, EndDefMType, 0); CWriteLength (conn); CWriteTopLevel (conn, StopMType); CWriteRequestBuffer (conn); cadillac_process_requests (conn); } void cadillac_finish_exception (type) tree type; { Connection *conn = cadillacObj.conn; fatal ("cadillac_finish_exception"); CWriteHeader (conn, EndDefMType, 0); CWriteLength (conn); CWriteTopLevel (conn, StopMType); CWriteRequestBuffer (conn); cadillac_process_requests (conn); } void cadillac_push_class (type) tree type; { } void cadillac_pop_class () { } void cadillac_push_lang (name) tree name; { Connection *conn = cadillacObj.conn; CLinkLanguageType m; if (name == lang_name_cplusplus) m = LinkCPlus; else if (name == lang_name_c) m = LinkC; else my_friendly_abort (32); CWriteHeader (conn, ForeignLinkageMType, m); CWriteRequestBuffer (conn); cadillac_process_requests (conn); } void cadillac_pop_lang () { Connection *conn = cadillacObj.conn; CWriteHeader (conn, ForeignLinkageMType, LinkPop); CWriteRequestBuffer (conn); cadillac_process_requests (conn); } void cadillac_finish_stmt () { } void cadillac_note_source () { cadillacObj.lineno = lineno; cadillacObj.filename = input_filename; } static void CWriteTopLevel (conn, m) Connection *conn; CMessageSubType m; { static context_id = 0; CWriteHeader (conn, TopLevelFormMType, m); cadillac_note_filepos (); /* Eventually, this will point somewhere into the digest file. */ context_id += 1; CWriteSomething (conn, &context_id, sizeof (BITS32)); CWriteSomething (conn, &cadillacObj.iflevel, sizeof (BITS32)); CWriteLength (conn); } static void cadillac_note_filepos () { extern FILE *finput; int pos = ftell (finput); CWriteSomething (cadillacObj.conn, &pos, sizeof (BITS32)); } void cadillac_switch_source (startflag) int startflag; { Connection *conn = cadillacObj.conn; /* Send out the name of the source file being compiled. */ CWriteHeader (conn, SourceFileMType, startflag ? StartMType : StopMType); CWriteSomething (conn, &cadillacObj.depth, sizeof (BITS16)); CWriteVstring0 (conn, input_filename); CWriteLength (conn); CWriteRequestBuffer (conn); cadillac_process_requests (conn); } void cadillac_push_source () { cadillacObj.depth += 1; cadillac_switch_source (1); } void cadillac_pop_source () { cadillacObj.depth -= 1; cadillac_switch_source (0); } struct cadillac_mdep { short object_type; char linkage; char access; short length; }; static void CWriteLanguageElem (conn, p, name) Connection *conn; struct cadillac_mdep *p; char *name; { CWriteSomething (conn, &p->object_type, sizeof (BITS16)); CWriteSomething (conn, &p->linkage, sizeof (BITS8)); CWriteSomething (conn, &p->access, sizeof (BITS8)); CWriteSomething (conn, &p->length, sizeof (BITS16)); CWriteVstring0 (conn, name); #if 0 /* Don't write date_type. */ CWriteVstring0 (conn, ""); #endif CWriteLength (conn); } static void CWriteLanguageDecl (conn, decl, object_type) Connection *conn; tree decl; CObjectType object_type; { struct cadillac_mdep foo; tree name; CWriteHeader (conn, LanguageElementMType, StartDefineMType); foo.object_type = object_type; if (decl_type_context (decl)) { foo.linkage = ParentLinkage; if (TREE_PRIVATE (decl)) foo.access = PrivateAccess; else if (TREE_PROTECTED (decl)) foo.access = ProtectedAccess; else foo.access = PublicAccess; } else { if (TREE_PUBLIC (decl)) foo.linkage = GlobalLinkage; else foo.linkage = FileLinkage; foo.access = PublicAccess; } name = DECL_NAME (decl); foo.length = IDENTIFIER_LENGTH (name); CWriteLanguageElem (conn, &foo, IDENTIFIER_POINTER (name)); CWriteRequestBuffer (conn); cadillac_process_requests (conn); } static void CWriteLanguageType (conn, type, object_type) Connection *conn; tree type; CObjectType object_type; { struct cadillac_mdep foo; tree name = TYPE_NAME (type); CWriteHeader (conn, LanguageElementMType, StartDefineMType); foo.object_type = object_type; if (current_class_type) { foo.linkage = ParentLinkage; if (TREE_PRIVATE (type)) foo.access = PrivateAccess; else if (TREE_PROTECTED (type)) foo.access = ProtectedAccess; else foo.access = PublicAccess; } else { foo.linkage = NoLinkage; foo.access = PublicAccess; } if (TREE_CODE (name) == TYPE_DECL) name = DECL_NAME (name); foo.length = IDENTIFIER_LENGTH (name); CWriteLanguageElem (conn, &foo, IDENTIFIER_POINTER (name)); CWriteRequestBuffer (conn); cadillac_process_requests (conn); } static void CWriteUseObject (conn, type, object_type, use) Connection *conn; tree type; CObjectType object_type; CMessageSubType use; { struct cadillac_mdep foo; tree name = NULL_TREE; CWriteHeader (conn, LanguageElementMType, use); foo.object_type = object_type; if (current_class_type) { foo.linkage = ParentLinkage; if (TREE_PRIVATE (type)) foo.access = PrivateAccess; else if (TREE_PROTECTED (type)) foo.access = ProtectedAccess; else foo.access = PublicAccess; } else { foo.linkage = NoLinkage; foo.access = PublicAccess; } switch (TREE_CODE (type)) { case VAR_DECL: case FIELD_DECL: case TYPE_DECL: case CONST_DECL: case FUNCTION_DECL: name = DECL_NAME (type); break; default: my_friendly_abort (33); } foo.length = IDENTIFIER_LENGTH (name); CWriteLanguageElem (conn, &foo, IDENTIFIER_POINTER (name)); CWriteRequestBuffer (conn); cadillac_process_requests (conn); } /* Here's how we exit under cadillac. */ static void exit_cadillac () { extern int errorcount; Connection *conn = cadillacObj.conn; if (flag_cadillac) { CCompilerMessage *req; CWriteHeader (conn, FinishedMType, errorcount ? 0 : CsObjectWritten | CsComplete); /* Bye, bye! */ CWriteRequestBuffer (conn); /* Block on read. */ while (! readable_p (cadillacObj.fd_input)) { if (exiting) my_friendly_abort (34); exiting = 1; } exiting = 1; req = CReadCompilerMessage (conn); cadillac_process_request (&cadillacObj, req); } } #else /* Stubs. */ void init_cadillac () {} void cadillac_start () {} void cadillac_start_decl (decl) tree decl; {} void cadillac_finish_decl (decl) tree decl; {} void cadillac_start_function (fndecl) tree fndecl; {} void cadillac_finish_function (fndecl) tree fndecl; {} void cadillac_finish_anon_union (decl) tree decl; {} void cadillac_start_enum (type) tree type; {} void cadillac_finish_enum (type) tree type; {} void cadillac_start_struct (type) tree type; {} void cadillac_finish_struct (type) tree type; {} void cadillac_finish_exception (type) tree type; {} void cadillac_push_class (type) tree type; {} void cadillac_pop_class () {} void cadillac_push_lang (name) tree name; {} void cadillac_pop_lang () {} void cadillac_note_source () {} void cadillac_finish_stmt () {} void cadillac_switch_source () {} void cadillac_push_source () {} void cadillac_pop_source () {} #endif