summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdrian Thurston <thurston@colm.net>2021-11-07 21:26:51 -0800
committerAdrian Thurston <thurston@colm.net>2021-11-07 21:26:51 -0800
commite62c4cfd98d53dbc3db9676445cb2da63d4a3567 (patch)
tree05ee7b05399e9b7d24072875649d57ccead6b2bd
parent8b60d8eb3679337b9036988d2898558d5ef49117 (diff)
downloadragel-e62c4cfd98d53dbc3db9676445cb2da63d4a3567.tar.gz
moved output filter, file name funcs, line directive generation from colm
-rw-r--r--src/ncommon.cc233
-rw-r--r--src/nragel.h80
2 files changed, 313 insertions, 0 deletions
diff --git a/src/ncommon.cc b/src/ncommon.cc
index 4e7f270d..79b93b1a 100644
--- a/src/ncommon.cc
+++ b/src/ncommon.cc
@@ -107,3 +107,236 @@ HostType *findAlphTypeInternal( const HostLang *hostLang, const char *s1 )
return 0;
}
+std::streamsize output_filter::countAndWrite( const char *s, std::streamsize n )
+{
+ for ( int i = 0; i < n; i++ ) {
+ switch ( s[i] ) {
+ case '\n':
+ line += 1;
+ break;
+ case '{':
+ /* If we detec an open block then eliminate the single-indent
+ * addition, which is to account for single statements. */
+ singleIndent = false;
+ level += 1;
+ break;
+ case '}':
+ level -= 1;
+ break;
+ }
+ }
+
+ return std::filebuf::xsputn( s, n );
+}
+
+bool openSingleIndent( const char *s, int n )
+{
+ if ( n >= 3 && memcmp( s, "if ", 3 ) == 0 )
+ return true;
+
+ if ( n >= 8 && memcmp( s, "else if ", 8 ) == 0 )
+ return true;
+
+ if ( n >= 5 && memcmp( s, "else\n", 4 ) == 0 )
+ return true;
+
+ return false;
+}
+
+/* Counts newlines before sending sync. */
+int output_filter::sync( )
+{
+ line += 1;
+ return std::filebuf::sync();
+}
+
+/* Counts newlines before sending data out to file. */
+std::streamsize output_filter::xsputn( const char *s, std::streamsize n )
+{
+ std::streamsize ret = n;
+ int l;
+
+restart:
+ if ( indent ) {
+ /* Consume mode Looking for the first non-whitespace. */
+ while ( n > 0 && ( *s == ' ' || *s == '\t' ) ) {
+ s += 1;
+ n -= 1;
+ }
+
+ if ( n > 0 ) {
+ int tabs = level + ( singleIndent ? 1 : 0 );
+
+ if ( *s == '}' ) {
+ /* If the next char is de-dent, then reduce the tabs. This is
+ * not a stream state change. The level reduction will be
+ * computed in write. */
+ tabs -= 1;
+ }
+
+ /* Note that the count and write will eliminate this if it detects
+ * an open block. */
+ if ( openSingleIndent( s, n ) )
+ singleIndent = true;
+ else
+ singleIndent = false;
+
+ if ( *s != '#' ) {
+ /* Found some data, print the indentation and turn off indentation
+ * mode. */
+ for ( l = 0; l < tabs; l++ )
+ countAndWrite( "\t", 1 );
+ }
+
+
+ indent = 0;
+
+ goto restart;
+ }
+ }
+ else {
+ char *nl;
+ if ( (nl = (char*)memchr( s, '\n', n )) ) {
+ /* Print up to and including the newline. */
+ int wl = nl - s + 1;
+ countAndWrite( s, wl );
+
+ /* Go into consume state. If we see more non-indentation chars we
+ * will generate the appropriate indentation level. */
+ s += wl;
+ n -= wl;
+ indent = true;
+ goto restart;
+ }
+ else {
+ /* Indentation off, or no indent trigger (newline). */
+ countAndWrite( s, n );
+ }
+ }
+
+ // What to do here?
+ return ret;
+}
+
+/* Scans a string looking for the file extension. If there is a file
+ * extension then pointer returned points to inside the string
+ * passed in. Otherwise returns null. */
+const char *findFileExtension( const char *stemFile )
+{
+ const char *ppos = stemFile + strlen(stemFile) - 1;
+
+ /* Scan backwards from the end looking for the first dot.
+ * If we encounter a '/' before the first dot, then stop the scan. */
+ while ( 1 ) {
+ /* If we found a dot or got to the beginning of the string then
+ * we are done. */
+ if ( ppos == stemFile || *ppos == '.' )
+ break;
+
+ /* If we hit a / then there is no extension. Done. */
+ if ( *ppos == '/' ) {
+ ppos = stemFile;
+ break;
+ }
+ ppos--;
+ }
+
+ /* If we got to the front of the string then bail we
+ * did not find an extension */
+ if ( ppos == stemFile )
+ ppos = 0;
+
+ return ppos;
+}
+
+/* Make a file name from a stem. Removes the old filename suffix and
+ * replaces it with a new one. Returns a newed up string. */
+const char *fileNameFromStem( const char *stemFile, const char *suffix )
+{
+ long len = strlen( stemFile );
+ assert( len > 0 );
+
+ /* Get the extension. */
+ const char *ppos = findFileExtension( stemFile );
+
+ /* If an extension was found, then shorten what we think the len is. */
+ if ( ppos != 0 )
+ len = ppos - stemFile;
+
+ /* Make the return string from the stem and the suffix. */
+ char *retVal = new char[ len + strlen( suffix ) + 1 ];
+ strncpy( retVal, stemFile, len );
+ strcpy( retVal + len, suffix );
+
+ return retVal;
+}
+
+exit_object endp;
+
+void operator<<( std::ostream &out, exit_object & )
+{
+ out << std::endl;
+ throw AbortCompile( 1 );
+}
+
+void genLineDirectiveC( std::ostream &out, bool lineDirectives, int line, const char *fileName )
+{
+ if ( line < 0 ) {
+ std::streambuf *sbuf = out.rdbuf();
+ output_filter *filter = dynamic_cast<output_filter*>(sbuf);
+ if ( filter == 0 )
+ return;
+
+ line = filter->line + 1;
+ fileName = filter->fileName;
+ }
+
+ if ( !lineDirectives )
+ out << "/* ";
+
+
+ out << "#line " << line << " \"";
+ for ( const char *pc = fileName; *pc != 0; pc++ ) {
+ if ( *pc == '\\' )
+ out << "\\\\";
+ else if ( *pc == '"' )
+ out << "\\\"";
+ else
+ out << *pc;
+ }
+ out << '"';
+
+ if ( !lineDirectives )
+ out << " */";
+
+ out << '\n';
+}
+
+void genLineDirectiveAsm( std::ostream &out, bool lineDirectives, int line, const char *fileName )
+{
+ if ( line < 0 ) {
+ std::streambuf *sbuf = out.rdbuf();
+ output_filter *filter = dynamic_cast<output_filter*>(sbuf);
+ if ( filter == 0 )
+ return;
+
+ line = filter->line + 1;
+ fileName = filter->fileName;
+ }
+
+ out << "/* #line " << line << " \"";
+ for ( const char *pc = fileName; *pc != 0; pc++ ) {
+ if ( *pc == '\\' )
+ out << "\\\\";
+ else if ( *pc == '"' )
+ out << "\\\"";
+ else
+ out << *pc;
+ }
+ out << '"';
+ out << " */\n";
+}
+
+void genLineDirectiveTrans( std::ostream &out, bool lineDirectives, int line, const char *fileName )
+{
+}
diff --git a/src/nragel.h b/src/nragel.h
index 11bca028..6eaa2028 100644
--- a/src/nragel.h
+++ b/src/nragel.h
@@ -19,6 +19,9 @@ CodeGenData *asm_makeCodeGen( const HostLang *hostLang, const CodeGenArgs &args
typedef CodeGenData *(*MakeCodeGenT)( const HostLang *hostLang, const CodeGenArgs &args );
+typedef void (*GenLineDirectiveT)( std::ostream &out, bool nld, int line, const char *file );
+typedef const char *(*DefaultOutFnT)( const char *inputFileName );
+
struct HostLang
{
HostType *hostTypes;
@@ -35,4 +38,81 @@ struct HostLang
GenLineDirectiveT genLineDirective;
};
+void genLineDirectiveC( std::ostream &out, bool nld, int line, const char *file );
+void genLineDirectiveAsm( std::ostream &out, bool nld, int line, const char *file );
+void genLineDirectiveTrans( std::ostream &out, bool nld, int line, const char *file );
+
+/* Filter on the output stream that keeps track of the number of lines
+ * output. */
+class output_filter
+:
+ public std::filebuf
+{
+public:
+ output_filter( const char *fileName )
+ :
+ fileName(fileName),
+ line(1),
+ level(0),
+ indent(false),
+ singleIndent(false)
+ {}
+
+ virtual int sync();
+ virtual std::streamsize xsputn( const char* s, std::streamsize n );
+
+ std::streamsize countAndWrite( const char* s, std::streamsize n );
+
+ const char *fileName;
+ int line;
+ int level;
+ bool indent;
+ bool singleIndent;
+};
+
+class cfilebuf : public std::streambuf
+{
+public:
+ cfilebuf( char *fileName, FILE* file ) : fileName(fileName), file(file) { }
+ char *fileName;
+ FILE *file;
+
+ int sync()
+ {
+ fflush( file );
+ return 0;
+ }
+
+ int overflow( int c )
+ {
+ if ( c != EOF )
+ fputc( c, file );
+ return 0;
+ }
+
+ std::streamsize xsputn( const char* s, std::streamsize n )
+ {
+ std::streamsize written = fwrite( s, 1, n, file );
+ return written;
+ }
+};
+
+class costream : public std::ostream
+{
+public:
+ costream( cfilebuf *b ) :
+ std::ostream(b), b(b) {}
+
+ ~costream()
+ { delete b; }
+
+ void fclose()
+ { ::fclose( b->file ); }
+
+ cfilebuf *b;
+};
+
+const char *findFileExtension( const char *stemFile );
+const char *fileNameFromStem( const char *stemFile, const char *suffix );
+
#endif