/* * Copyright 2001-2018 Adrian Thurston * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #ifndef _COMMON_H #define _COMMON_H #include #include #include #include "dlist.h" struct colm_location; struct InputData; struct CodeGenData; struct HostLang; struct CodeGenArgs; enum RagelBackend { Direct, Translated }; enum BackendFeature { GotoFeature, BreakFeature, VarFeature }; #define S8BIT_MIN -128 #define S8BIT_MAX 127 #define U8BIT_MIN 0 #define U8BIT_MAX 255 #define S16BIT_MIN -32768 #define S16BIT_MAX 32767 #define U16BIT_MIN 0 #define U16BIT_MAX 65535 #define S31BIT_MIN -1073741824l #define S31BIT_MAX 1073741823l #define S32BIT_MIN -2147483648l #define S32BIT_MAX 2147483647l #define U32BIT_MIN 0 #define U32BIT_MAX 4294967295l #define S64BIT_MIN (-9223372036854775807LL - 1LL) #define S64BIT_MAX 9223372036854775807LL #define U64BIT_MIN 0 #define U64BIT_MAX 18446744073709551615ULL struct ParserLoc { const char *fileName; int line; int col; }; /* Location in an input file. */ struct InputLoc { InputLoc( colm_location *pcloc ); InputLoc() : fileName(0), line(-1), col(-1) {} InputLoc( const ParserLoc loc ) { fileName = loc.fileName; line = loc.line; col = loc.col; if ( fileName == 0 ) fileName = "-"; if ( line == 0 ) line = 1; } InputLoc( const InputLoc &loc ) { fileName = loc.fileName; line = loc.line; col = loc.col; if ( fileName == 0 ) fileName = "-"; if ( line == 0 ) line = 1; } InputLoc( const char *fileName, int line, int col ) : fileName(fileName), line(line), col(col) {} const char *fileName; int line; int col; }; extern InputLoc internal; typedef unsigned long long Size; struct Key { private: long key; public: friend struct KeyOps; Key( ) {} Key( const Key &key ) : key(key.key) {} Key( long key ) : key(key) {} /* Returns the value used to represent the key. This value must be * interpreted based on signedness. */ long getVal() const { return key; }; bool isUpper() const { return ( 'A' <= key && key <= 'Z' ); } bool isLower() const { return ( 'a' <= key && key <= 'z' ); } bool isPrintable() const { return ( 7 <= key && key <= 13 ) || ( 32 <= key && key < 127 ); } Key toUpper() const { return Key( 'A' + ( key - 'a' ) ); } Key toLower() const { return Key( 'a' + ( key - 'A' ) ); } }; struct CondKey { private: long key; public: friend inline bool operator<( const CondKey key1, const CondKey key2 ); friend inline bool operator>( const CondKey key1, const CondKey key2 ); friend inline bool operator==( const CondKey key1, const CondKey key2 ); friend inline CondKey operator+( const CondKey key1, const CondKey key2 ); friend inline CondKey operator-( const CondKey key1, const CondKey key2 ); friend struct KeyOps; CondKey( ) {} CondKey( const CondKey &key ) : key(key.key) {} CondKey( long key ) : key(key) {} /* Returns the value used to represent the key. This value must be * interpreted based on signedness. */ long getVal() const { return key; }; bool isUpper() const { return ( 'A' <= key && key <= 'Z' ); } bool isLower() const { return ( 'a' <= key && key <= 'z' ); } bool isPrintable() const { return ( 7 <= key && key <= 13 ) || ( 32 <= key && key < 127 ); } CondKey toUpper() const { return CondKey( 'A' + ( key - 'a' ) ); } CondKey toLower() const { return CondKey( 'a' + ( key - 'A' ) ); } /* Decrement. Needed only for ranges. */ inline void decrement(); inline void increment(); }; inline CondKey operator+(const CondKey key1, const CondKey key2) { return CondKey( key1.key + key2.key ); } inline CondKey operator-(const CondKey key1, const CondKey key2) { return CondKey( key1.key - key2.key ); } struct HostType { const char *data1; const char *data2; const char *internalName; bool isSigned; bool isOrd; bool isChar; long long sMinVal; long long sMaxVal; unsigned long long uMinVal; unsigned long long uMaxVal; unsigned int size; }; typedef void (*GenLineDirectiveT)( std::ostream &out, bool nld, int line, const char *file ); typedef const char *(*DefaultOutFnT)( const char *inputFileName ); typedef CodeGenData *(*MakeCodeGenT)( const HostLang *hostLang, const CodeGenArgs &args ); struct HostLang { HostType *hostTypes; int numHostTypes; int defaultAlphType; bool explicitUnsigned; bool loopLabels; RagelBackend backend; BackendFeature feature; MakeCodeGenT makeCodeGen; DefaultOutFnT defaultOutFn; 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 ); extern const HostLang hostLangC; extern const HostLang hostLangAsm; HostType *findAlphType( const HostLang *hostLang, const char *s1 ); HostType *findAlphType( const HostLang *hostLang, const char *s1, const char *s2 ); HostType *findAlphTypeInternal( const HostLang *hostLang, const char *s1 ); const char *defaultOutFnC( const char *inputFileName ); extern HostType hostTypesC[]; /* An abstraction of the key operators that manages key operations such as * comparison and increment according the signedness of the key. */ struct KeyOps { /* Defaults to C "char" type: Signed 8 bit. */ KeyOps() : isSigned(true), explicitUnsigned(true), minKey(CHAR_MIN), maxKey(CHAR_MAX) {} bool isSigned; bool explicitUnsigned; Key minKey, maxKey; void setAlphType( const HostLang *hostLang, const HostType *alphType ) { isSigned = alphType->isSigned; explicitUnsigned = hostLang->explicitUnsigned; if ( isSigned ) { minKey = (long) alphType->sMinVal; maxKey = (long) alphType->sMaxVal; } else { minKey = (long) alphType->uMinVal; maxKey = (long) alphType->uMaxVal; } } /* Compute the distance between two keys. */ Size span( Key key1, Key key2 ) { return isSigned ? (unsigned long long)( (long long)key2.key - (long long)key1.key + 1) : (unsigned long long)( (unsigned long)key2.key) - (unsigned long long)((unsigned long)key1.key) + 1; } Size alphSize() { return span( minKey, maxKey ); } inline bool lt( const Key key1, const Key key2 ) { return this->isSigned ? key1.key < key2.key : (unsigned long)key1.key < (unsigned long)key2.key; } inline bool le( const Key key1, const Key key2 ) { return this->isSigned ? key1.key <= key2.key : (unsigned long)key1.key <= (unsigned long)key2.key; } inline bool gt( const Key key1, const Key key2 ) { return this->isSigned ? key1.key > key2.key : (unsigned long)key1.key > (unsigned long)key2.key; } inline bool ge( const Key key1, const Key key2 ) { return this->isSigned ? key1.key >= key2.key : (unsigned long)key1.key >= (unsigned long)key2.key; } inline bool eq( const Key key1, const Key key2 ) { return key1.key == key2.key; } inline bool ne( const Key key1, const Key key2 ) { return key1.key != key2.key; } inline Key add(const Key key1, const Key key2) { /* FIXME: must be made aware of isSigned. */ return Key( key1.key + key2.key ); } inline Key sub(const Key key1, const Key key2) { /* FIXME: must be made aware of isSigned. */ return Key( key1.key - key2.key ); } /* Decrement. Needed only for ranges. */ inline void decrement( Key &key ) { key.key = this->isSigned ? key.key - 1 : ((unsigned long)key.key)-1; } /* Increment. Needed only for ranges. */ inline void increment( Key &key ) { key.key = this->isSigned ? key.key+1 : ((unsigned long)key.key)+1; } /* Returns the key casted to a long long. This form of the key does not * require any signedness interpretation. */ inline long long getLongLong( const Key &key ) { return this->isSigned ? (long long)key.key : (long long)(unsigned long)key.key; } }; /* CondKey */ inline bool operator<( const CondKey key1, const CondKey key2 ) { return key1.key < key2.key; } inline bool operator>( const CondKey key1, const CondKey key2 ) { return key1.key > key2.key; } inline bool operator==( const CondKey key1, const CondKey key2 ) { return key1.key == key2.key; } /* Increment. Needed only for ranges. */ inline void CondKey::increment() { key = key + 1; } /* 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 nullbuf : public std::streambuf { public: virtual std::streamsize xsputn( const char * s, std::streamsize n ) { return n; } virtual int overflow( int c ) { return 1; } }; 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 ); struct Export { Export( std::string name, Key key ) : name(name), key(key) {} std::string name; Key key; Export *prev, *next; }; typedef DList ExportList; struct exit_object { }; extern exit_object endp; void operator<<( std::ostream &out, exit_object & ); enum RagelFrontend { KelbtBased, ReduceBased }; CodeGenData *makeCodeGen( const HostLang *hostLang, const CodeGenArgs &args ); CodeGenData *makeCodeGenAsm( const HostLang *hostLang, const CodeGenArgs &args ); #endif