csselect.c
来自「开放源码的编译器open watcom 1.6.0版的源代码」· C语言 代码 · 共 311 行
C
311 行
/****************************************************************************
*
* 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: processing for SELECT, CASE, OTHERWISE, and ENDSELECT
*
****************************************************************************/
#include "ftnstd.h"
#include "errcod.h"
#include "global.h"
#include "opr.h"
#include "fmemmgr.h"
#include "recog.h"
#include "types.h"
#include "ferror.h"
#include "utility.h"
#include <limits.h>
extern void AddCSNode(byte);
extern void DelCSNode(void);
extern void CSNoMore(void);
extern void Match(void);
extern void CSExtn(void);
extern void ColonLabel(void);
extern label_id NextLabel(void);
extern void GLabel(label_id);
extern void FiniSelect(void);
extern void InitSelect(void);
extern void GBranch(label_id);
extern void FreeLabel(label_id);
case_entry *NewCase(void) {
//==========================
case_entry *ptr;
ptr = FMemAlloc( sizeof( case_entry ) );
ptr->label.g_label = 0;
ptr->low = 0;
ptr->high = 0;
ptr->link = NULL;
ptr->multi_case = FALSE;
return( ptr );
}
void CpSelect(void) {
//==================
// Compile a SELECT statement.
Remember.slct = TRUE;
CSExtn();
AddCSNode( CS_SELECT );
CSHead->branch = NextLabel();
CSHead->bottom = NextLabel();
CSHead->cs_info.cases = NewCase();
if( RecKeyWord( "CASE" ) ) {
AdvanceITPtr();
} else {
ReqNOpn();
AdvanceITPtr();
}
ReqOpenParen();
if( !RecEOS() ) { // consider: SELECT
SelectExpr();
CSHead->cs_info.cases->sel_type = CITNode->typ;
} else {
CSHead->cs_info.cases->sel_type = TY_NO_TYPE;
}
InitSelect();
AdvanceITPtr();
ReqCloseParen();
if( !RecKeyWord( "FROM" ) ) {
ReqNOpn();
}
AdvanceITPtr();
ColonLabel();
}
void CpCase(void) {
//================
// Compile a CASE statement.
if( RecKeyWord( "DEFAULT" ) ) {
AdvanceITPtr();
CpOtherwise();
} else {
if( CSHead->typ == CS_SELECT ) {
CaseHandler();
} else if( CSHead->typ == CS_CASE ) {
GBranch( CSHead->bottom );
CaseHandler();
} else if( CSHead->typ == CS_OTHERWISE ) {
Error( SP_OTHERWISE_LAST );
} else {
Match();
}
}
}
static intstar4 MinCaseValue( TYPE typ ) {
//================================================
// Get a value for case expression.
if( _IsTypeInteger( typ ) ) {
return( LONG_MIN );
} else { // if( typ = TY_CHAR ) {
return( 0 );
}
}
static intstar4 MaxCaseValue( TYPE typ ) {
//================================================
// Get a value for case expression.
if( _IsTypeInteger( typ ) ) {
return( LONG_MAX );
} else { // if( typ = TY_CHAR ) {
return( 255 );
}
}
static intstar4 CaseValue(void) {
//===================================
// Get a value for case expression.
if( _IsTypeInteger( CITNode->typ ) ) {
return( ITIntValue( CITNode ) );
} else if( _IsTypeLogical( CITNode->typ ) ) {
return( _LogValue( CITNode->value.logstar1 ) );
} else { // if( CITNode->typ = TY_CHAR ) {
return( *CITNode->value.cstring.strptr );
}
}
static void CaseHandler(void) {
//=============================
label_id label;
case_entry *link;
case_entry *kase;
intstar4 low;
intstar4 high;
bool case_ok;
bool multi_case;
CSHead->typ = CS_CASE;
label = NextLabel();
GLabel( label );
if( ReqNOpn() ) { // consider: CASE 10
AdvanceITPtr();
}
multi_case = FALSE;
ReqOpenParen();
for(;;) {
if( _IsTypeLogical( CSHead->cs_info.cases->sel_type ) ) {
// no range allowed for LOGICAL select expressions
case_ok = ConstExpr( CSHead->cs_info.cases->sel_type );
if( case_ok ) {
low = CaseValue();
high = low;
}
AdvanceITPtr();
} else {
if( RecNOpn() && RecNextOpr( OPR_COL ) ) {
low = MinCaseValue( CSHead->cs_info.cases->sel_type );
AdvanceITPtr();
case_ok = ConstExpr( CSHead->cs_info.cases->sel_type );
if( case_ok ) {
high = CaseValue();
}
AdvanceITPtr();
} else {
case_ok = ConstExpr( CSHead->cs_info.cases->sel_type );
if( case_ok ) {
low = CaseValue();
high = low;
}
AdvanceITPtr();
if( RecColon() ) {
if( RecNOpn() &&
( RecNextOpr( OPR_RBR ) || RecNextOpr( OPR_COM ) ) ) {
high = MaxCaseValue( CSHead->cs_info.cases->sel_type );
} else {
case_ok &= ConstExpr( CSHead->cs_info.cases->sel_type );
if( case_ok ) {
high = CaseValue();
}
}
AdvanceITPtr();
}
}
}
if( case_ok ) {
if( high < low ) {
Error( SP_NEVER_CASE );
} else {
kase = CSHead->cs_info.cases;
while( kase->link != NULL ) {
if( kase->link->low > high ) break;
kase = kase->link;
}
if( ( kase != CSHead->cs_info.cases ) &&
( kase->high >= low ) ) {
Error( SP_CASE_OVERLAP );
} else {
link = kase->link;
kase->link = NewCase();
kase = kase->link;
kase->link = link;
kase->label.g_label = label;
kase->high = high;
kase->low = low;
kase->multi_case = multi_case;
multi_case = TRUE;
}
}
}
if( !RecComma() ) break;
}
ReqCloseParen();
ReqNOpn();
AdvanceITPtr();
ReqEOS();
CSHead->block = ++BlockNum;
}
void CpOtherwise(void) {
//=====================
// Compile an OTHERWISE statement.
if( (CSHead->typ == CS_CASE) || (CSHead->typ == CS_SELECT) ) {
GBranch( CSHead->bottom );
CSHead->typ = CS_OTHERWISE;
CSHead->cs_info.cases->label.g_label = NextLabel();
CSHead->cs_info.cases->multi_case = FALSE;
GLabel( CSHead->cs_info.cases->label.g_label );
CSHead->block = ++BlockNum;
} else if( CSHead->typ == CS_OTHERWISE ) {
Error( SP_OTHERWISE_LAST );
} else {
Match();
}
CSNoMore();
}
void CpEndSelect(void) {
//=====================
// Compile an ENDSELECT statement.
GBranch( CSHead->bottom );
if( CSHead->typ == CS_SELECT ) {
Error( SP_EMPTY_SELECT );
} else if( CSHead->typ == CS_CASE ) {
CSHead->cs_info.cases->label.g_label = CSHead->bottom;
FiniSelect();
} else if( CSHead->typ == CS_OTHERWISE ) {
FiniSelect();
} else {
Match();
}
GLabel( CSHead->bottom );
// the bottom label will be freed as the default case when no default
// case has been specified
if( CSHead->typ != CS_CASE ) {
FreeLabel( CSHead->bottom );
}
FreeLabel( CSHead->branch );
DelCSNode();
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?