8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-29 03:23:03 +01:00
firebird-mirror/src/config/Lex.cpp
2006-04-06 08:18:53 +00:00

376 lines
7.2 KiB
C++

/*
*
* The contents of this file are subject to the Initial
* Developer's Public License Version 1.0 (the "License");
* you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
* http://www.ibphoenix.com/idpl.html.
*
* Software distributed under the License is distributed on
* an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either
* express or implied. See the License for the specific
* language governing rights and limitations under the License.
*
* The contents of this file or any work derived from this file
* may not be distributed under any other license whatsoever
* without the express prior written permission of the original
* author.
*
*
* The Original Code was created by James A. Starkey for IBPhoenix.
*
* Copyright (c) 1997 - 2000, 2001, 2003 James A. Starkey
* Copyright (c) 1997 - 2000, 2001, 2003 Netfrastructure, Inc.
* All Rights Reserved.
*/
// Lex.cpp: implementation of the Lex class.
//
//////////////////////////////////////////////////////////////////////
#include <string.h>
#include <stdio.h>
#include <memory.h>
#include "firebird.h"
#include "Lex.h"
#include "AdminException.h"
#include "InputStream.h"
#define WHITE_SPACE " \t\n\r"
#define PUNCTUATION_CHARS "<>="
#define MULTI_CHARS "" //"+=*/%!~<>~^|&="
#define MAX_TOKEN 1024
#define UPCASE(c) ((c >= 'a' && c <= 'z') ? c - 'a' + 'A' : c)
#define WHITE 1
#define PUNCT 2
#define MULTI_CHAR 4
#define DIGIT 8
#define TERM (WHITE | PUNCT)
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
Lex::Lex(const char *punctuation, int debugFlags)
{
lineComment = NULL;
commentStart = NULL;
memset (charTable, 0, sizeof (charTable));
setCharacters (PUNCT, punctuation);
setCharacters (WHITE, WHITE_SPACE);
setCharacters (DIGIT, "0123456789");
ptr = end = NULL;
inputStream = NULL;
tokenType = NONE;
lineNumber = 0;
continuationChar = 0;
captureStart = captureEnd = 0;
flags = debugFlags;
}
Lex::~Lex()
{
if (inputStream)
inputStream->release();
}
void Lex::skipWhite()
{
for (;;)
{
while (ptr >= end)
if (!getSegment())
return;
while (ptr < end)
if (lineComment && lineComment [0] == *ptr && match (lineComment, ptr))
{
while (ptr < end && *ptr++ != '\n')
;
++inputStream->lineNumber;
}
else if (commentStart && commentStart [0] == *ptr && match (commentStart, ptr))
{
ptr += strlen (commentStart);
while (ptr < end)
if (commentEnd [0] == *ptr && match (commentEnd, ptr))
{
ptr += strlen (commentEnd);
break;
}
else if (*ptr++ == '\n')
++inputStream->lineNumber;
}
else if (*ptr == continuationChar && ptr [1] == '\n')
{
ptr += 2;
++inputStream->lineNumber;
}
else if (charTable [*ptr] & WHITE)
{
if (*ptr++ == '\n')
{
eol = true;
++inputStream->lineNumber;
}
}
else
return;
}
}
// Just another custom memcmp-like routine.
bool Lex::match(const char *pattern, const char *string)
{
while (*pattern && *string)
if (*pattern++ != *string++)
return false;
return *pattern == 0;
}
void Lex::getToken()
{
priorInputStream = tokenInputStream;
priorLineNumber = tokenLineNumber;
if (tokenType == END_OF_STREAM)
throw AdminException ("expected token, got end-of-file");
eol = false;
skipWhite();
if (tokenInputStream = inputStream)
tokenLineNumber = inputStream->lineNumber;
if (ptr >= end)
{
tokenType = END_OF_STREAM;
strcpy (token, "-end-of-file-");
return;
}
tokenOffset = inputStream->getOffset (ptr);
char *p = token;
char *endToken = token + sizeof (token);
char c = *p++ = *ptr++;
if (charTable [c] & PUNCT)
tokenType = PUNCT;
else if (c == '\'' || c == '"')
{
p = token;
for (;;)
{
if (ptr >= end)
{
if (!getSegment())
throw AdminException ("end of file in quoted string");
}
else if (*ptr == c)
break;
else
{
if (p >= endToken)
throw AdminException ("token overflow in quoted string");
*p++ = *ptr++;
}
}
++ptr;
tokenType = (c == '"') ? QUOTED_STRING : SINGLE_QUOTED_STRING;
}
else if (charTable [c] & DIGIT)
{
tokenType = NUMBER;
while (ptr < end && (charTable [*ptr] & DIGIT))
*p++ = *ptr++;
}
else
{
tokenType = NAME;
if (flags & LEX_upcase)
{
p [-1] = UPCASE(c);
while (ptr < end && !(charTable [*ptr] & (WHITE | PUNCT)))
{
c = *ptr++;
*p++ = UPCASE(c);
}
}
else
while (ptr < end && !(charTable [*ptr] & (WHITE | PUNCT)))
*p++ = *ptr++;
}
*p = 0;
}
void Lex::setCharacters(int type, const char *characters)
{
for (const char *p = characters; *p; ++p)
charTable [*p] |= type;
}
/***
void Lex::openFile(const char *fileName)
{
inputStream = new InputFile (fileName, inputStream);
}
***/
void Lex::setLineComment(const char *string)
{
lineComment = string;
}
void Lex::setCommentString(const char *start, const char *cend)
{
commentStart = start;
commentEnd = cend;
}
bool Lex::isKeyword(const char *word) const
{
return strcmp (token, word) == 0;
}
bool Lex::match(const char *word)
{
if (!isKeyword (word))
return false;
if (*word == captureStart)
captureStuff();
getToken();
return true;
}
JString Lex::reparseFilename()
{
char *p = token;
while (*p)
++p;
while (ptr < end && *ptr != '>' && !(charTable [*ptr] & WHITE))
*p++ = *ptr++;
*p = 0;
JString string = token;
//getToken();
return string;
}
JString Lex::getName()
{
if (tokenType != NAME)
syntaxError ("name");
JString name = token;
getToken();
return name;
}
void Lex::syntaxError(const char *expected)
{
AdminException exception ("expected %s, got \"%s\"", expected, token);
if (tokenInputStream)
exception.setLocation (tokenInputStream->getFileName(), tokenLineNumber);
throw exception;
}
/***
InputFile* Lex::pushFile(const char *fileName)
{
if (inputStream)
inputStream->ptr = ptr;
InputFile *inputFile = new InputFile (fileName, inputStream);
inputStream = inputFile;
ptr = end = NULL;
tokenType = NONE;
return inputFile;
}
***/
void Lex::setContinuationChar(char c)
{
continuationChar = c;
}
void Lex::pushStream(InputStream *stream)
{
stream->addRef();
if (flags & LEX_trace)
{
const char *fileName = stream->getFileName();
if (fileName)
printf ("Opening %s\n", fileName);
}
if (inputStream)
inputStream->ptr = ptr;
stream->prior = inputStream;
inputStream = stream;
ptr = end = NULL;
tokenType = NONE;
}
bool Lex::getSegment()
{
if (!inputStream)
{
tokenType = END_OF_STREAM;
eol = true;
return false;
}
if (!(ptr = inputStream->getSegment()))
{
end = ptr;
InputStream *prior = inputStream->prior;
inputStream->close();
inputStream->release();
if (!(inputStream = prior))
return false;
ptr = inputStream->ptr;
}
end = (ptr) ? inputStream->getEnd() : NULL;
if (end && (flags & LEX_list))
printf (" %s", ptr);
return true;
}
void Lex::captureStuff()
{
stuff.clear();
for (;;)
{
if (ptr >= end)
{
if (!getSegment())
return;
continue;
}
if (*ptr == captureEnd)
return;
stuff.putCharacter (*ptr++);
}
}