Hi Tao,
> -----Original Message-----
> From: tao wang [mailto:[EMAIL PROTECTED]
> Sent: Saturday, March 01, 2003 9:49 AM
> To: [EMAIL PROTECTED]
> Subject: how to detect a circular macro by using perl
> 
> 
> Hi Everyone,
>   I'm trying to parse lines of macros definitions as
> following:
> 
> AV   $(G)/er $(M)/q $(T)/w/f
> G    ter/eee
> M    $(W)
> T    g/ee/fet
> W    $(AV)
> 
> You can see the AV is actually a circular macro since
> the AV -> M -> W-> AV.  I'm think about create a tree
> to do it.  Is it possible? and how can i do it?  Are
> there any other ways to do it? thank a lot.  I really
> appreciate it.                 - tao
> 

This was a real brain teaser for me! I have put together
a script that seems to work, but it's *neither* concise *nor*
elegant. If you or anyone else has some nice solution,
please post it! :)

My script:

#!/usr/bin/perl
use strict;
use warnings;

# sample input

my $input = <<'*EOF*';
AV   $(G)/er $(M)/q $(T)/w/f
G    ter/eee
M    $(W)
T    g/ee/fet
W    $(AV)
*EOF*

# parse input into a hash having key == macro name
# and value == hash (ref) of dependent macro names

        my %macros;
        my @lines = split /\n/, $input;
        for (@lines) {
                my ($name, $value) = /^(\w+)\s+(.*)/;
                next unless $name and $value;
                my (@macs) = /\$\((\w+)\)/g;
                $macros{$name}->{$_} = 1 for (@macs);
                }

# print (for debugging)

        print "input:\n";
        for (sort keys %macros) {
                print "$_:";
                for my $mac (sort keys %{$macros{$_}}) {
                        print " -> $mac";
                        }
                print "\n";
                }

# iterate thru hash finding circular dependences

        print "expand:\n";
        my $cir_count = 0;
        for (sort keys %macros) {
                my $def = "$_:";
                $cir_count += expand (\$def, $_, $macros{$_});
                print "$def\n";
                }
        print "$cir_count circular definitions\n";

# recursive expand and check circular routine

sub expand
{
        my ($def, $name, $mhash) = @_;
        return 0 unless $mhash;
        for my $mac (sort keys %{$mhash}) {
                $$def .= " -> $mac";
                if ($mac eq $name) {
                        $$def .= " *CIRCULAR*";
                        return 1;
                        }
                return 1 if expand ($def, $name, $macros{$mac});
                }
        return 0;
}

output:

input:
AV: -> G -> M -> T
M: -> W
W: -> AV
expand:
AV: -> G -> M -> W -> AV *CIRCULAR*
M: -> W -> AV -> G -> M *CIRCULAR*
W: -> AV -> G -> M -> W *CIRCULAR*
3 circular definitions

Note: I am correct in that AV, M, and W are circular
(not just AV) am I not?

Notice that I have not captured the 'guts' of each macro,
just calls to other macros. The parsing may have to be
adjusted to suit your purposes. The 'sort' of hashes in
the script is optional, I used it simply to put
the results in some kind of order; in your real script you
probably should use array references to insure the
expansion sequence is maintained.

Well, it's a poor, old, hacker's start at least... again,
does anyone have a really slick solution?

Aloha => Beau;


-- 
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to