/* -*- C++ -*- * Copyright ©2004 Hugo Mills * * This software is distributed under the terms of the GNU GPL v3 * For more information on the GPL, see the file COPYING or * visit http://www.gnu.org/ * * This software is distributed without warranty */ #include "magellan/configlexer.h" #include "magellan/options.h" ConfigLexer* lex; ConfigLexer* ConfigLexer::next(void) { // std::cerr << "NEXT" << std::endl; while(true) { char ch = input->get(); if(input->eof()) { if(parsestate != WS) throw UnexpectedEOF(); currentvalue.first = END; if(opts->debug_lexer() >= 1) std::cerr << "Lexer: next value " << currentvalue.second << std::endl; return this; } // Keep track of the line numbers if(ch == 10) line++; switch(parsestate) { case WS: // More white space if(isspace(ch)) { break; } // Comment handling if(ch == '#') { parsestate = PERLCOMMENT; break; } if(ch == '/') { parsestate = POSSCOMMENT; currentvalue.first = CHAR; currentvalue.second += ch; break; } // Quoted strings if(ch == '"') { parsestate = QUOTEDSTRING; currentvalue.first = STRING; currentvalue.second = ""; break; } // Numbers if(isdigit(ch) || ch == '-' || ch == '+') { parsestate = NUMBER; currentvalue.first = INTEGER; currentvalue.second = ch; break; } // Unquoted strings/tokens if(ch == '_' || isalpha(ch)) { parsestate = TEXT; currentvalue.first = TOKEN; currentvalue.second = ch; break; } currentvalue.first = CHAR; currentvalue.second = ch; if(opts->debug_lexer() >= 1) std::cerr << "Lexer: next value " << currentvalue.second << std::endl; return this; break; case PERLCOMMENT: case CPPCOMMENT: if(ch == 10) parsestate = WS; break; case POSSCOMMENT: if(ch == '*') parsestate = CCOMMENT; else if(ch == '/') { currentvalue.second = ""; parsestate = CPPCOMMENT; } else { parsestate = WS; input->unget(); // We've already got something in the result string, // so keep this one for the "next token" request if(opts->debug_lexer() >= 1) std::cerr << "Lexer: next value " << currentvalue.second << std::endl; return this; } break; case CCOMMENT: if(ch == '*') parsestate = POSSCOMMENTEND; break; case POSSCOMMENTEND: if(ch == '/') parsestate = WS; else parsestate = CCOMMENT; break; case TEXT: if(ch == '_' || ch == '-' || isalnum(ch)) currentvalue.second += ch; else { parsestate = WS; input->unget(); if(opts->debug_lexer() >= 1) std::cerr << "Lexer: next value " << currentvalue.second << std::endl; return this; } break; case QUOTEDSTRING: if(ch == '"') { parsestate = WS; if(opts->debug_lexer() >= 1) std::cerr << "Lexer: next value " << currentvalue.second << std::endl; return this; } currentvalue.second += ch; break; case NUMBER: if(ch == '.') { currentvalue.first = FLOAT; currentvalue.second += ch; parsestate = DECIMAL; break; } // No break here case DECIMAL: if(isdigit(ch)) currentvalue.second += ch; else { parsestate = WS; input->unget(); if(opts->debug_lexer() >= 1) std::cerr << "Lexer: next value " << currentvalue.second << std::endl; return this; } break; } } } bool ConfigLexer::eos(void) { // std::cerr << "EOS: " << type() << " (" << CHAR << ") " // << value() << std::endl; bool rv = (type() == CHAR && value() == "}"); return rv; } ConfigLexer* ConfigLexer::section_next(void) { while(!eos()) next(); next(); return this; } ConfigLexer* ConfigLexer::directive_next(void) { while(!(type() == CHAR && value() == ";")) next(); next(); return this; }