gentable.c

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

C
390
字号
/****************************************************************************
*
*                            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 <stdlib.h>
#include <limits.h>
#include "yacc.h"
#include "alloc.h"

#define INFINITY        32767

#define Token(c)        ((c).token)
#define SetToken(c,i)   ((c).token = (i))
#define IsUsed(c)       ((c).action&0x4000)
#define Action(c)       ((c).action&0x3fff)
#define SetAction(c,i)  ((c).action |= (0x4000|(i)))
#define IsBase(c)       ((c).action&0x8000)
#define SetBase(c)      ((c).action |= 0x8000)
#define roundup(a,b)    ((((a)+(b)-1)/(b))*(b))

#define BLOCK           512

static int addtotable(  short *token,
                        short *s,
                        short *action,
                        short default_token,
                        short parent_token );

typedef struct a_table {
    short       token, action;
} a_table;

static int avail, used;
static a_table *table;

void genobj( void )
{
    value_size token_size;
    short *token, *action, *base, *other, *parent, *size;
    register short *p, *q, *r, *s;
    short error, tokval, redun, *same, *diff, *test, *best;
    a_sym *sym;
    a_pro *pro;
    an_item *item;
    a_state *x;
    a_shift_action *tx;
    a_reduce_action *rx;
    int i, j, savings, min, ntoken, dtoken, ptoken;
    unsigned new_action, shift;
    unsigned parent_base;
    unsigned num_default, num_parent;

    if( fastflag ) {
        GenFastTables();
        return;
    }
    if( bigflag || compactflag ) {
        token_size = FITS_A_WORD;
    } else {
        token_size = FITS_A_BYTE;
    }
    num_default = num_parent = 0;
    ntoken = MaxTerminalTokenValue();
    dtoken = ++ntoken;
    ptoken = ++ntoken;
    for( i = nterm; i < nsym; ++i ) {
        symtab[i]->token = ++ntoken;
    }
    ++ntoken;

    error = nstate + npro;
    action = CALLOC( ntoken, short );
    for( i = 0; i < ntoken; ++i ) {
        action[i] = error;
    }
    token = CALLOC( ntoken, short );
    test = CALLOC( ntoken, short );
    best = CALLOC( ntoken, short );
    base = CALLOC( nstate, short );
    other = CALLOC( nstate, short );
    parent = CALLOC( nstate, short );
    size = CALLOC( nstate, short );
    same = r = diff = NULL;
    shift = parent_base = 0;
    for( i = nstate; --i >= 0; ) {
        x = statetab[i];
        q = token;
        for( tx = x->trans; (sym = tx->sym); ++tx ) {
            action[*q++ = sym->token] = tx->state->sidx;
        }
        savings = 0;
        for( rx = x->redun; (pro = rx->pro); ++rx ) {
            redun = pro->pidx + nstate;
            p = Members( rx->follow, setmembers );
            if( p - setmembers > savings ) {
                savings = p - setmembers;
                r = q;
            }
            while( --p >= setmembers ) {
                tokval = symtab[*p]->token;
                action[*q++ = tokval] = redun;
            }
        }
        if( savings ) {
            tokval = other[i] = action[*r];
            action[*q++ = dtoken] = tokval;
            p = r;
            while( --savings >= 0 )
                action[*p++] = error;
            while( p < q )
                *r++ = *p++;
            q = r;
            ++ num_default;
        } else
            other[i] = error;
        r = q;
        min = size[i] = r - token;
        parent[i] = nstate;
        for( j = nstate; --j > i; ) {
            if( abs( size[j] - size[i] ) < min ) {
                x = statetab[j];
                q = (p = test) + ntoken;
                for( tx = x->trans; (sym = tx->sym); ++tx )
                    if( action[sym->token] == tx->state->sidx )
                       *p++ = sym->token;
                    else
                       *--q = sym->token;
                for( rx = x->redun; (pro = rx->pro); ++rx ) {
                    if( (redun = pro->pidx + nstate) == other[j] )
                        redun = error;
                    s = Members( rx->follow, setmembers );
                    while( --s >= setmembers ) {
                        tokval = symtab[*s]->token;
                        if( action[tokval] == redun )
                            *p++ = tokval;
                        else
                            *--q = tokval;
                    }
                }
                if( other[j] != error ) {
                    if( other[j] == other[i] )
                        *p++ = dtoken;
                    else
                        *--q = dtoken;
                }
                savings = size[i] + size[j] - 2*(p - test);
                if( savings < min ) {
                    min = savings;
                    same = p;
                    diff = q;
                    s = test;  test = best;  best = s;
                    parent[i] = j;
                }
            }
        }
        if( min >= size[i] )
            s = r;
        else {
            ++ num_parent;
            s = token;
            p = same;
            while( --p >= best )
                action[*p] = error;
            for( q = token; q < r; ++q )
                if( action[*q] != error )
                    *s++ = *q;
            p = best + ntoken;
            while( --p >= diff )
                if( action[*p] == error )
                    *s++ = *p;
            tokval = parent[i];
            action[*s++ = ptoken] = tokval;
        }
        base[i] = addtotable( token, s, action, dtoken, ptoken );
        while( --s >= token )
            action[*s] = error;
    }
    putambigs( base );
    putnum( "YYNOACTION", error - nstate + used );
    putnum( "YYEOFTOKEN", eofsym->token );
    putnum( "YYERRTOKEN", errsym->token );
    putnum( "YYETOKEN", errsym->token );
    if( compactflag ) {
        parent_base = used + npro;
        putnum( "YYPARENT", parent_base );
        for( i = 256, shift = 8; i < used; i <<= 1, ++shift ) ;
        putnum( "YYPRODSIZE", shift );
    } else {
        putnum( "YYPTOKEN", ptoken );
        putnum( "YYDTOKEN", dtoken );
    }
    putnum( "YYSTART", base[startstate->sidx] );
    putnum( "YYSTOP", base[eofsym->enter->sidx] );
    putnum( "YYERR", base[errstate->sidx] );
    putnum( "YYUSED", used );
    if( compactflag ) {
        begtab( "YYPACKTYPE", "yyacttab" );
        for( i = 0, j = nstate; i < used; ++i ) {
            new_action = table[i].action;
            if( i == base[j-1] ) {
                // First element in each state is default/parent
                -- j;
                if( parent[j] == nstate ) {
                    // No parent state
                    tokval = used + parent_base;
                } else {
                    tokval = base[parent[j]] + parent_base;
                }
                // 0 indicates no default
                if( new_action != 0 ) {
                    if( new_action < nstate ) {
                        // Shift
                        new_action = base[ new_action ];
                    } else {
                        // Reduce
                        new_action -= nstate;   // convert to 0 based
                        new_action += used;             // now convert to 'used' base
                    }
                }
            } else {
                tokval = table[i].token;
                if( new_action < nstate ) {
                    // Shift
                    new_action = base[ new_action ];
                } else {
                    // Reduce
                    new_action -= nstate;       // convert to 0 based
                    new_action += used;         // now convert to 'used' base
                }
            }
            putcompact( tokval, new_action );
        }
        endtab();
        // Combine lengths & lhs into a single table
        begtab( "YYPRODTYPE", "yyprodtab" );
        for( i = 0; i < npro; ++i ) {
            for( item = protab[i]->item, j = 0; item->p.sym; ++item ) {
                ++ j;
            }
            puttab( FITS_A_WORD, (j << shift) + protab[i]->sym->token );
        }
        endtab();
    } else {
        begtab( "YYCHKTYPE", "yychktab" );
        for( i = 0; i < used; ++i ) {
            puttab( token_size, Token( table[i] ) );
        }
        endtab();
        begtab( "YYACTTYPE", "yyacttab" );
        for( i = 0; i < used; ++i ) {
            if( (j = Action( table[i] )) < nstate ) {
                puttab( FITS_A_WORD, base[j] );
            } else {
                puttab( FITS_A_WORD, j - nstate + used );
            }
        }
        endtab();
        begtab( "YYPLENTYPE", "yyplentab" );
        for( i = 0; i < npro; ++i ) {
            for( item = protab[i]->item; item->p.sym; ++item )
              /* do nothing */;
            puttab( FITS_A_BYTE, item - protab[i]->item );
        }
        endtab();
        begtab( "YYPLHSTYPE", "yyplhstab" );
        for( i = 0; i < npro; ++i ) {
            puttab( token_size, protab[i]->sym->token );
        }
        endtab();
    }
    dumpstatistic( "bytes used in tables", bytesused );
    dumpstatistic( "states with defaults", num_default );
    dumpstatistic( "states with parents", num_parent );
    puttokennames( dtoken, token_size );
}

static int addtotable(  short *token,
                        short *s,
                        short *action,
                        short default_token,
                        short parent_token )
{
    unsigned            start, max, i;
    short               default_action;
    short *             r;
    a_table *           t;

    if( compactflag ) {
        start = used++;         // Leave room for parent & default
        default_action = 0;
        for( ;; ++ token ) {
            if( used >= avail ) {
                avail = roundup( used + 1, BLOCK );
                if( table ) {
                    table = REALLOC( table, avail, a_table );
                } else {
                    table = MALLOC( avail, a_table );
                }
            }
            if( token == s ) break;
            if( *token == default_token ) {
                default_action = action[*token];
            } else if( *token != parent_token ) {
                table[used].token = *token;
                table[used].action = action[*token];
                ++ used;
            }
        }
        table[start].token = action[ parent_token ];
        table[start].action = default_action;
    } else {
        r = token;
        max = *(r++);
        for(; r < s; ++r ) {
            if( *r > max ) {
                max = *r;
            }
        }
        for( start = 0; ; ++start ) {
            if( start + max >= avail ) {
                i = avail;
                avail = roundup( start + max + 1, BLOCK );
                if( table ) {
                    table = REALLOC( table, avail, a_table );
                } else {
                    table = MALLOC( avail, a_table );
                }
                while( i < avail ) {
                    table[i].token = TOKEN_IMPOSSIBLE;
                    table[i].action = 0;
                    ++i;
                }
            }
            if( !IsBase( table[start] ) ) {
                for( r = token; r < s; ++r ) {
                    if( IsUsed( table[start + *r] ) ) {
                        goto contin2;
                    }
                }
                break;
            }
            contin2:;
        }
        SetBase( table[start] );
        for( r = token; r < s; ++r ) {
            t = &table[start + *r];
            if( ! bigflag ) {
                if( *r >= CHAR_MAX ) {
                    msg( "too many tokens!\n" );
                }
            }
            SetToken( *t, *r );
            SetAction( *t, action[*r] );
        }
        if( (i = start + max + 1) > used ) {
            used = i;
        }
    }
    return( start );
}

⌨️ 快捷键说明

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