/*
* Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005 Yokogawa Electric Corporation,
* YDC Corporation, IPA (Information-technology Promotion Agency, Japan).
* All rights reserved.
*
* Redistribution and use of this software in source and binary forms, with
* or without modification, are permitted provided that the following
* conditions and disclaimer are agreed and accepted by the user:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the names of the copyrighters, the name of the project which
* is related to this software (hereinafter referred to as "project") nor
* the names of the contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* 4. No merchantable use may be permitted without prior written
* notification to the copyrighters. However, using this software for the
* purpose of testing or evaluating any products including merchantable
* products may be permitted without any notification to the copyrighters.
*
*
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHTERS, THE PROJECT AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING
* BUT NOT LIMITED THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHTERS, THE PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT,STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*
* $TAHI: v6eval/lib/Cm/CmLexer.cc,v 1.17 2003/12/04 04:59:47 akisada Exp $
*/
#include <time.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <ctype.h>
#include <sys/param.h>
#include "CmMain.h"
#include "CmMatch.h"
#include "CmLexer.h"
#define sharpComment 1
#define sharpLineNotation 1
#define slashSlashComment 1
#define slashAsteriskComment 1
//----------------------------------------------------------------------
// controls:
// "@" : dynamic debugging YYDEBUG
// "#" : comment sharpComment
// "0" : end of line
// sharpLineNotation
// "/*" : C comment slashAsteriskComment
// "//" : C++ comment slashSlashComment
STR CmLexer::controls(STR s) {
int c=*s;
switch(c) {
#if defined(sharpComment)
case '#': {
return current("");}
#endif
#if defined(YYDEBUG)
case '@': {
STR start=(s=next());
for(;isdigit(c=*s);s=next());
*s=0; int n=atoi(start); *s=c;
DBGFLAGS(n)^=1;
return s;}
#endif
case '/': {
#if defined(slashSlashComment)
if(s[1]=='/') {return current("");}
#endif
#if defined(slashAsteriskComment)
if(s[1]=='*') {return skipComment(next(2));}
#endif
break;}
case 0: {
if((s=getLine())==0) {
return 0;}
#if defined(sharpLineNotation)
s=getLineTag(s);
#endif
return s;}}
return 0;}
//----------------------------------------------------------------------
// SCAN FOR ALPHA NUMERICS
CSTR CmLexer::nameLex(STR& s,CmCString& tmp) {
STR p=s;
int c=0;
for(;isAlnum(c=*p);p=next());
*p=0; tmp=s; *p=c;
s=p;
return tmp.string();}
//----------------------------------------------------------------------
// SCAN FOR NUMERICS
int32_t CmLexer::digitLex(STR& s) {
int c=*s;
int32_t v=0, base, mask;
/**/ if(c!='0') {base=10; mask=eDD_;}
else if((c=*next())=='x'||c=='X') {base=16; mask=eHH_; c=*next();}
else if(c=='b'||c=='B') {base=2; mask=eBB_; c=*next();}
else {base=8; mask=eOO_;}
for(;numTypes_[c&0xff]&mask;c=*next()) {
int32_t n=c<='9'?c-'0':10+(tolower(c)-'a');
v=(v*base)+n;}
s=current();
return v;}
//----------------------------------------------------------------------
// SCAN FOR QUOTED STRING
CSTR CmLexer::stringLex(STR& s,CmCString& tmp) {
STR p=0;
int c0=*s;
int c=0;
int offset=s-buffer(); // Save offset in case buffer grows
for(p=next();(c=*p)&&(c!=c0);p=next()) {
if(c!='\\') continue;
c=*(p=next());
if(c==0||c=='\n') {
p=next(-1);
p=continueGetLine();}}
s=buffer()+offset; // Reset offset just in case buffer grew
*p=0; tmp=s+1; *p=c;
if(!c) {error('E',"unterminated string");}
else {next();}
s=p;
return tmp.string();}
//----------------------------------------------------------------------
// ERROR MESSAGE HANDLING
void CmLexer::eout(CSTR f,int l,char lvl,CSTR fmt,va_list v) {
static CSTR errLevel[5]={
"information","warning","error","sever error","unrecoverable"};
static CSTR errFmt="\"%s\", line %d: %s: ";
int level;
switch(lvl) {
case 'I': level=0; break;
case 'W': level=1; break;
case 'E': level=2; break;
case 'S': level=3; break;
case 'U': level=4; break;
default: level=0; break;}
if(warningSuppress_&&level<=1) return;
char buf[BUFSIZ];
int n=snprintf(buf,sizeof(buf),errFmt,f!=0?f:"",l,errLevel[level]);
n+=vsnprintf(buf+n,sizeof(buf)-n,fmt,v);
CmLexer* lx=CmLexer::instance();
STR s=lx!=0?lx->current():0;
if(s!=0) {
s++; char x=*s; *s=0;
n+=snprintf(buf+n,sizeof(buf)-n," near \'%s\'",lx->buffer()); *s=x;}
snprintf(buf+n,sizeof(buf)-n,"\n");
eoutf(buf);
if(level>=3) exit(level);
if(level>=2) {errorCount_++;}}
void CmLexer::eouts(CSTR f,int l,char lvl,CSTR fmt,...) {
va_list v;
va_start(v,fmt);
eout(f,l,lvl,fmt,v);
va_end(v);}
void CmLexer::error(char lvl,CSTR fmt,...) {
CmLexer* lex=instance();
int l=0;
CSTR s=0;
if(lex!=0) {
l=lex->lineNo();
s=lex->fileName();}
va_list v;
va_start(v,fmt);
eout(s,l,lvl,fmt,v);
va_end(v);}
void CmLexer::uerror(CSTR s,CSTR a) {
if(!errorCount_) error(s[0],&s[2],a);
else error('U',"cannot recover from earlier errors: good bye!");}
//----------------------------------------------------------------------
// CHARACTER CLASSIFICATION
bool CmLexer::isAlpha(int c) {return (isalpha(c)||c=='_');}
bool CmLexer::isAlnum(int c) {return (isalnum(c)||c=='_');}
void CmLexer::initNumTypes() {
int i=0;
for(i=0;i<256;i++) {numTypes_[i]=0;}
for(i='0';i<='1';++i) {numTypes_[i]=eHH_|eDD_|eOO_|eBB_;}
for(i='2';i<='7';++i) {numTypes_[i]=eHH_|eDD_|eOO_;}
for(i='8';i<='9';++i) {numTypes_[i]=eHH_|eDD_;}
for(i='a';i<='f';++i) {numTypes_[i]=eHH_;}
for(i='A';i<='F';++i) {numTypes_[i]=eHH_;}}
void CmLexer::initialize() {
static bool hasBeenHere=false;
if(hasBeenHere) return;
hasBeenHere=true;
initNumTypes();}
//----------------------------------------------------------------------
// ADVANCING THE BUFFER
STR CmLexer::getLine() {
STR s=current(readCompleteLine(0));
if(DBGFLAGS(2)) {puts(s!=0?s:"EOF");}
return s;}
STR CmLexer::continueGetLine() {
STR s=current(readCompleteLine(current()-buffer()));
if(DBGFLAGS(2)) {puts(s!=0?s:"EOF");}
return s;}
STR CmLexer::skipComment(STR s) {
for(;;s=next()) {
for(;*s==0;) {
s=getLine();
if(s==0) {return s;}}
if(s[0]=='*'&&s[1]=='/') {s=next(2); break;}}
return s;}
STR CmLexer::readCompleteLine(int offset) {
bool completeLineRead=false;
int newoffset=offset;
++lineNo_;
// Keep reading until we read a complete line
STR s=fgets(buffer_+newoffset,buffer_size-newoffset,iod_);
if (s) {
do {
if (strlen(buffer_)==(buffer_size-1)) {
if ((buffer_[buffer_size-2]=='\n')||feof(iod_)) {
completeLineRead=true;
}
else {
STR temp=buffer_;
int temp_size=buffer_size;
buffer_size*=2;
buffer_=new char[buffer_size+4];
memcpy(buffer_,temp,temp_size);
delete temp;
newoffset=strlen(buffer_);
fgets(buffer_+newoffset,buffer_size-newoffset,iod_);
}
}
else {
completeLineRead=true;
}
} while (!completeLineRead);
s=buffer_+offset;}
return s;}
//----------------------------------------------------------------------
// if controls shown then rescan from current
STR CmLexer::nextToken() {
STR s=0;
int c=0;
for(;(s=current());){
for(;isspace(c=*s);s=next());
if(!controls(s)) break;}
return current();}
STR CmLexer::getLineTag(STR s) {
CSTR *ps;
int line;
char tmpName[MAXPATHLEN];
for(ps=_tag2Fmts;*ps!=0;ps++)
if(sscanf(s,*ps,&line,tmpName)==2){
fileName(tmpName);
lineNo_=line-1;
return current("");}
for(ps=_tag1Fmts;*ps!=0;ps++)
if(sscanf(s,*ps,&line,tmpName)==1) {
lineNo_=line-1;
return current("");}
return s;}
FILE* CmLexer::open(CSTR s) {
FILE* iod=fopen(s,"r");
if(iod==0) {eoutf(" cannot open %s\n",s);}
return iod;}
void CmLexer::close() {
if(iod_!=0) {fclose(iod_);}
iod_=0; lineNo_=0; current_=0; fileName_=0;}
void CmLexer::fileName(CSTR s) {
CmString tmp(s);
CmString* name=nameSet_.find(&tmp);
if(name==0) {
name=new CmCString(s);
nameSet_.add(name);}
fileName_=name->string();}
CmLexer::CmLexer(CSTR s):iod_(0),current_(0),buffer_(0),buffer_size(BUFSIZ),lineNo_(0),fileName_(0) {
fileName(s);
buffer_=new char[buffer_size+4];
buffer_[0]=0;
current_=buffer_;
iod_=s!=0?open(s):stdin;
instance_=this;
if(iod_==0) {exit(1);}}
CmLexer::~CmLexer() {
delete buffer_;
close();
instance_=0;}
bool CmLexer::eof() {return (feof(iod_));}
CSTR CmLexer::_tag2Fmts[]={
"# %d \"%[^\"]\"",
"# line %d \"%s[^\"]\"",
"#%d \"%s[^\"]\"",
"#line %d \"%s[^\"]\"",
0};
CSTR CmLexer::_tag1Fmts[]={
"# %d",
"#%d",
"# line %d",
"#line %d",
0};
uint32_t CmLexer::errorCount_=0;
uint32_t CmLexer::warningSuppress_=0;
char CmLexer::numTypes_[256];
CmLexer* CmLexer::instance_=0;
StringSet CmLexer::nameSet_;
syntax highlighted by Code2HTML, v. 0.9.1