mirror of
https://github.com/sheumann/dmake.git
synced 2024-09-27 07:54:45 +00:00
40188c17b0
This was used with old versions of occ, but is not needed any more.
255 lines
7.0 KiB
C
255 lines
7.0 KiB
C
/* RCS -- $Header: /u2/dvadura/src/generic/dmake/src/RCS/percent.c,v 1.1 1992/01/24 03:29:34 dvadura Exp $
|
|
-- SYNOPSIS -- handle building or %-rule meta-target nfa.
|
|
--
|
|
-- DESCRIPTION
|
|
-- Builds the NFA used by dmake to match targets against %-meta
|
|
-- rule constructs. The NFA is built as a set of DFA's.
|
|
--
|
|
-- AUTHOR
|
|
-- Dennis Vadura, dvadura@watdragon.uwaterloo.ca
|
|
-- CS DEPT, University of Waterloo, Waterloo, Ont., Canada
|
|
--
|
|
-- COPYRIGHT
|
|
-- Copyright (c) 1990 by Dennis Vadura. All rights reserved.
|
|
--
|
|
-- This program is free software; you can redistribute it and/or
|
|
-- modify it under the terms of the GNU General Public License
|
|
-- (version 1), as published by the Free Software Foundation, and
|
|
-- found in the file 'LICENSE' included with this distribution.
|
|
--
|
|
-- This program is distributed in the hope that it will be useful,
|
|
-- but WITHOUT ANY WARRANTY; without even the implied warrant of
|
|
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
-- GNU General Public License for more details.
|
|
--
|
|
-- You should have received a copy of the GNU General Public License
|
|
-- along with this program; if not, write to the Free Software
|
|
-- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
--
|
|
-- LOG
|
|
-- $Log: percent.c,v $
|
|
* Revision 1.1 1992/01/24 03:29:34 dvadura
|
|
* dmake Version 3.8, Initial revision
|
|
*
|
|
*/
|
|
|
|
#include "extern.h"
|
|
|
|
static DFAPTR _build_dfa ANSI((char *));
|
|
static char _shift_dfa ANSI((DFAPTR, char *));
|
|
|
|
#define NO_ACTION 0
|
|
#define START_PERCENT 1
|
|
#define END_PERCENT 2
|
|
#define ACCEPT 4
|
|
#define FAIL -1
|
|
|
|
static NFAPTR _nfa = NIL( NFA );
|
|
|
|
|
|
PUBLIC DFALINKPTR
|
|
Match_dfa( char *buf )/*
|
|
==================
|
|
This routines runs all DFA's in parrallel and selects the one that best
|
|
matches the string. If no match then it returns NIL( DFA ) */
|
|
{
|
|
register NFAPTR nfa;
|
|
int adv;
|
|
DFALINKPTR dfa_list = NIL(DFALINK);
|
|
|
|
DB_ENTER( "Match_dfa" );
|
|
DB_PRINT( "dfa", ("Matching %s", buf) );
|
|
|
|
/* Run each of the DFA's on the input string in parallel, we terminate
|
|
* when all DFA's have either failed or ACCEPTED, if more than one DFA
|
|
* accepts we build a list of all accepting DFA's sorted on states with
|
|
* those matching in a higher numbered state heading the list. */
|
|
|
|
do {
|
|
adv = FALSE;
|
|
|
|
for( nfa = _nfa; nfa != NIL( NFA ); nfa = nfa->next ) {
|
|
if( nfa->status != (char) FAIL && nfa->status != (char) ACCEPT ) {
|
|
adv++;
|
|
nfa->status = _shift_dfa( nfa->dfa, buf );
|
|
|
|
/* Construct the list of matching DFA's */
|
|
if( nfa->status == (char) ACCEPT ) {
|
|
DFALINKPTR dl;
|
|
|
|
TALLOC( dl, 1, DFALINK );
|
|
dl->dl_meta = nfa->dfa->node;
|
|
dl->dl_per = _substr( nfa->dfa->pstart, nfa->dfa->pend );
|
|
dl->dl_state = nfa->dfa->states - nfa->dfa->c_state;
|
|
|
|
if( dfa_list == NIL(DFALINK) )
|
|
dfa_list = dl;
|
|
else {
|
|
DFALINKPTR tdli = dfa_list;
|
|
DFALINKPTR tdlp = NIL(DFALINK);
|
|
|
|
for( ; tdli != NIL(DFALINK); tdli = tdli->dl_next ) {
|
|
if( dl->dl_state >= tdli->dl_state )
|
|
break;
|
|
tdlp = tdli;
|
|
}
|
|
|
|
if( tdli != NIL(DFALINK) ) {
|
|
tdli->dl_prev = dl;
|
|
dl->dl_next = tdli;
|
|
}
|
|
|
|
if( tdlp != NIL(DFALINK) ) {
|
|
tdlp->dl_next = dl;
|
|
dl->dl_prev = tdlp;
|
|
}
|
|
else
|
|
dfa_list = dl;
|
|
}
|
|
|
|
DB_PRINT( "dfa", ("Matched [%s]", dl->dl_meta->CE_NAME) );
|
|
}
|
|
}
|
|
}
|
|
buf++;
|
|
}
|
|
while ( adv );
|
|
|
|
for( nfa = _nfa; nfa != NIL( NFA ); nfa = nfa->next ) {
|
|
nfa->status = 0;
|
|
nfa->dfa->c_state = nfa->dfa->states;
|
|
}
|
|
|
|
DB_RETURN( dfa_list );
|
|
}
|
|
|
|
|
|
PUBLIC void
|
|
Check_circle_dfa(void)/*
|
|
====================
|
|
This function is called to test for circularities in the DFA lists
|
|
constructed from %-meta targets. */
|
|
{
|
|
register NFAPTR nfa;
|
|
|
|
for( nfa = _nfa; nfa != NIL(NFA); nfa = nfa->next )
|
|
if( Test_circle( nfa->dfa->node, FALSE ) )
|
|
Fatal( "Detected circular dependency in inference graph at [%s]",
|
|
nfa->dfa->node->CE_NAME );
|
|
}
|
|
|
|
|
|
PUBLIC void
|
|
Add_nfa( char *name )/*
|
|
=================
|
|
Given name, build a DFA and add it to the NFA. The NFA is maintained as
|
|
a singly linked list of DFA's. */
|
|
{
|
|
NFAPTR nfa;
|
|
|
|
TALLOC(nfa, 1, NFA);
|
|
nfa->dfa = _build_dfa(name);
|
|
|
|
if( _nfa != NIL(NFA) ) nfa->next = _nfa;
|
|
|
|
_nfa = nfa;
|
|
}
|
|
|
|
|
|
static DFAPTR
|
|
_build_dfa( char *name )/*
|
|
====================
|
|
Construct a dfa for the passed in cell name. The routine returns a struct
|
|
that represents a finite state machine that can recognize a regular
|
|
expression with exactly one '%' sign in it. The '%' symbol is used as a
|
|
wildcard character that will match anything except the character that
|
|
immediately follows it or NUL.
|
|
|
|
The Construction of DFA's is well know and can be found in Hopcroft and
|
|
Ullman or any other book discussing formal language theory.
|
|
A more practical treatise can be found in Compilers, Aho, Sethi and Ullman.
|
|
*/
|
|
{
|
|
DFAPTR dfa;
|
|
int nstates;
|
|
register STATEPTR sp;
|
|
STATEPTR per_state = NIL(STATE);
|
|
int pcount=0;
|
|
int end_percent=FALSE;
|
|
|
|
nstates = strlen(name)+2;
|
|
|
|
/* Allocate a DFA node and the right number of states. */
|
|
TALLOC(dfa, 1, DFA);
|
|
TALLOC(sp=dfa->c_state=dfa->states, nstates, STATE);
|
|
dfa->node = Def_cell( name );
|
|
|
|
/* Now construct the state table for the DFA */
|
|
do {
|
|
if( *name == '%' ) {
|
|
if( pcount++ > 0 )
|
|
Error( "Only one %% allowed within a %%-meta target" );
|
|
|
|
sp->symbol = 0;
|
|
sp->action = START_PERCENT;
|
|
sp->no_match = sp->match = per_state = sp+1;
|
|
end_percent = TRUE;
|
|
}
|
|
else {
|
|
sp->symbol = *name;
|
|
sp->no_match = per_state;
|
|
|
|
if( *name == '\0' ) {
|
|
sp->action = ACCEPT;
|
|
sp->match = dfa->states;
|
|
}
|
|
else {
|
|
sp->action = NO_ACTION;
|
|
sp->match = sp+1;
|
|
}
|
|
|
|
if( end_percent ) {
|
|
sp->action |= END_PERCENT;
|
|
end_percent = FALSE;
|
|
}
|
|
}
|
|
|
|
sp++;
|
|
}
|
|
while( *name++ );
|
|
|
|
return(dfa);
|
|
}
|
|
|
|
|
|
static char
|
|
_shift_dfa( DFAPTR dfa, char *data )/*
|
|
=========================
|
|
Take a given dfa and advance it based on the current state, the shift
|
|
action in that state, and the current data value. */
|
|
{
|
|
register STATEPTR sp = dfa->c_state;
|
|
char c = *data;
|
|
|
|
/* Check if it is a START_PERCENT action if so then we need to save
|
|
* a pointer to the start of the string and advance to the next state. */
|
|
if( sp->action & START_PERCENT ) {
|
|
dfa->pstart = data;
|
|
sp++;
|
|
}
|
|
|
|
/* Now check if the current char matches the character expected in the
|
|
* current state. If it does then perform the specified action, otherwise
|
|
* either shift it or fail. We fail if the next state on no-match is
|
|
* NIL. */
|
|
if( sp->symbol == c ) {
|
|
if( sp->action & END_PERCENT ) dfa->pend = data;
|
|
if( sp->action & ACCEPT ) return(ACCEPT);
|
|
dfa->c_state = sp->match;
|
|
}
|
|
else if( (dfa->c_state = sp->no_match) == NIL(STATE) || !c )
|
|
return(FAIL);
|
|
|
|
return(NO_ACTION);
|
|
}
|