📄 scan.c
字号:
/****************************************************************************
*
* Open Watcom Project
*
* Portions Copyright (c) 1983-2002 Sybase, Inc. All Rights Reserved.
*
* ========================================================================
*
* This file contains Original Code and/or Modifications of Original
* Code as defined in and that are subject to the Sybase Open Watcom
* Public License version 1.0 (the 'License'). You may not use this file
* except in compliance with the License. BY USING THIS FILE YOU AGREE TO
* ALL TERMS AND CONDITIONS OF THE LICENSE. A copy of the License is
* provided with the Original Code and Modifications, and is also
* available at www.sybase.com/developer/opensource.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND SYBASE AND ALL CONTRIBUTORS HEREBY DISCLAIM
* ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR
* NON-INFRINGEMENT. Please see the License for the specific language
* governing rights and limitations under the License.
*
* ========================================================================
*
* Description: Lexical scanner, Windows RC version.
*
****************************************************************************/
#include <ctype.h>
#include <string.h>
#include "varstr.h"
#include "rctypes.h"
#include "global.h"
#include "rcio.h"
#include "rcmem.h"
#include "errors.h"
#include "ytab.gh"
#include "scan.h"
#include "keyword.h"
#include "depend.h"
//#include "rcdll.h"
#include "errprt.h"
#ifdef SCANDEBUG
#define DEBUGPUTS(s) PutScanString(s);
static void PutScanString( const char *string )
{
if( CmdLineParms.DebugScanner && string != NULL ) {
RcFprintf( stdout, NULL, "%s\n", string );
}
} /* PutScanString */
#else
#define DEBUGPUTS(s)
#endif
/*** Macros to implement the parts of a finite state machine ***/
/* change_state changes states without reading a character */
static int _next;
static int LookAhead;
static int longString;
static int newLineInString = 0;
static int ScanDFA( ScanValue *value );
static void GetNextChar( void )
{
while( 1 ) {
LookAhead = _next;
if( LookAhead != RC_EOF ) {
_next = RcIoGetChar();
if( LookAhead == '\\' && _next == '\n' ) {
_next = RcIoGetChar();
continue;
}
}
break;
}
} /* GetNextChar */
static void CharInit( void )
{
_next = RcIoGetChar();
GetNextChar();
} /* CharInit */
#define state(s) s
#define do_transition(s) GetNextChar(); goto s
#define change_state(s) goto s
#define enter_start_state CharInit()
static void AddDigitToInt( long *value, int base, int newchar )
{
int newdigit;
if( isdigit(newchar) ) {
newdigit = newchar - '0';
} else { /* assume it is a hex digit */
newdigit = toupper(newchar) - 'A' + 10;
}
*value = *value * base + newdigit;
} /* AddDigitToInt */
static int ScanCPPDirective( ScanValue *value )
/*********************************************/
/* This function takes the correct action for the #line directive and returns */
/* the token following the preprocessor stuff. It uses Scan to do it's */
/* scanning. DON'T call this function from within Scan or the functions it */
/* calls unless you are very careful about recurtion. */
{
int token;
int linenum;
if( StopInvoked ) {
RcFatalError( ERR_STOP_REQUESTED );
}
/* get the "line" or "pragma" directive */
token = ScanDFA( value );
if( token != Y_NAME ) {
RcFatalError( ERR_INVALID_CPP );
}
if( stricmp( value->string.string, "line" ) == 0 ) {
RcMemFree( value->string.string );
/* get the line number */
token = ScanDFA( value );
if( token != Y_INTEGER ) {
RcFatalError( ERR_INVALID_CPP_LINE );
}
RcMemFree( value->intinfo.str );
value->intinfo.str = NULL;
linenum = value->intinfo.val;
/* get the filename if there is one */
token = ScanDFA( value );
if( token == Y_STRING ) {
RcIoSetLogicalFileInfo( linenum, value->string.string );
if( AddDependency( value->string.string ) ) {
ErrorHasOccured = TRUE;
}
RcMemFree( value->string.string );
token = ScanDFA( value );
} else {
RcIoSetLogicalFileInfo( linenum, NULL );
}
} else if( stricmp( value->string.string, "pragma" ) == 0 ) {
RcMemFree( value->string.string );
token = Y_POUND_PRAGMA;
} else if( stricmp( value->string.string, "error" ) == 0 ) {
char buf[80];
unsigned i;
i = 0;
while( LookAhead != '\n' && LookAhead != RC_EOF ) {
buf[i] = LookAhead;
i ++;
GetNextChar();
}
buf[i] = '\0';
RcFatalError( ERR_TEXT_FROM_CPP, buf );
} else {
RcFatalError( ERR_INVALID_CPP );
}
return( token );
} /* ScanCPPDirective */
extern void ScanInit( void )
/**************************/
{
enter_start_state;
} /* ScanInit */
static int ScanDFA( ScanValue * value )
/*************************************/
{
long newint; /* these are used to accumulate parts of */
VarString *newstring; /* a new value */
int token;
#ifdef SCANDEBUG
char debugstring[10];
#endif
char *stringFromFile;
value->intinfo.type = SCAN_INT_TYPE_DEFAULT;
value->string.string = NULL;
longString = FALSE;
state(S_START):
if( isspace(LookAhead) ) {
do_transition( S_START );
} else if( isdigit(LookAhead) ) {
newint = LookAhead - '0';
newstring = VarStringStart();
VarStringAddChar( newstring, LookAhead );
if( LookAhead == '0' ) {
do_transition( S_HEXSTART );
} else {
do_transition( S_DECIMAL );
}
} else if( isalpha(LookAhead) || LookAhead == '_' ) {
newstring = VarStringStart();
VarStringAddChar( newstring, LookAhead );
if( LookAhead == 'l' || LookAhead == 'L' ) {
do_transition( S_L_STRING );
}
do_transition( S_NAME );
} else switch (LookAhead) {
case '"':
newstring = VarStringStart(); /* don't include the " */
newLineInString = 0; /* reset newline in string status */
do_transition( S_STRING );
case '.':
newstring = VarStringStart();
VarStringAddChar( newstring, LookAhead );
do_transition( S_DOS_FILENAME );
case RC_EOF:
DEBUGPUTS("RC_EOF")
return( 0 ); /* yacc wants 0 on EOF */
case '#': do_transition( S_POUND_SIGN );
case '(': do_transition( S_LPAREN );
case ')': do_transition( S_RPAREN );
case '[': do_transition( S_LSQ_BRACKET );
case ']': do_transition( S_RSQ_BRACKET );
case '{': do_transition( S_LBRACE );
case '}': do_transition( S_RBRACE );
case '+': do_transition( S_PLUS );
case '-': do_transition( S_MINUS );
case '~': do_transition( S_BITNOT );
case '!': do_transition( S_NOT );
case '*': do_transition( S_TIMES );
case '/': do_transition( S_DIVIDE );
case '%': do_transition( S_MOD );
case '>': do_transition( S_GT );
case '<': do_transition( S_LT );
case '=': do_transition( S_EQ );
case '&': do_transition( S_BITAND );
case '^': do_transition( S_BITXOR );
case '|': do_transition( S_BITOR );
case '?': do_transition( S_QUESTION );
case ':': do_transition( S_COLON );
case ',': do_transition( S_COMMA );
case ';': do_transition( S_COMMENT );
case '\\':
newstring = VarStringStart();
VarStringAddChar( newstring, '\\' );
VarStringAddChar( newstring, LookAhead );
do_transition( S_DOS_FILENAME );
default:
value->UnknownChar = LookAhead;
do_transition( S_ERROR );
}
state(S_L_STRING):
if( LookAhead =='"' ) {
longString = TRUE;
RcMemFree( VarStringEnd( newstring, NULL ) );
change_state( S_START );
} else {
change_state( S_NAME );
}
state(S_ERROR):
ErrorHasOccured = TRUE;
return( Y_SCAN_ERROR );
state(S_COMMENT):
if( LookAhead == '\n' || LookAhead == RC_EOF ) {
do_transition( S_START );
} else {
do_transition( S_COMMENT );
}
state(S_POUND_SIGN):
DEBUGPUTS( "#" )
return( Y_POUND_SIGN );
state(S_LPAREN):
DEBUGPUTS( "(" )
return( Y_LPAREN );
state(S_RPAREN):
DEBUGPUTS( ")" )
return( Y_RPAREN );
state( S_LSQ_BRACKET ):
DEBUGPUTS( "[" )
return( Y_LSQ_BRACKET );
state( S_RSQ_BRACKET ):
DEBUGPUTS( "]" )
return( Y_RSQ_BRACKET );
state(S_LBRACE):
DEBUGPUTS( "{" )
return( Y_LBRACE );
state(S_RBRACE):
DEBUGPUTS( "}" )
return( Y_RBRACE );
state(S_PLUS):
DEBUGPUTS( "+" )
return( Y_PLUS );
state(S_MINUS):
DEBUGPUTS( "-" )
return( Y_MINUS );
state(S_BITNOT):
DEBUGPUTS( "~" )
return( Y_BITNOT );
state(S_NOT):
if( LookAhead == '=' ) {
do_transition( S_NE );
} else {
DEBUGPUTS( "!" )
return( Y_NOT );
}
state(S_TIMES):
DEBUGPUTS( "*" )
return( Y_TIMES );
state(S_DIVIDE):
DEBUGPUTS( "/" )
return( Y_DIVIDE );
state(S_MOD):
DEBUGPUTS( "%" )
return( Y_MOD );
state(S_GT):
switch (LookAhead) {
case '>': do_transition( S_SHIFTR );
case '=': do_transition( S_GE );
default:
DEBUGPUTS( ">" )
return( Y_GT );
}
state(S_LT):
switch (LookAhead) {
case '<': do_transition( S_SHIFTL );
case '=': do_transition( S_LE );
default:
DEBUGPUTS( "<" )
return( Y_LT );
}
state(S_EQ):
if( LookAhead == '=' ) {
do_transition( S_ENDEQ );
} else {
DEBUGPUTS( "=" )
return( Y_SINGLE_EQ );
}
state(S_BITAND):
if( LookAhead == '&' ) {
do_transition( S_AND );
} else {
DEBUGPUTS( "&" )
return( Y_BITAND );
}
state(S_BITXOR):
DEBUGPUTS( "^" )
return( Y_BITXOR );
state(S_BITOR):
if( LookAhead == '|' ) {
do_transition( S_OR );
} else {
DEBUGPUTS( "|" )
return( Y_BITOR );
}
state(S_QUESTION):
DEBUGPUTS( "?" )
return( Y_QUESTION );
state(S_COLON):
DEBUGPUTS( ":" )
return( Y_COLON );
state(S_COMMA):
DEBUGPUTS( "," )
return( Y_COMMA );
state(S_NE):
DEBUGPUTS( "!=" )
return( Y_NE );
state(S_SHIFTR):
DEBUGPUTS( ">>" )
return( Y_SHIFTR );
state(S_GE):
DEBUGPUTS( ">=" )
return( Y_GE );
state(S_SHIFTL):
DEBUGPUTS( "<<" )
return( Y_SHIFTL );
state(S_LE):
DEBUGPUTS( "<=" )
return( Y_LE );
state(S_ENDEQ):
DEBUGPUTS( "==" )
return( Y_EQ );
state(S_AND):
DEBUGPUTS( "&&" )
return( Y_AND );
state(S_OR):
DEBUGPUTS( "||" )
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -