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