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