Parsing comments again (cpp linemarkers)
[email protected] Thu, 3 Jun 2004 15:54:56 +0200
| Newsgroups | perl.recdescent |
|---|---|
| Message-ID | <[email protected]> |
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