Hi,

I'm almost finished with the script (the stripped down test case 
is on the bottom of this mail) which parses cpp-preprocessed output.

The pecularity of parsing cpp-output is that if the cpp-processed
file #includes a file, then cpp prints a linemarker line, like:

        # 1 "..\\mmstorageiface\\group\\bld.inf" 1

In my script I keep track of the current working directory and
update it (in the updateCurdir() below) whenever a linemarker
rule (with flags 1 or 2) triggers. The script works fine for
the most of my input files, but there are few that break it.

There are 5 kind of sections started by the "section" terminal.
And the problem comes when the input file #includes another
file, while being in the middle of one section, like here:

        PRJ_MMPFILES
        MMSTORAGEIFACE.MMP
        ..\GROUP\PNMSG.MMP
        # 72 "bld.inf" 2
        makefile ..\group\convcolor.mk

The section above is started by the "PRJ_MMPFILES" terminal,
then 2 paths to .mmp files are coming and then (unexpected)
the cpp-linemarker comes before the last path.

What could I do now to solve this problem, please?

I can't just skip the linemarker comments as in P::RD::FAQ.

I also don't want to prepend the linemarker subrule to each
of the 5 section rules, like here:

        prj_mmpfile: /PRJ_MMPFILES\b/i 
                (linemarker | mmpfile[\%::prj_mmpfiles])(s?)

because that would make my script really unreadable and
because I'll have to add an if-statement into each of the
5 actions in order to distinguish if it was triggered by
another linemarker or by the normal section entry.

Any advices please?

Regards
Alex


#!/usr/bin/perl

use strict;
use vars qw($parser $text %prj_platforms %prj_exports 
        %prj_testexports %prj_mmpfiles %prj_testmmpfiles);
use Parse::RecDescent;
# platforms to use when 'DEFAULT' has been specified
use constant DEFPLATS => qw(ARMI ARM4 THUMB WINS WINSCW);
#$RD_WARN  = 1;
#$RD_HINT  = 1;
#$RD_TRACE = 120;
use constant GRAMMAR => q(

inffile: chunk(s) /^\Z/
chunk:  linemarker | 
        prj_platform |
        prj_export |
        prj_testexport | 
        prj_mmpfile |
        prj_testmmpfile |
        <error>

# cpp linemarker, as described in cpp manual "Preprocessor output"
linemarker: '#' <skip: '[ \t]+'> linenum path flag(s?) {
        ::updateCurdir($item{path}, $item[-1]);
}
linenum: /\d+/
flag: '1' | '2' | '3' | '4'

prj_platform: /PRJ_PLATFORMS\b/i platform(s?) {
        # go through all specified platforms
        for my $p (@{$item[-1]}) {
                if ($p =~ /^DEFAULT$/i) {
                        # store the names of 5 default platforms
                        @::prj_platforms{::DEFPLATS} = (1) x 5;
                } else {
                        $::prj_platforms{uc $p} = 1;
                }
        }
}
# TODO: make these terminals ignore filenames like TOOLS.mk
platform:
        /ARM4\b/i |
        /ARMI\b/i |
        /DEFAULT\b/i |
        /MCOT\b/i |
        /MCOY\b/i |
        /MEIG\b/i |
        /MHELEN\b/i |
        /MINT\b/i |
        /MISA\b/i |
        /MLNK\b/i |
        /MTEMPLATE\b/i |
        /MWD2\b/i |
        /THUMB\b/i |
        # don't match TOOLS.mk
        /TOOLS(?=(?:\s|\Z))/i |
        /WINC\b/i |
        /WINSCW\b/i |
        /WINS\b/i

# the rules prj_export and prj_testexport below are similar, so they
# just pass a reference to the corresponding hash down to the export rule
prj_export: /PRJ_EXPORTS\b/i export[\%::prj_exports](s?)
prj_testexport: /PRJ_TESTEXPORTS\b/i export[\%::prj_testexports](s?)
# export statements are terminated by newlines, so don't skip newlines
export: path <skip: '[ \t]+'> path(?) {
        ::storeExpPath($arg[0], $item[1], $item[-1]->[0]);
}

# the rules prj_mmpfile and prj_testmmpfile below are similar, so they
# just pass a reference to the corresponding hash down to the mmpfile rule
prj_mmpfile: /PRJ_MMPFILES\b/i mmpfile[\%::prj_mmpfiles](s?)
prj_testmmpfile: /PRJ_TESTMMPFILES\b/i mmpfile[\%::prj_testmmpfiles](s?)
mmpfile: makefile(?) path special(?) {
        ::storeMmpPath($arg[0], $item[1]->[0], $item{path}, $item[-1]->[0]);
}

path:   /"([^"]*)"/ {
                ::unixifyPath($1);
        }
        | ...!section ...!platform ...!linemarker /\S+/ {
                ::unixifyPath($item[-1]);
        }
section:
        /PRJ_EXPORTS\b/i |
        /PRJ_MMPFILES\b/i |
        /PRJ_PLATFORMS\b/i |
        /PRJ_TESTEXPORTS\b/i |
        /PRJ_TESTMMPFILES\b/i
makefile:
        /GNUMAKEFILE\b/i |
        /MAKEFILE\b/i |
        /NMAKEFILE\b/i
special:
        /TIDY\b/i |
        /IGNORE\b/i |
        /MANUAL\b/i |
        /SUPPORT\b/i
);

# the actual functions are larger, but I've skipped them here
sub unixifyPath($) { return 1; }
sub updateCurdir($$) { return 1; }
sub storeExpPath($$$) { return 1; }
sub storeMmpPath($$$$) { return 1; }

$parser = Parse::RecDescent->new(GRAMMAR) or die 'Bad grammar';
$text .= $_ while (<DATA>);
defined $parser->inffile($text) or die 'Bad text';

__DATA__
PRJ_PLATFORMS
DEFAULT WINC

PRJ_EXPORTS
..\inc\cmmphonebookstoreextinterface.h  \tcf\cmmphonebookstoreextinterface.h
..\inc\cmmphonebookstoremesshandler.h   \tcf

..\inc\cmmonstoremesshandler.h          MANUAL
..\inc\cmmonstoreextinterface.h         ignore

PRJ_TESTEXPORTS
..\inc\cmmenstoreextinterface.h         \tcf\cmmenstoreextinterface.h
..\inc\cmmenstoremesshandler.h

mmstorageiface.iby      \epoc32\rom\include\mmstorageiface.iby

# 1 "..\\mmstorageiface\\group\\bld.inf" 1

PRJ_MMPFILES
MMSTORAGEIFACE.MMP
..\GROUP\PNMSG.MMP
# 72 "bld.inf" 2
makefile ..\group\convcolor.mk

PRJ_TESTMMPFILES

Reply via email to