2 Copyright (C) 2001-2006, William Joseph.
5 This file is part of GtkRadiant.
7 GtkRadiant is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 GtkRadiant is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GtkRadiant; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 #if !defined( INCLUDED_SCRIPT_SCRIPTTOKENISER_H )
23 #define INCLUDED_SCRIPT_SCRIPTTOKENISER_H
25 #include "iscriplib.h"
27 class ScriptTokeniser : public Tokeniser
40 typedef bool ( ScriptTokeniser::*Tokenise )( char c );
44 SingleCharacterInputStream<TextInputStream> m_istream;
45 std::size_t m_scriptline;
46 std::size_t m_scriptcolumn;
48 char m_token[MAXTOKEN];
59 CharType charType( const char c ){
62 case '\n': return eNewline;
63 case '"': return eCharQuote;
64 case '/': return eCharSolidus;
65 case '*': return eCharStar;
66 case '{': case '(': case '}': case ')': case '[': case ']': case ',': case ':': return ( m_special ) ? eCharSpecial : eCharToken;
78 void push( Tokenise state ){
79 ASSERT_MESSAGE( m_state != m_stack + 2, "token parser: illegal stack push" );
80 *( ++m_state ) = state;
83 ASSERT_MESSAGE( m_state != m_stack, "token parser: illegal stack pop" );
86 void add( const char c ){
87 if ( m_write < m_token + MAXTOKEN - 1 ) {
92 ASSERT_MESSAGE( m_write > m_token, "no char to remove" );
96 bool tokeniseDefault( char c ){
97 switch ( charType( c ) )
100 if ( !m_crossline ) {
101 globalErrorStream() << Unsigned( getLine() ) << ":" << Unsigned( getColumn() ) << ": unexpected end-of-line before token\n";
107 push( Tokenise( &ScriptTokeniser::tokeniseToken ) );
111 push( Tokenise( &ScriptTokeniser::tokeniseSpecial ) );
115 push( Tokenise( &ScriptTokeniser::tokeniseQuotedToken ) );
118 push( Tokenise( &ScriptTokeniser::tokeniseSolidus ) );
125 bool tokeniseToken( char c ){
126 switch ( charType( c ) )
133 m_emit = true; // emit token
136 #if 0 //SPoG: ignore comments in the middle of tokens.
137 push( Tokenise( &ScriptTokeniser::tokeniseSolidus ) );
149 bool tokeniseQuotedToken( char c ){
150 switch ( charType( c ) )
154 globalErrorStream() << Unsigned( getLine() ) << ":" << Unsigned( getColumn() ) << ": unexpected end-of-line in quoted token\n";
167 push( Tokenise( &ScriptTokeniser::tokeniseEndQuote ) );
174 bool tokeniseSolidus( char c ){
175 switch ( charType( c ) )
183 m_emit = true; // emit single slash
192 push( Tokenise( &ScriptTokeniser::tokeniseComment ) );
193 break; // dont emit single slash
196 push( Tokenise( &ScriptTokeniser::tokeniseBlockComment ) );
197 break; // dont emit single slash
203 bool tokeniseComment( char c ){
206 if ( state() == Tokenise( &ScriptTokeniser::tokeniseToken ) ) {
208 m_emit = true; // emit token immediatly preceding comment
213 bool tokeniseBlockComment( char c ){
216 push( Tokenise( &ScriptTokeniser::tokeniseEndBlockComment ) );
220 bool tokeniseEndBlockComment( char c ){
225 if ( state() == Tokenise( &ScriptTokeniser::tokeniseToken ) ) {
227 m_emit = true; // emit token immediatly preceding comment
229 break; // dont emit comment
231 break; // no state change
234 push( Tokenise( &ScriptTokeniser::tokeniseBlockComment ) );
239 bool tokeniseEndQuote( char c ){
241 m_emit = true; // emit quoted token
244 bool tokeniseSpecial( char c ){
246 m_emit = true; // emit single-character token
250 /// Returns true if a token was successfully parsed.
257 if ( !( ( *this ).*state() )( c ) ) {
276 m_eof = !m_istream.readChar( m_current );
278 return m_write != m_token;
281 const char* fillToken(){
295 ScriptTokeniser( TextInputStream& istream, bool special )
296 : m_state( m_stack ),
297 m_istream( istream ),
300 m_crossline( false ),
303 m_special( special ){
304 m_stack[0] = Tokenise( &ScriptTokeniser::tokeniseDefault );
305 m_eof = !m_istream.readChar( m_current );
306 m_token[MAXTOKEN - 1] = '\0';
314 const char* getToken(){
323 ASSERT_MESSAGE( !m_unget, "can't unget more than one token" );
326 std::size_t getLine() const {
329 std::size_t getColumn() const {
330 return m_scriptcolumn;
335 inline Tokeniser& NewScriptTokeniser( TextInputStream& istream ){
336 return *( new ScriptTokeniser( istream, true ) );
339 inline Tokeniser& NewSimpleTokeniser( TextInputStream& istream ){
340 return *( new ScriptTokeniser( istream, false ) );