sstyle_f.c

来自「开放源码的编译器open watcom 1.6.0版的源代码」· C语言 代码 · 共 552 行

C
552
字号
/****************************************************************************
*
*                            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:  WHEN YOU FIGURE OUT WHAT THIS FILE DOES, PLEASE
*               DESCRIBE IT HERE!
*
****************************************************************************/


#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <assert.h>
#include "vi.h"
#include "sstyle.h"
#include "lang.h"


/*----- LOCALS -----*/
static int          firstChar;
static linenum      thisLine;
static ss_flags_f   flags;

enum getFloatCommands {
    AFTER_DOT,
    AFTER_EXP,
    BADTEXT,
};

static int issymbol( int c )
{
    /* symbol list taken from Watcom Fortran 77 Lang Ref. pg 3
    */
    if( c == '=' ||
        c == '+' ||
        c == '-' ||
        c == '*' ||
        c == '/' ||
        c == '(' ||
        c == ')' ||
        c == ',' ||
        c == '.' ||
        c == '$' ||
        c == ':' ||
        c == '%' ||
        c == '\\' ) {
        return( 1 );
    } else {
        return( 0 );
    }
}

static int iscomment( int c )
{
    if( c == '!' ||
        c == 'c' ||
        c == 'C' ||
        c == 'd' ||
        c == 'D' ||
        c == '*' ) {
        return( 1 );
    } else {
        return( 0 );
    }
}

static int islogical( char *string )
{
    if( !strnicmp( string, ".ne.", 4 ) ||
        !strnicmp( string, ".eq.", 4 ) ||
        !strnicmp( string, ".ge.", 4 ) ||
        !strnicmp( string, ".le.", 4 ) ||
        !strnicmp( string, ".lt.", 4 ) ||
        !strnicmp( string, ".gt.", 4 ) ||
        !strnicmp( string, ".or.", 4 )
        ){
        return( 4 );
    } else if ( !strnicmp( string, ".and.", 5 ) ||
                !strnicmp( string, ".xor.", 5 ) ||
                !strnicmp( string, ".not.", 5 )
              ) {
        return( 5 );
    } else {
        return ( 0 );
    }
}

static bool isInitialLine( line *line )
{
    char    *data;
    if( line->len < 6 ) {
        return( TRUE );
    }
    data = ( line->inf.ld.nolinedata ) ? WorkLine->data : line->data;
    if( isspace( data[ 5 ] ) ||
        data[ 5 ] == '0' ) {
        return( TRUE );
    } else {
        return( FALSE );
    }
}

void InitFORTRANLine( char *text, linenum line_no )
{
    firstChar = *text;
    thisLine = line_no;
}

static void getFloat( ss_block *ss_new, char *start, int skip, int command )
{
    char    *text = start + skip;

    ss_new->type = SE_FLOAT;

    switch( command ) {
        case AFTER_DOT:
            if( !isdigit( *text ) ) {
                if( *text == 'E' || *text == 'D' ) {
                    getFloat( ss_new, start, text - start + 1, AFTER_EXP );
                    return;
                }
                if( *text && !isspace( *text ) && !issymbol( *text ) ) {
                    if( *text ) text++;
                    ss_new->type = SE_INVALIDTEXT;
                }
                break;
            }
            text++;
            while( isdigit( *text ) ) {
                text++;
            }
            if( *text != 'E' && *text != 'D' ) {
                break;
            }
            text++;
            // fall through
        case AFTER_EXP:
            if( *text == '+' || *text == '-' ) {
                text++;
            }
            if( !isdigit( *text ) ) {
                if( *text ) text++;
                ss_new->type = SE_INVALIDTEXT;
                break;
            }
            text++;
            while( isdigit( *text ) ) {
                text++;
            }
            if( *text && !isspace( *text ) && !issymbol( *text ) ) {
                ss_new->type = SE_INVALIDTEXT;
                text++;
            }
    }
    ss_new->len = text - start;
}


static void getNumber( ss_block *ss_new, char *start )
{
    char    *text = start + 1;
    char    save_char;
    char    *save_loc;
    int     nchars;

    while( isdigit( *text ) ) {
        text++;
    }

    switch( *text ) {
        case 'h':
        case 'H':
            /* Hollerith constant (string)
            */
            save_loc = text;
            save_char = *text;
            *text = 0;
            nchars = atoi( start );
            text++;
            while( *text && nchars != 0 ) {
                nchars--;
                text++;
            }
            if( *text == '\0' && nchars > 0 ) {
                ss_new->type = SE_INVALIDTEXT;
            } else {
                ss_new->type = SE_STRING;
            }
            *save_loc = save_char;
            break;
        case '.':
            getFloat( ss_new, start, text - start + 1, AFTER_DOT );
            return;
        case 'E':
        case 'D':
            getFloat( ss_new, start, text - start + 1, AFTER_EXP );
            return;
        default:
            ss_new->type = SE_INTEGER;
    }
    ss_new->len = text - start;
}

static void getWhiteSpace( ss_block *ss_new, char *start )
{
    char    *text = start + 1;
    while( isspace( *text ) ) {
        text++;
    }
    ss_new->type = SE_WHITESPACE;
    ss_new->len = text - start;
}


static void getText( ss_block *ss_new, char *start )
{
    char    keyword[ MAX_INPUT_LINE + 1 ];
    char    *text = start;
    int     index = 0;

    // eliminate leading spaces
    while( isspace( *text ) ) text++;

    // take copy string up to first white space
    while( isalnum( *text ) ||
           ( *text == '_' ) || ( *text == '$' ) ) {
        keyword[ index++ ] = toupper( *text );
        text++;
    }
    keyword[ index ] = '\0';

    // test if string is keyword
    if( IsKeyword( keyword, TRUE ) ) {
        char *end = text;

        ss_new->type = SE_KEYWORD;

        // attempt to find a "*" associated with type
        while( isspace( *text ) ) {
            text++;
        }
        if( *text == '*' ){
            text++;
        } else {
            text = end;
        }
    } else {
        ss_new->type = SE_IDENTIFIER;
    }

    ss_new->len = text - start;
}


static void getSymbol( ss_block *ss_new, int length )
{
    ss_new->type = SE_SYMBOL;
    ss_new->len = length;
}

static void getLiteral( ss_block *ss_new, char *start, int skip )
{
    char    *text = start + skip;
    char    lastchar = '\0';
    bool    empty = TRUE;
    bool    multiLine = flags.inString;
    line    *line;
    fcb     *fcb;
    char    *data;
    int     rc;
squashed:
    while( ( *text ) && ( *text != '\'' ) ) {
        empty = FALSE;
        text++;
    }
    flags.inString = FALSE;
    if( *text == '\0' ) {
        // if next line a continuation line, then flag flags.inString, else
        // flag unterminated string
        rc = CGimmeLinePtr( thisLine + 1, &fcb, &line );
        while( 1 ) {
            if( rc != ERR_NO_ERR ) {
                break;
            }
            data = ( line->inf.ld.nolinedata ) ? WorkLine->data : line->data;
            if( !iscomment( data[ 0 ] ) ) {
                break;
            }
            rc = CGimmeNextLinePtr( &fcb, &line );
        }
        ss_new->type = SE_INVALIDTEXT;
        if( rc == ERR_NO_ERR && !isInitialLine( line ) ) {
            ss_new->type = SE_STRING;
            flags.inString = TRUE;
        }
    } else {
        text++;
        lastchar = tolower( *text );
        switch( lastchar ) {
            case '\'':
                text++;
                empty = FALSE;
                goto squashed;
            case 'c':
                text++;
                ss_new->type = SE_STRING;
                break;
            case 'x':
                text++;
                ss_new->type = SE_HEX;
                break;
            case 'o':
                text++;
                ss_new->type = SE_OCTAL;
                break;
            default:
                // hard to say if invalid or not - take a guess
                if( islower( *text ) ) {
                    text++;
                    ss_new->type = SE_INVALIDTEXT;
                } else {
                    ss_new->type = SE_STRING;
                }
                break;
        }
    }
    ss_new->len = text - start;
    if( empty == TRUE && multiLine == FALSE ) {
        ss_new->type = SE_INVALIDTEXT;
    }
}

static void getComment( ss_block *ss_new, char *start )
{
    char    *text = start + 1;
    while( *text ) {
        text++;
    }
    ss_new->type = SE_COMMENT;
    ss_new->len = text - start;
}

static void getBeyondText( ss_block *ss_new )
{
    ss_new->type = SE_WHITESPACE;
    ss_new->len = BEYOND_TEXT;
}

static void getInvalidChar( ss_block *ss_new )
{
    ss_new->type = SE_INVALIDTEXT;
    ss_new->len = 1;
}

static void getLabelOrWS( ss_block *ss_new, char *start, int text_col )
{
    char    *text = start;
    while( isspace( *text ) && text_col <= 4 ) {
        text++;
        text_col++;
    }
    if( *text && text_col <= 4 ) {
        ss_new->type = SE_JUMPLABEL;
        while( *text && text_col <= 4 ) {
            if( !isdigit( *text ) && !isspace( *text ) ) {
                text++;
                ss_new->type = SE_INVALIDTEXT;
                break;
            }
            text++;
            text_col++;
        }
        ss_new->len = text - start;
    } else {
        getWhiteSpace( ss_new, start );
    }
}

static void getContinuationOrWS( ss_block *ss_new, char *start )
{
    if( isspace( *start ) ) {
        getWhiteSpace( ss_new, start );
        return;
    }
    /* this is technically wrong - a ' ' on an initial line is
     * also a label, but that would be ugly
     */
    ss_new->type = SE_JUMPLABEL;
    ss_new->len = 1;
}

void InitFORTRANFlagsGivenValues( ss_flags_f *newFlags )
{
    flags = *newFlags;
}

void GetFORTRANFlags( ss_flags_f *storeFlags )
{
    *storeFlags = flags;
}

void InitFORTRANFlags( linenum line_no )
{
    char    *text;
    char    *start;
    line    *line;
    fcb     *fcb;
    int     rc;
    int     numQuotes = 0;

    flags.inString = 0;

    rc = CGimmeLinePtr( line_no, &fcb, &line );
    if( rc != ERR_NO_ERR ) {
        // probably past eof
        return;
    }

    if( isInitialLine( line ) ) {
        return;
    }

    while( 1 ) {
        rc = GimmePrevLinePtr( &fcb, &line );
        if( rc != ERR_NO_ERR ) {
            break;
        }
        text = ( line->inf.ld.nolinedata ) ? WorkLine->data : line->data;
        start = text;
        if( iscomment( *text ) ) {
            continue;
        }
        while( *text ) {
            if( *text == '!' ) {
                // rest of line is part of a comment
                break;
            } else if( *text == '\'' ) {
                numQuotes ^= 1;
            }
            text++;
        }
        if( isInitialLine( line ) ) {
            break;
        }
    }

    if( numQuotes == 1 ) {
        flags.inString = TRUE;
    }
}

void GetFORTRANBlock( ss_block *ss_new, char *start, int text_col )
{
    int length=0;
    if( start[ 0 ] == '\0' ) {
        if( text_col == 0 ) {
            // line is empty -
            // do not flag following line as having anything to do
            // with an unterminated string from previous line
            flags.inString = FALSE;
        }
        getBeyondText( ss_new );
        return;
    }

    if( iscomment( firstChar ) ) {
        getComment( ss_new, start );
        return;
    }

    if( text_col <= 4 ) {
        getLabelOrWS( ss_new, start, text_col );
        return;
    }

    if( text_col == 5 ) {
        getContinuationOrWS( ss_new, start );
        return;
    }

    if( flags.inString ) {
        getLiteral( ss_new, start, 0 );
        return;
    }

    if( isspace( start[ 0 ] ) ) {
        getWhiteSpace( ss_new, start );
        return;
    }

    switch( start[ 0 ] ) {

        case '!':
            getComment( ss_new, start );
            return;
        case '\'':
            getLiteral( ss_new, start, 1 );
            return;
        case '.':
            if( isdigit( start[ 1 ] ) ) {
                getFloat( ss_new, start, 1, AFTER_DOT );
                return;
            }
            length = islogical( start );
            if( length > 0 ){
                getSymbol( ss_new, length );
                return;
            }
    }

    if( issymbol( start[ 0 ] ) ) {
        getSymbol( ss_new, 1 );
        return;
    }

    if( isdigit( *start ) ) {
        getNumber( ss_new, start );
        return;
    }

    if( isalpha( *start ) || ( *start == '_' ) || ( *start == '$' ) ) {
        getText( ss_new, start );
        return;
    }

    getInvalidChar( ss_new );
}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?