cdk@neptune.dsc.com (Colin Kelley) (06/19/91)
Here's the source code to a tool for extracting inline function definitions. I'm placing it under the Gnu GPL. Can someone please make it available for FTP? I don't have direct internet access, but I'd like to make it available for those who do. -Colin Kelley, Digital Sound Corporation cdk%neptune%dschub@hub.ucsb.edu ...!pyramid!ucsbcsl!dschub!neptune!cdk (805) 566-3000 x3175 --------------------------------------------------------------------------- #! /bin/sh # This is a shell archive, meaning: # 1. Remove everything above the #! /bin/sh line. # 2. Save the resulting text in a file. # 3. Execute the file with /bin/sh (not csh) to create the files: # README # Makefile # extract-inline.cc # event.h # comment.h # ident.h # keyword.h # inline.h # event.cc # comment.cc # ident.cc # keyword.cc # inline.cc # move-if-change # This archive created: Tue Jun 18 10:05:41 1991 export PATH; PATH=/bin:$PATH if test -f 'README' then echo shar: will not over-write existing file "'README'" else cat << \SHAR_EOF > 'README' This code is covered under the Gnu General Public License, version 1. This is a set of C++ classes for scanning C++. The application provided here is a C++ inline extractor. It takes a single code file, with inline and non-inline functions intermingled, and splits it into two files, one with the inline functions, the other with the remainder. The recommended usage for a hypothetical module called `module', is: - keep the module class definitions in `module.h' - add one line to the end of `module.h': #include "module-inline.h" - place all the code, both inline and not, in `module.code' - put this in your Makefile: module-inline.h module.cc: module.code extract-inline module.code module-inline.tmp module.cc move-if-change module-inline.tmp module-inline.h These classes are useful for other C++ tools as well, such as formatting documentation. -Colin Kelley, June 1991 Digital Sound Corporation cdk%neptune%dschub@hub.ucsb.edu ...!pyramid!ucsbcsl!dschub!neptune!cdk (805) 566-3000 x3175 SHAR_EOF fi # end of overwriting check if test -f 'Makefile' then echo shar: will not over-write existing file "'Makefile'" else cat << \SHAR_EOF > 'Makefile' CC = g++ CFLAGS = -Wall -I/usr/local/lib/g++-include -g OBJS = event.o comment.o ident.o keyword.o inline.o SRC = README Makefile extract-inline.cc \ event.h comment.h ident.h keyword.h inline.h \ event.cc comment.cc ident.cc keyword.cc inline.cc \ move-if-change RESULTS = extract-inline RESULTOBJS = extract-inline.o all: $(RESULTS) clean: rm -f $(OBJS) $(RESULTOBJS) $(RESULTS) cleanly: clean all ######################################################################## extract-inline: extract-inline.o $(OBJS) $(CC) $(CFLAGS) -o extract-inline extract-inline.o $(OBJS) extract-inline.o: extract-inline.cc $(CC) $(CFLAGS) -c extract-inline.cc extract-inline.cc: event.h comment.h ident.h keyword.h inline.h touch extract-inline.cc ######################################################################## event.o: event.cc $(CC) $(CFLAGS) -c event.cc event.cc: event.h touch event.cc event.h: touch event.h #---------------------------------------------------------------------- comment.o: comment.cc $(CC) $(CFLAGS) -c comment.cc comment.cc: comment.h touch comment.cc comment.h: event.h touch comment.h #---------------------------------------------------------------------- ident.o: ident.cc $(CC) $(CFLAGS) -c ident.cc ident.cc: ident.h touch ident.cc ident.h: event.h touch ident.h #---------------------------------------------------------------------- keyword.o: keyword.cc $(CC) $(CFLAGS) -c keyword.cc keyword.cc: keyword.h touch keyword.cc keyword.h: event.h ident.h touch keyword.h #---------------------------------------------------------------------- inline.o: inline.cc $(CC) $(CFLAGS) -c inline.cc inline.cc: inline.h touch inline.cc inline.h: event.h keyword.h touch inline.h ######################################################################## shar: extract-inline.shar extract-inline.shar: $(SRC) shar $(SRC) > extract-inline.tmp move-if-change extract-inline.tmp extract-inline.shar SHAR_EOF fi # end of overwriting check if test -f 'extract-inline.cc' then echo shar: will not over-write existing file "'extract-inline.cc'" else cat << \SHAR_EOF > 'extract-inline.cc' /* * This code is covered under the Gnu General Public License, version 1. * Colin Kelley, June 1991 */ /* * This is the main program for the inline extractor. It pipelines state * machines to simulate C++ scanning: * * comment | ident | keyword | inline */ #include "event.h" #include "comment.h" #include "ident.h" #include "keyword.h" #include "inline.h" extern "C" void perror( const char* ); static void usage() { fprintf( stderr, "usage: extract-inline source-file inline-file remain-file\n" " reads from <source-file>, writing all inline functions to\n" " <inline-file>, with the remainder passed through to <remain-file>.\n"); } int __main() { return 0; } int main( int argc, char* argv[] ) { if (argc != 4) { usage(); exit( 1 ); } const char* srcFileName = argv[1]; const char* inlineFileName = argv[2]; const char* remainFileName = argv[3]; FILE* srcFile = fopen( srcFileName, "r" ); if (!srcFile) { perror( srcFileName ); exit( 1 ); } FILE* inlineFile = fopen( inlineFileName, "w" ); if (!inlineFile) { perror( inlineFileName ); exit( 1 ); } FILE* remainFile = fopen( remainFileName, "w" ); if (!remainFile) { perror( remainFileName ); exit( 1 ); } fprintf( inlineFile, "/*\n" " * WARNING\n" " * Don't change this file! It was machine-generated from `%s'.\n" " */\n", srcFileName ); fprintf( inlineFile, "#line 1 \"%s\"\n", srcFileName ); fprintf( remainFile, "/*\n" " * WARNING\n" " * Don't change this file! It was machine-generated from `%s'.\n" " */\n", srcFileName ); fprintf( remainFile, "#line 1 \"%s\"\n", srcFileName ); OutputEvent outputRemainEvent( remainFile ); OutputEvent outputInlineEvent( inlineFile ); ExtractInlineFSM extractInlineFSM( &outputRemainEvent, &outputInlineEvent ); KeywordFSM keywordFSM( &extractInlineFSM ); IdentNumberFSM identNumberFSM( &keywordFSM ); CommentQuotedFSM commentQuotedFSM( &identNumberFSM ); Event *event; while ((event = NextEvent( srcFile )) != NULL) { commentQuotedFSM.Inject( event ); } } SHAR_EOF fi # end of overwriting check if test -f 'event.h' then echo shar: will not over-write existing file "'event.h'" else cat << \SHAR_EOF > 'event.h' /* * This code is covered under the Gnu General Public License, version 1. * Colin Kelley, June 1991 */ #pragma once /* * This module has the basic declarations which form the foundation for * pipelined state machines which scan C and C++ code. It defines the * abstract Event, EventSink, and FSM (Finite State Machine) classes which * are used throughout. It also defines classes for all the common character * types. Note that in order to be able to ask an object its type, the * Event class must define an enum with all event types in it. This obviously * impedes the reusability of the class, since this essentially amounts to * the class knowing all types which will subtype it. Welcome to C++. */ extern "C" { #include <stdio.h> } typedef int Boolean; #define TRUE 1 #define FALSE 0 extern "C" char* malloc( unsigned int size ); extern "C" char* realloc( char* buffer, unsigned int newSize ); extern "C" void free( char* buffer ); class CharAccumulator { public: inline CharAccumulator() { cursor = 0; size = AllocSize; buffer = malloc( size ); } inline ~CharAccumulator() { free( buffer ); } inline void AddChar( char toAdd ); inline const char* AccumulatorBuffer() const { // make sure it's NUL-terminated buffer[cursor] = '\0'; // return buffer pointer return buffer; } private: const int AllocSize = 500; inline void ExpandSize() { size += AllocSize; buffer = realloc( buffer, size ); } char* buffer; int cursor; int size; }; inline void CharAccumulator::AddChar( char toAdd ) { // make sure there's always room for terminating NUL if (cursor + 1 >= size) { ExpandSize(); } // add character buffer[cursor] = toAdd; // move cursor cursor++; } class Event { public: enum EventType { // primitive characters of interest Space, Tab, Pound, Star, Slash, BackSlash, NewLine, SingleQuote, DoubleQuote, LeftParen, RightParen, LeftBrace, RightBrace, LeftBracket, RightBracket, Character, // higher-level events EscapedNewLine, WhiteSpace, Indent, Comment, CplusComment, InterfaceCommand, ImplementationCommand, FunctionCommand, QuotedCharacter, QuotedString, Ident, Number, Keyword, LineDirective, BlockBegin, BlockEnd, Header, }; Event() { startingRow = 0; startingColumn = 0; next = 0; } Event( int r, int c ) { startingRow = r; startingColumn = c; next = 0; } virtual ~Event(); virtual void Output( FILE* outFile, int deltaIndent ) const = 0; virtual EventType ThisEventCode() const = 0; virtual Boolean IsCharEvent() const = 0; inline int StartingRow() const { return startingRow; } inline int StartingColumn() const { return startingColumn; } inline Link( Event* nextEvent ) { next = nextEvent; } inline Event* Next() const { return next; } private: int startingRow; int startingColumn; Event* next; }; class EventSink { public: EventSink() { } ~EventSink() { } void virtual Inject( Event* event ) = 0; private: char dummy; // some stupid compilers complain if there are no members }; class OutputEvent : public EventSink { public: OutputEvent( FILE* f ) { outFile = f; } ~OutputEvent() { fflush( outFile ); } void Inject( Event* event ); private: FILE* outFile; }; class EventList { public: EventList() { head = tail = NULL; } ~EventList() { for (Event* event = head; event != NULL; ) { Event* next = event->Next(); delete event; event = next; } head = tail = NULL; } void EmitList( EventSink* sink ) { for (Event* event = head; event != NULL; ) { Event* next = event->Next(); sink->Inject( event ); // this will delete event event = next; } head = tail = NULL; } void AddToEnd( Event* newEvent ) { if (tail) { tail->Link( newEvent ); tail = newEvent; } else { head = tail = newEvent; } } int StartingRow() const { if (!head) { return 0; } else { return head->StartingRow(); } } int StartingColumn() const { if (!head) { return 0; } else { return head->StartingColumn(); } } private: Event* head; Event* tail; }; class FSM : public EventSink { public: FSM( EventSink* eventSink ) { nextEventSink = eventSink; } ~FSM() { } protected: void Emit( Event* event ) { nextEventSink->Inject( event ); } private: EventSink* nextEventSink; }; class CharEvent : public Event { public: CharEvent() { } CharEvent( int r, int c ) : Event( r, c ) { } ~CharEvent(); void Output( FILE* outFile, int deltaIndent ) const = 0; virtual EventType ThisEventCode() const = 0; Boolean IsCharEvent() const; virtual char ThisChar() const = 0; private: }; class NonCharEvent : public Event { public: NonCharEvent() { } NonCharEvent( int r, int c ) : Event( r, c ) { } ~NonCharEvent(); void Output( FILE* outFile, int deltaIndent ) const = 0; virtual EventType ThisEventCode() const = 0; Boolean IsCharEvent() const; private: }; class AccumulatorEvent : public NonCharEvent { public: AccumulatorEvent( int r, int c ) : NonCharEvent( r, c ) { accumulator.CharAccumulator(); } ~AccumulatorEvent(); inline void AddChar( char toAdd ) { accumulator.AddChar( toAdd ); } inline const char* AccumulatorBuffer() const { return accumulator.AccumulatorBuffer(); } void Output( FILE* outFile, int deltaIndent ) const; protected: CharAccumulator accumulator; private: int virtual OutputFirstLine( FILE* outFile, const char* buffer ) const; void virtual OutputRemainingLines( FILE* outFile, const char* remaining, int deltaIndent ) const; void virtual OutputHeader( FILE* outFile ) const = 0; void virtual OutputTrailer( FILE* outFile ) const = 0; }; class SpaceEvent : public CharEvent { public: SpaceEvent( int r, int c ) : CharEvent( r, c ) { } ~SpaceEvent(); void Output( FILE* outFile, int indent ) const; EventType ThisEventCode() const; char ThisChar() const; private: }; class TabEvent : public CharEvent { public: TabEvent( int r, int c ) : CharEvent( r, c ) { } ~TabEvent(); void Output( FILE* outFile, int indent ) const; EventType ThisEventCode() const; char ThisChar() const; int NumberOfSpaces() { return 8 - (unsigned(StartingColumn()) % 8); } private: }; class PoundEvent : public CharEvent { public: PoundEvent( int r, int c ) : CharEvent( r, c ) { } ~PoundEvent(); void Output( FILE* outFile, int indent ) const; EventType ThisEventCode() const; char ThisChar() const; private: }; class StarEvent : public CharEvent { public: StarEvent( int r, int c ) : CharEvent( r, c ) { } ~StarEvent(); void Output( FILE* outFile, int indent ) const; EventType ThisEventCode() const; char ThisChar() const; private: }; class SlashEvent : public CharEvent { public: SlashEvent( int r, int c ) : CharEvent( r, c ) { } ~SlashEvent(); void Output( FILE* outFile, int indent ) const; EventType ThisEventCode() const; char ThisChar() const; private: }; class BackSlashEvent : public CharEvent { public: BackSlashEvent( int r, int c ) : CharEvent( r, c ) { } ~BackSlashEvent(); void Output( FILE* outFile, int indent ) const; EventType ThisEventCode() const; char ThisChar() const; private: }; class NewLineEvent : public CharEvent { public: NewLineEvent( int r, int c ) : CharEvent( r, c ) { } ~NewLineEvent(); void Output( FILE* outFile, int indent ) const; EventType ThisEventCode() const; char ThisChar() const; private: }; class SingleQuoteEvent : public CharEvent { public: SingleQuoteEvent( int r, int c ) : CharEvent( r, c ) { } ~SingleQuoteEvent(); void Output( FILE* outFile, int indent ) const; EventType ThisEventCode() const; char ThisChar() const; private: }; class DoubleQuoteEvent : public CharEvent { public: DoubleQuoteEvent( int r, int c ) : CharEvent( r, c ) { } ~DoubleQuoteEvent(); void Output( FILE* outFile, int indent ) const; EventType ThisEventCode() const; char ThisChar() const; private: }; class MatchingEvent : public CharEvent { public: MatchingEvent( int r, int c ) : CharEvent( r, c ) { level = 0; } ~MatchingEvent(); int level; private: }; class LeftParenEvent : public MatchingEvent { public: LeftParenEvent( int r, int c ) : MatchingEvent( r, c ) { } ~LeftParenEvent(); void Output( FILE* outFile, int indent ) const; EventType ThisEventCode() const; char ThisChar() const; private: }; class RightParenEvent : public MatchingEvent { public: RightParenEvent( int r, int c ) : MatchingEvent( r, c ) { } ~RightParenEvent(); void Output( FILE* outFile, int indent ) const; EventType ThisEventCode() const; char ThisChar() const; private: }; class LeftBraceEvent : public MatchingEvent { public: LeftBraceEvent( int r, int c ) : MatchingEvent( r, c ) { } ~LeftBraceEvent(); void Output( FILE* outFile, int indent ) const; EventType ThisEventCode() const; char ThisChar() const; private: }; class RightBraceEvent : public MatchingEvent { public: RightBraceEvent( int r, int c ) : MatchingEvent( r, c ) { } ~RightBraceEvent(); void Output( FILE* outFile, int indent ) const; EventType ThisEventCode() const; char ThisChar() const; private: }; class LeftBracketEvent : public MatchingEvent { public: LeftBracketEvent( int r, int c ) : MatchingEvent( r, c ) { } ~LeftBracketEvent(); void Output( FILE* outFile, int indent ) const; EventType ThisEventCode() const; char ThisChar() const; private: }; class RightBracketEvent : public MatchingEvent { public: RightBracketEvent( int r, int c ) : MatchingEvent( r, c ) { level = 0; } ~RightBracketEvent(); void Output( FILE* outFile, int indent ) const; EventType ThisEventCode() const; char ThisChar() const; private: }; class LineDirectiveEvent : public NonCharEvent { public: LineDirectiveEvent( int r, int c ) : NonCharEvent( r, c ) { } ~LineDirectiveEvent(); void Output( FILE* outFile, int indent ) const; EventType ThisEventCode() const; char ThisChar() const; private: }; class CharacterEvent : public CharEvent { public: CharacterEvent( int r, int c, char ch ) : CharEvent( r, c ) { thisChar = ch; } ~CharacterEvent(); void Output( FILE* outFile, int indent ) const; EventType ThisEventCode() const; char ThisChar() const; private: char thisChar; }; Event* NextEvent( FILE* inFile ); SHAR_EOF fi # end of overwriting check if test -f 'comment.h' then echo shar: will not over-write existing file "'comment.h'" else cat << \SHAR_EOF > 'comment.h' /* * This code is covered under the Gnu General Public License, version 1. * Colin Kelley, June 1991 */ #pragma once /* * This state machine extracts comments, both C and C++ style, and quoted * characters and strings, from a character event stream. It introduces * the following event types: * CommentEvent * CplusCommentEvent * QuotedCharacterEvent * QuotedStringEvent */ #include "event.h" class CommentEvent : public AccumulatorEvent { public: inline CommentEvent( int r, int s ) : AccumulatorEvent( r, s ) { } ~CommentEvent(); EventType ThisEventCode() const; private: void OutputRemainingLines( FILE* outFile, const char* remaining, int deltaIndent ) const; void OutputHeader( FILE* outFile ) const; void OutputTrailer( FILE* outFile ) const; }; class CplusCommentEvent : public CommentEvent { public: inline CplusCommentEvent( int r, int s ) : CommentEvent( r, s ) { } ~CplusCommentEvent(); EventType ThisEventCode() const; private: void OutputHeader( FILE* outFile ) const; void OutputTrailer( FILE* outFile ) const; }; class QuotedEvent : public AccumulatorEvent { public: inline QuotedEvent( int r, int s ) : AccumulatorEvent( r, s ) { } private: }; class QuotedCharacterEvent : public QuotedEvent { public: inline QuotedCharacterEvent( int r, int s ) : QuotedEvent( r, s ) { } inline ~QuotedCharacterEvent() { } EventType ThisEventCode() const; private: void OutputHeader( FILE* outFile ) const; void OutputTrailer( FILE* outFile ) const; }; class QuotedStringEvent : public QuotedEvent { public: inline QuotedStringEvent( int r, int s ) : QuotedEvent( r, s ) { } inline ~QuotedStringEvent() { } EventType ThisEventCode() const; private: void OutputHeader( FILE* outFile ) const; void OutputTrailer( FILE* outFile ) const; }; class CommentQuotedFSM : public FSM { public: CommentQuotedFSM( EventSink* eventSink ) : FSM( eventSink ) { state = StartState; comment = NULL; quoted = NULL; } ~CommentQuotedFSM() { if (comment) { delete comment; } if (quoted) { delete quoted; } } void Inject( Event* event ); private: void AddCommentChar( char c ); void AddQuotedChar( char c ) { quoted->AddChar( c ); } EventType quoteCode; CommentEvent* comment; QuotedEvent* quoted; enum CommentQuotedState { // comment states WaitForCommentOrQuote, WaitForStartStarOrSlash, SavingCplusComment, SavingComment, WaitForEndSlash, // quoted states SaveString, EscapeCharacter, }; CommentQuotedState state; const CommentQuotedState StartState = WaitForCommentOrQuote; }; SHAR_EOF fi # end of overwriting check if test -f 'ident.h' then echo shar: will not over-write existing file "'ident.h'" else cat << \SHAR_EOF > 'ident.h' /* * This code is covered under the Gnu General Public License, version 1. * Colin Kelley, June 1991 */ #pragma once /* * This state machine extracts identifiers and numbers from a character * event stream. It introduces the following event types: * IdentEvent * NumberEvent */ #include "event.h" class IdentEvent : public AccumulatorEvent { public: inline IdentEvent( int r, int s ) : AccumulatorEvent( r, s ) { } ~IdentEvent(); EventType ThisEventCode() const; private: void OutputHeader( FILE* outFile ) const; void OutputTrailer( FILE* outFile ) const; }; class NumberEvent : public AccumulatorEvent { public: inline NumberEvent( int r, int s ) : AccumulatorEvent( r, s ) { } ~NumberEvent(); EventType ThisEventCode() const; private: void OutputHeader( FILE* outFile ) const; void OutputTrailer( FILE* outFile ) const; }; class IdentNumberFSM : public FSM { public: IdentNumberFSM( EventSink* eventSink ) : FSM( eventSink ) { state = StartState; ident = NULL; number = NULL; } ~IdentNumberFSM() { if (ident) { delete ident; } if (number) { delete number; } } void Inject( Event* event ); private: void AddIdentChar( char c ) { ident->AddChar( c ); } void AddNumberChar( char c ) { number->AddChar( c ); } IdentEvent* ident; NumberEvent* number; enum IdentNumberState { WaitForIdentOrNumber, SavingIdent, SavingNumber, }; IdentNumberState state; const IdentNumberState StartState = WaitForIdentOrNumber; }; SHAR_EOF fi # end of overwriting check if test -f 'keyword.h' then echo shar: will not over-write existing file "'keyword.h'" else cat << \SHAR_EOF > 'keyword.h' /* * This code is covered under the Gnu General Public License, version 1. * Colin Kelley, June 1991 */ #pragma once /* * This state machine converts identifiers which are keywords into keyword * events. It introduces event type (surprise): * KeywordEvent */ #include "event.h" #include "ident.h" extern "C" int strlen( const char* ); extern "C" int strcmp( const char*, const char* ); extern "C" const char* strcpy( char*, const char* ); class KeywordEvent : public NonCharEvent { public: inline KeywordEvent( int r, int s, const char* kw ) : NonCharEvent( r, s ) { keyword = malloc( strlen( kw ) + 1 ); strcpy( keyword, kw ); } ~KeywordEvent(); void Output( FILE* outFile, int indent ) const; EventType ThisEventCode() const; inline int IsKeyword( const char* kw ) const { return strcmp( kw, keyword ) == 0; } private: char* keyword; void OutputHeader( FILE* outFile ) const; void OutputTrailer( FILE* outFile ) const; }; class KeywordFSM : public FSM { public: KeywordFSM( EventSink* eventSink ) : FSM( eventSink ) { } ~KeywordFSM() { } void Inject( Event* event ); private: // degenerate state machine! }; SHAR_EOF fi # end of overwriting check if test -f 'inline.h' then echo shar: will not over-write existing file "'inline.h'" else cat << \SHAR_EOF > 'inline.h' /* * This code is covered under the Gnu General Public License, version 1. * Colin Kelley, June 1991 */ #pragma once /* * This state machine extracts everything from the `inline' keyword up until * the trailing right brace and places it in a separate file. It complains * (but continues) if `inline' is found nested in braces. */ #include "event.h" #include "keyword.h" class ExtractInlineFSM : public FSM { public: ExtractInlineFSM( EventSink* nSink, EventSink* iSink ) : FSM( nSink ) { state = StartState; braceLevel = 0; inlineSink = iSink; } ~ExtractInlineFSM() { } void Inject( Event* event ); void EmitInline( Event* event ) { inlineSink->Inject( event ); } private: enum ExtractInlineState { CopyingCode, ExtractingInline, }; ExtractInlineState state; const ExtractInlineState StartState = CopyingCode; EventSink* inlineSink; int braceLevel; }; SHAR_EOF fi # end of overwriting check if test -f 'event.cc' then echo shar: will not over-write existing file "'event.cc'" else cat << \SHAR_EOF > 'event.cc' /* * This code is covered under the Gnu General Public License, version 1. * Colin Kelley, June 1991 */ #include "event.h" Event::~Event() { } CharEvent::~CharEvent() { } Boolean CharEvent::IsCharEvent() const { return TRUE; } NonCharEvent::~NonCharEvent() { } Boolean NonCharEvent::IsCharEvent() const { return FALSE; } AccumulatorEvent::~AccumulatorEvent() { accumulator.CharAccumulator::~CharAccumulator(); } void AccumulatorEvent::Output( FILE* outFile, int indent ) const { const char* buffer = accumulator.AccumulatorBuffer(); // output header OutputHeader( outFile ); // output first line int i = OutputFirstLine( outFile, buffer ); // output remaining lines if (buffer[i] != '\0') { OutputRemainingLines( outFile, &buffer[i], indent ); } // output trailer OutputTrailer( outFile ); } int AccumulatorEvent::OutputFirstLine( FILE* outFile, const char* buffer ) const { for (int i = 0; buffer[i] != '\0'; i++) { putc( buffer[i], outFile ); if (buffer[i] == '\n') { return i + 1; } } return i; } void AccumulatorEvent::OutputRemainingLines( FILE* outFile, const char* remaining, int ) const { // don't use any special indenting fputs( remaining, outFile ); } void OutputEvent::Inject( Event* event ) { event->Output( outFile, 0 ); delete event; } SpaceEvent::~SpaceEvent() { } void SpaceEvent::Output( FILE* outFile, int ) const { putc( ' ', outFile ); } EventType SpaceEvent::ThisEventCode() const { return Event::Space; } char SpaceEvent::ThisChar() const { return ' '; } TabEvent::~TabEvent() { } void TabEvent::Output( FILE* outFile, int ) const { putc( '\t', outFile ); } EventType TabEvent::ThisEventCode() const { return Event::Tab; } char TabEvent::ThisChar() const { return '\t'; } StarEvent::~StarEvent() { } void StarEvent::Output( FILE* outFile, int ) const { putc( '*', outFile ); } EventType StarEvent::ThisEventCode() const { return Event::Star; } char StarEvent::ThisChar() const { return '*'; } SlashEvent::~SlashEvent() { } void SlashEvent::Output( FILE* outFile, int ) const { putc( '/', outFile ); } EventType SlashEvent::ThisEventCode() const { return Event::Slash; } char SlashEvent::ThisChar() const { return '/'; } PoundEvent::~PoundEvent() { } void PoundEvent::Output( FILE* outFile, int ) const { putc( '#', outFile ); } EventType PoundEvent::ThisEventCode() const { return Event::Pound; } char PoundEvent::ThisChar() const { return '#'; } BackSlashEvent::~BackSlashEvent() { } void BackSlashEvent::Output( FILE* outFile, int ) const { putc( '\\', outFile ); } EventType BackSlashEvent::ThisEventCode() const { return Event::BackSlash; } char BackSlashEvent::ThisChar() const { return '\\'; } NewLineEvent::~NewLineEvent() { } void NewLineEvent::Output( FILE* outFile, int ) const { putc( '\n', outFile ); } EventType NewLineEvent::ThisEventCode() const { return Event::NewLine; } char NewLineEvent::ThisChar() const { return '\n'; } SingleQuoteEvent::~SingleQuoteEvent() { } void SingleQuoteEvent::Output( FILE* outFile, int ) const { putc( '\'', outFile ); } EventType SingleQuoteEvent::ThisEventCode() const { return Event::SingleQuote; } char SingleQuoteEvent::ThisChar() const { return '\''; } DoubleQuoteEvent::~DoubleQuoteEvent() { } void DoubleQuoteEvent::Output( FILE* outFile, int ) const { putc( '"', outFile ); } EventType DoubleQuoteEvent::ThisEventCode() const { return Event::DoubleQuote; } char DoubleQuoteEvent::ThisChar() const { return '"'; } MatchingEvent::~MatchingEvent() { } LeftParenEvent::~LeftParenEvent() { } void LeftParenEvent::Output( FILE* outFile, int ) const { putc( '(', outFile ); } EventType LeftParenEvent::ThisEventCode() const { return Event::LeftParen; } char LeftParenEvent::ThisChar() const { return '('; } RightParenEvent::~RightParenEvent() { } void RightParenEvent::Output( FILE* outFile, int ) const { putc( ')', outFile ); } EventType RightParenEvent::ThisEventCode() const { return Event::RightParen; } char RightParenEvent::ThisChar() const { return ')'; } LeftBraceEvent::~LeftBraceEvent() { } void LeftBraceEvent::Output( FILE* outFile, int ) const { putc( '{', outFile ); } EventType LeftBraceEvent::ThisEventCode() const { return Event::LeftBrace; } char LeftBraceEvent::ThisChar() const { return '{'; } RightBraceEvent::~RightBraceEvent() { } void RightBraceEvent::Output( FILE* outFile, int ) const { putc( '}', outFile ); } EventType RightBraceEvent::ThisEventCode() const { return Event::RightBrace; } char RightBraceEvent::ThisChar() const { return '}'; } LeftBracketEvent::~LeftBracketEvent() { } void LeftBracketEvent::Output( FILE* outFile, int ) const { putc( '[', outFile ); } EventType LeftBracketEvent::ThisEventCode() const { return Event::LeftBracket; } char LeftBracketEvent::ThisChar() const { return '['; } RightBracketEvent::~RightBracketEvent() { } void RightBracketEvent::Output( FILE* outFile, int ) const { putc( ']', outFile ); } EventType RightBracketEvent::ThisEventCode() const { return Event::RightBracket; } char RightBracketEvent::ThisChar() const { return ']'; } LineDirectiveEvent::~LineDirectiveEvent() { } void LineDirectiveEvent::Output( FILE* outFile, int ) const { fprintf( outFile, "\n#line %d\n", StartingRow() ); } EventType LineDirectiveEvent::ThisEventCode() const { return Event::LineDirective; } CharacterEvent::~CharacterEvent() { } void CharacterEvent::Output( FILE* outFile, int ) const { putc( thisChar, outFile ); } EventType CharacterEvent::ThisEventCode() const { return Event::Character; } char CharacterEvent::ThisChar() const { return thisChar; } Event* NextEvent( FILE* inFile ) { int c = getc( inFile ); if (c == EOF) { return (Event*)NULL; } static int row = 1; static int column = 0; Event *event; switch (c) { case ' ': event = new SpaceEvent( row, column ); break; case '\t': event = new TabEvent( row, column ); break; case '#': event = new PoundEvent( row, column ); break; case '*': event = new StarEvent( row, column ); break; case '/': event = new SlashEvent( row, column ); break; case '\\': event = new BackSlashEvent( row, column ); break; case '\n': event = new NewLineEvent( row, column ); row++; column = -1; break; case '\'': event = new SingleQuoteEvent( row, column ); break; case '"': event = new DoubleQuoteEvent( row, column ); break; case '(': event = new LeftParenEvent( row, column ); break; case ')': event = new RightParenEvent( row, column ); break; case '{': event = new LeftBraceEvent( row, column ); break; case '}': event = new RightBraceEvent( row, column ); break; case '[': event = new LeftBracketEvent( row, column ); break; case ']': event = new RightBracketEvent( row, column ); break; default: event = new CharacterEvent( row, column, (char)c ); break; } column++; return event; } SHAR_EOF fi # end of overwriting check if test -f 'comment.cc' then echo shar: will not over-write existing file "'comment.cc'" else cat << \SHAR_EOF > 'comment.cc' /* * This code is covered under the Gnu General Public License, version 1. * Colin Kelley, June 1991 */ #include "comment.h" CommentEvent::~CommentEvent() { } void CommentEvent::OutputRemainingLines( FILE* outFile, const char* remaining, int deltaIndent ) const { for (int i = 0; remaining[i] != '\0';) { // find current indentation for (int lineIndent = 0; remaining[i] == ' '; lineIndent++, i++) ; // add in delta lineIndent += deltaIndent; // indent this much on output for (int j = 0; j < lineIndent; j++) { putc( ' ', outFile ); } // output remaining characters on line for (; remaining[i] != '\0'; i++) { putc( remaining[i], outFile ); if (remaining[i] == '\n') { i++; break; } } } } void CommentEvent::OutputHeader( FILE* outFile ) const { fputs( "/*", outFile ); } void CommentEvent::OutputTrailer( FILE* outFile ) const { fputs( "*/", outFile ); } EventType CommentEvent::ThisEventCode() const { return Event::Comment; } CplusCommentEvent::~CplusCommentEvent() { } void CplusCommentEvent::OutputHeader( FILE* outFile ) const { fputs( "//", outFile ); } void CplusCommentEvent::OutputTrailer( FILE* outFile ) const { } EventType CplusCommentEvent::ThisEventCode() const { return Event::CplusComment; } void QuotedCharacterEvent::OutputHeader( FILE* outFile ) const { fputs( "'", outFile ); } void QuotedCharacterEvent::OutputTrailer( FILE* outFile ) const { fputs( "'", outFile ); } EventType QuotedCharacterEvent::ThisEventCode() const { return Event::SingleQuote; } void QuotedStringEvent::OutputHeader( FILE* outFile ) const { fputs( "\"", outFile ); } void QuotedStringEvent::OutputTrailer( FILE* outFile ) const { fputs( "\"", outFile ); } EventType QuotedStringEvent::ThisEventCode() const { return Event::DoubleQuote; } void CommentQuotedFSM::AddCommentChar( char c ) { comment->AddChar( c ); } void CommentQuotedFSM::Inject( Event* event ) { switch (state) { case WaitForCommentOrQuote: switch (event->ThisEventCode()) { case Event::Slash: // swallow slash delete event; // transition state = WaitForStartStarOrSlash; break; case Event::SingleQuote: // remember it was single quote quoteCode = Event::SingleQuote; // swallow single quote delete event; // allocate quoted string storage quoted = new QuotedCharacterEvent( event->StartingRow(), event->StartingColumn() ); // transition state = SaveString; break; case Event::DoubleQuote: // remember it was double quote quoteCode = Event::DoubleQuote; // swallow double quote delete event; // allocate quoted string storage quoted = new QuotedStringEvent( event->StartingRow(), event->StartingColumn() ); // transition state = SaveString; break; default: // emit this event Emit( event ); break; } break; case WaitForStartStarOrSlash: switch (event->ThisEventCode()) { case Event::Star: // swallow star delete event; // transition comment = new CommentEvent( event->StartingRow(), event->StartingColumn() - 2 ); state = SavingComment; break; case Event::Slash: // swallow second slash delete event; // transition comment = new CplusCommentEvent( event->StartingRow(), event->StartingColumn() - 2 ); state = SavingCplusComment; break; default: // emit buffered slash Event* bufferedSlash = new SlashEvent( event->StartingRow(), event->StartingColumn() - 1); Emit( bufferedSlash ); // then emit this event Emit( event ); // transition back where we came from state = WaitForCommentOrQuote; } break; case SavingComment: switch (event->ThisEventCode()) { case Event::Star: // swallow star delete event; // transition state = WaitForEndSlash; break; default: // verify that we have a char if (!event->IsCharEvent()) { fprintf( stderr, "non-char event in comment!\n" ); exit( 1 ); } // add this character to comment AddCommentChar( ((CharEvent*)event)->ThisChar() ); // swallow event delete event; break; } break; case SavingCplusComment: switch (event->ThisEventCode()) { case Event::NewLine: // emit buffered comment event Emit( comment ); comment = NULL; // emit new line Emit( event ); // transition state = WaitForCommentOrQuote; break; default: // verify that we have a char if (!event->IsCharEvent()) { fprintf( stderr, "non-char event in comment!\n" ); exit( 1 ); } // add this character to comment AddCommentChar( ((CharEvent*)event)->ThisChar() ); // swallow event delete event; break; } break; case WaitForEndSlash: switch (event->ThisEventCode()) { case Event::Slash: // swallow slash delete event; // emit the comment event we've been building Emit( comment ); comment = NULL; // transition back to beginning state = WaitForCommentOrQuote; break; case Event::Star: // save this star AddCommentChar( '*' ); // swallow event delete event; // stay in same state ; break; default: // save buffered star AddCommentChar( '*' ); // verify that we have a char if (!event->IsCharEvent()) { fprintf( stderr, "non-char event in comment!\n" ); exit( 1 ); } // then add this character to comment AddCommentChar( ((CharEvent*)event)->ThisChar() ); // swallow event delete event; // transition back to saving comment state = SavingComment; break; } break; /* * Quoted String FSM portion begins here. */ case SaveString: if( event->ThisEventCode() == quoteCode) { // emit saved string event Emit( quoted ); quoted = NULL; // transition state = WaitForCommentOrQuote; } else if( event->ThisEventCode() == Event::BackSlash) { // save backslash in quoted string AddQuotedChar( '\\' ); // swallow event delete event; // transition state = EscapeCharacter; break; } else { // verify that we have a char if (!event->IsCharEvent()) { fprintf( stderr, "non-char event in comment!\n" ); exit( 1 ); } // add this character to quoted string AddQuotedChar( ((CharEvent*)event)->ThisChar() ); // swallow event delete event; // same state ; break; } break; case EscapeCharacter: // verify that we have a char if (!event->IsCharEvent()) { fprintf( stderr, "non-char event in comment!\n" ); exit( 1 ); } // add this character regardless AddQuotedChar( ((CharEvent*)event)->ThisChar() ); // swallow event delete event; // transition back state = SaveString; break; } } SHAR_EOF fi # end of overwriting check if test -f 'ident.cc' then echo shar: will not over-write existing file "'ident.cc'" else cat << \SHAR_EOF > 'ident.cc' /* * This code is covered under the Gnu General Public License, version 1. * Colin Kelley, June 1991 */ #include "ident.h" IdentEvent::~IdentEvent() { } void IdentEvent::OutputHeader( FILE* outFile ) const { } void IdentEvent::OutputTrailer( FILE* outFile ) const { } EventType IdentEvent::ThisEventCode() const { return Event::Ident; } NumberEvent::~NumberEvent() { } void NumberEvent::OutputHeader( FILE* outFile ) const { } void NumberEvent::OutputTrailer( FILE* outFile ) const { } EventType NumberEvent::ThisEventCode() const { return Event::Number; } void IdentNumberFSM::Inject( Event* event ) { switch (state) { case WaitForIdentOrNumber: switch (event->ThisEventCode()) { case Event::Character: char c = ((CharacterEvent*)event)->ThisChar(); if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || c == '_' || c == '$') { // swallow char event delete event; // start ident event ident = new IdentEvent( event->StartingRow(), event->StartingColumn() ); ident->AddChar( c ); // transition state = SavingIdent; } else if (c >= '0' && c <= '9') { // swallow char event delete event; // start number event number = new NumberEvent( event->StartingRow(), event->StartingColumn() ); number->AddChar( c ); // transition state = SavingNumber; } else { // emit this event Emit( event ); } break; default: // emit this event Emit( event ); break; } break; case SavingIdent: switch (event->ThisEventCode()) { case Event::Character: char c = ((CharacterEvent*)event)->ThisChar(); if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '_' || c == '$') { // add character to ident AddIdentChar( c ); // swallow char event delete event; // same state ; } else { // emit ident event Emit( ident ); ident = NULL; // emit this event Emit( event ); // transition state = WaitForIdentOrNumber; } break; default: // emit ident event Emit( ident ); ident = NULL; // emit this event Emit( event ); // transition state = WaitForIdentOrNumber; break; } break; case SavingNumber: switch (event->ThisEventCode()) { case Event::Character: char c = ((CharacterEvent*)event)->ThisChar(); if ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f') || c == 'x' || c == 'X') { // add character to number AddNumberChar( c ); // swallow char event delete event; // same state ; } else { // emit number event Emit( number ); number = NULL; // emit this event Emit( event ); // transition state = WaitForIdentOrNumber; } break; default: // emit number event Emit( number ); number = NULL; // emit this event Emit( event ); // transition state = WaitForIdentOrNumber; break; } break; } } SHAR_EOF fi # end of overwriting check if test -f 'keyword.cc' then echo shar: will not over-write existing file "'keyword.cc'" else cat << \SHAR_EOF > 'keyword.cc' /* * This code is covered under the Gnu General Public License, version 1. * Colin Kelley, June 1991 */ #include "keyword.h" KeywordEvent::~KeywordEvent() { free( keyword ); } void KeywordEvent::Output( FILE* outFile, int indent ) const { fputs( keyword, outFile ); } EventType KeywordEvent::ThisEventCode() const { return Event::Keyword; } void KeywordFSM::Inject( Event* event ) { if (event->ThisEventCode() == Event::Ident) { static const char* keywords[] = { "asm", "auto", "break", "case", "catch", "char", "class", "const", "continue", "default", "delete", "do", "double", "else", "enum", "extern", "float", "for", "friend", "goto", "if", "inline", "int", "long", "new", "operator", "private", "protected", "public", "register", "return", "short", "signed", "sizeof", "static", "struct", "switch", "template", "this", "throw", "try", "typedef", "union", "unsigned", "virtual", "void", "volatile", "while", NULL }; const char* str = ((IdentEvent*)event)->AccumulatorBuffer(); for (int i = 0; keywords[i] != NULL; i++) { if (strcmp( str, keywords[i] ) == 0) { // emit keyword event KeywordEvent* keywordEvent = new KeywordEvent( event->StartingRow(), event->StartingColumn(), str ); Emit( keywordEvent ); // destroy old event delete event; return; } } } // emit event Emit( event ); } SHAR_EOF fi # end of overwriting check if test -f 'inline.cc' then echo shar: will not over-write existing file "'inline.cc'" else cat << \SHAR_EOF > 'inline.cc' /* * This code is covered under the Gnu General Public License, version 1. * Colin Kelley, June 1991 */ #include "event.h" #include "inline.h" void ExtractInlineFSM::Inject( Event* event ) { switch (state) { case CopyingCode: switch (event->ThisEventCode()) { case Event::LeftBrace: braceLevel++; // emit event Emit( event ); break; case Event::RightBrace: braceLevel--; // emit event Emit( event ); break; case Event::Keyword: // check if it's `inline' if (((KeywordEvent*)event)->IsKeyword( "inline" )) { // don't handle 'inline' if it's enclosed in braces if (braceLevel != 0) { fprintf( stderr, "inline at line %d at brace level %d!\n", event->StartingRow(), braceLevel ); Emit( event ); break; } // start inline with #line directive EmitInline( new LineDirectiveEvent(event->StartingRow(), event->StartingColumn() ) ); // then inline keyword EmitInline( event ); // transition state = ExtractingInline; break; } else { ; // fall through } default: // emit event Emit( event ); break; } break; case ExtractingInline: switch (event->ThisEventCode()) { case Event::LeftBrace: braceLevel++; // add this to inline function EmitInline( event ); break; case Event::RightBrace: braceLevel--; // add this to inline function EmitInline( event ); // stop if outer-most right brace if (braceLevel == 0) { // mark current line in remain file Emit( new LineDirectiveEvent( event->StartingRow() + 1, event->StartingColumn() ) ); // add on an extra new line for appearance EmitInline( new NewLineEvent( 0, 0 ) ); // transition state = CopyingCode; } break; default: // add this to inline function EmitInline( event ); break; } } } SHAR_EOF fi # end of overwriting check if test -f 'move-if-change' then echo shar: will not over-write existing file "'move-if-change'" else cat << \SHAR_EOF > 'move-if-change' #!/bin/sh if test -r $2; then if cmp $1 $2 > /dev/null; then echo $2 is unchanged rm $1 else mv $1 $2 fi else mv $1 $2 fi SHAR_EOF chmod +x 'move-if-change' fi # end of overwriting check # End of shell archive exit 0