字符串操作符
.用于连接字符串
use warning 开启per内置的警告信息,或者用-w参数
use diagnostics 查看更多编译信息或者用-Mdiagnostics参数
读到文件结尾end-of-line时,返回undef标志,用defined函数是否是undef状态。
标量都是单数(singular),列表与数组代表复数(plural)
列表(list)指的是标量的有序集合,而数组(array)则是存储列表的变量
或者说列表指的是数据,而数组指的是变量
$rocks[$#rocks] $rocks[-1]等效 都指最后一个
("aaa","bbb","ccc","ddd")
qw(aaa,bbb,ccc,ddd)两等效
Perl允许使用任何标点符号作为定界符,常用的有:
qw! aaa bbb ccc ddd !
qw/ aaa bbb ccc ddd /
qw# aaa bbb ccc ddd #
@arrayname 引用整个数组
push-pop操作数组尾和shift-unshift操作数组首
splice
@array = qw(aaa,ddd,eee);
@removed = splice @array,2;
#@removed变成qw(ccc,ddd)
#@array变成qw(aaa,bbb)
foreach(1..10){
print "this num is $_!\n"# $_ 默认变量
}
state来声明为当前子程序的持有性私有变量,并且多次调用这个子程序期间保留该变量的值。
chomp;#不加参数,默认用默认参数$_
@ARGV #命令行默认参数
6个特殊文件句柄是Perl保留的,STDIN,STDOUT,STDERR,DATA,ARGV,ARGVOUT
数组用方括号,哈希用花括号
$hash{ 'index1' } = 'index1value';
哈希函数
$reverhash = revers %hash
my @k = keys %hash;
my @v = values %hash;
while(($key,$value) = each %hash)
{}
exists/delete
%ENV
print "PATH is $ENV{PATH}\n"
正则表达式
$_ = "yabba dabba doo";
if( /abba/ )
{..}
Unicode属性,Unicode字符能够理解自身含义,它们包含字节组合之外,还附带着属性信息。
if(/\q{Space}/){}
if(/\q{Digit}/){}
元字符
点号(.)是能匹配任意一个字符的通配符,换行符除外。
/3\.14159/这个模式中点号就不是表示通配的元字符
星号(*)正是用来匹配前面的条目零次或任意多次的
/abb\t*bbb/匹配abb\tbbb abb\t\tbbb
/aaa.*bbb因此会匹配任意字符零次到无限多次
加号(+)也是量词,会匹配前一个条目一次以上
问号(?),前面条目可出现一次或不出现
模式分组
/fred*/匹配freddddd
/(fred)*/ 匹配fredfred
反向引用来引用圆括号中的模式所柳丁的文字,这个行为我们称为捕获组,
比如\1\2表示相应顺序的捕获组
$_ = "abb";
if(/(.)\1/){}#匹配 ‘bb'
/y(.)(.)\2\1/ #匹配’abba'
“aa11bb"
\111是指\111,而不是\1或\11, Perl尽可能往多的原则靠
if(/(.)\g{1}11/)指\1解决反引用与直接量部分的二义性
if(/(.)\111/)指\111
if(/(.)(.)\g{-1}11/相对自己的位置来找编号
择一匹配
/fred(|\t)+barney/
字符集,指的是一组可能出现的字符,通过写在方括号([])内表示。
[abcwxyx]匹配7个字符内任意一个
[\000-\177] 将匹配任意一个7位的ASCII字符
[^def]会匹配这三个字符以外的任何字符^ 脱字符
字符集的简写
比如表示任意一个数字的字符集的简写是\d
\s简写能匹配任意空白符,所以效果上大抵等同于Unicode属性\p{Space}
Perl5.6之前,\s仅能匹配5个 换页符,水平制表符,换行符,回车符,空格
\h只匹配水平空白符
\v只匹配垂直空白符
\R简写能匹配任意一种断行符
\w能匹配的字符并不是严格意义上的单词字符
[^\d],[^\w],[^\s] 非数字,非单词或者非空白符
[\D],[\W],[\S] 大写版本表示否定意义
[\d\D],表示任何数字或非数字,也就是匹配任意字符(包含换行符),而点号不匹配换行符
正则表达式进行匹配
用m//进行匹配
/i进行大小写无关的匹配
/s匹配任意字符 点号无法匹配换行符,对单行点号就适用了
$_ = "I saw Barney\ndown at the bowling alley\nwith fred\nlast night.\n"
if(/Barney.*Fred/s){}没有/s修饰符,匹配会失败。
/x加入空白符
/-?[0-9]+\.?[0-9]*/
/ -? [0-9]+ \.? [0-9]* /x#这样便于阅读,理解,但原来的空白和制表本身需要用\空格和\t
组合选项修饰符
if(/barney.*fred/is){}
三种字符解释方式:ASCII(/a),Unicode(/u)和locale(l),locale经常会引发问题。
锚位,可以让模式仅在字符串指定位置匹配。
\A锚位匹配字符串的绝对开头,如果开头位置不匹配,是不会顺移到下一个位置继续尝试的。
m{\Ahttps?://}i#判断字符串是否以https开头
m{\.png\z}i#匹配以.png结尾的
字符串的绝对末尾,强调后面再无任何其他东西。 \Z允许后面出现换行符
while(<STDIN>){
print if /\.png\Z/;
}
while(<STDIN>){
chomp;
print "$_\n" if /\.png\z/;
}
可以用$锚位和/m修饰符表示对多行内容进行匹配。
/fred$/m
单词锚位
/\bfred\b/可匹配fred,但无法匹配frederick,alfred,manfredss。\b是单词边界锚位,也称为”整词匹配“
绑定操作符=~
默认情况下模式匹配的操作对象是$_,绑定操作符(=~) 告诉perl用右边的模式来匹配左边的字符串。
模式中的内插
my $what = "larry";
while(<>){#每次读一行输入
if(/\A($what)/){#模式的锚位被定在字符串的开头
print "We saw $what in beginning of $_";
}
}
除非while循环的条件表达式中只有整行输入操作符(<STDIN>),否则输入行不会被 PERL自动存入$_.
捕获变量
捕获组会把匹配圆括号中模式的字符串保存到相应的地方$1,$2,$3
$_ = "Hello there,neighbor";
if(/(\S+) (\S+),(\S+)/){
print "word were $1 $2 $3\n";
}
运行结果是:words were Hello there neighbor.
捕获变量的存续期, 它们能戚到下次成功匹配为止。失败的匹配不会改动上次成功匹配时捕获的内容。
不捕获模式:用?:修饰的圆括号不会将捕获部分的匹配字符串放到捕获变量中
if(/(?:bronto)?saurs (steak|burger){
print "Fred wants a $1\n";
}
命名捕获
my $names = 'Fred or Barney';
if( $names =~ m/(?<name1>\w+) (?:and|or) (?<name2>\w+/){
say "i saw $+{name1} and $+{name2}";
}
自动捕获变量:$&,$`,$'免费但影响运行速度
字符串里实际匹配模式的部分会被自动在存进$&里
if( "Hello there,neighbor" =~ /\s(\w+),/){
print "That actually matched '$&'.\n";
}
$1保存there
$&保存there,
匹配区段之前的内容会存到$`里,匹配区段之后的内容则会存到$'里
用/p修饰符则可用${^PREMATCH},${^MATCH}和${^POSTMATCH}表示。
用正则表达式处理文本
用s///进行替换
$_ = "He's out bowling with Barney tonight.";
s/Barney/Fred/;#把Barney替换为Fred
print "$_\n";
s/Barney/Fred/g;#/g 全局替换
my @filelds = split /separator/,$string;
my @fields = split /:/,"abc:def:g:h";#得到("abc","def","g","h")
join函数功能与split相反
my $result = join $glue,@pieces;
my $x = join ":",4,6,8,10,12;# $x为"4:6:8:10:12"
$_ = "Hello there,neighbor";
my($first,$second,$third) = /(\S+) (\S+),(\S+)/;
print "$second is my $third\n";
贪婪量词
/fred.+barney/#要求能匹配的字符串越长越好
非贪婪量词
/fred.+?barney/#要求能匹配的字符串越短越好
if(flag){...}#flag为真时才执行
unless(flag){...}#flag为假时才执行
while(flag){...}#flag为真时才执行
until(flag){...}#flag为假时才执行
last操作符能立即中止循环的执行,相当C语言中的"break"
next相当continue
redo操作符返回到当前循环块的顶端,而不经过任何条件测试,也不会进入下一次循环迭代。
LINE:while(<>){
foreach(split){
last LINE if /__END__/;
...
}
}
die "Oops! A file called '$filename' already exist.\n"
if -e $filename;
PERL 模块
perldoc CGI 打开模块文档
perl自带cpan命令查看所有模块: $cpan -a
模块使用MakeMaker
$perl Makefile.PL
$make install
使用Module::Build
$perl Build.PL
$./Build install
perl自带的path::class模块则提供了更友好的操作界面:
my $dir=dir( qw(Users fred lib) );
my $subdir= $dir ->subdir( 'perl5' );# Users/fred/lib/perl5
DateTime处理日期和时间的模块
chdir操作符来改变当前的工作目录
my @all_files = <*>;
my @all_files = glob "*";
Perl里面,可以使用unlink操作符,并指定要删除的文件列表。
rename函数
chmod函数类似unix的chmod命令
chmod 0755,'fred','barney';
字符串与排序
$where = index($big,$small);
$big = "Howdy world!";
$where = index($big,"wor");# $where is 6
my $part = substr($string,$initial_position,$length);
省略第三参数将取到字符串结尾
$initial_position 负数表示从后数起
substr($string,-20) =~ s/fred/barney/g;# 将后面20字符所有fred换成barney
sprintf函数与printf有相同的参数
my $date_tag = sprintf "%4d/%02d",$yr,$mo;
hex('DEA')
oct('0377')
智能匹配
use 5.010001
say "I found Fred in the name!" if $name ~~ /Fred/;
等价以下:
my $flag = 0;
foreach my $key (keys %names ){
next unless $key =~ /Fred/;
$flag = $key;
last;
}
print "I found Fred in the name!" if $flag;
given-when类似switch
given ( $ARGV[0] ){
when ( 'Fred' ){say 'Name is Fred' }
when ( /fred/i ){say 'Name has fred in it' }
defalut{say 'ss'}
}
进程管理
system 'date'; # perl调用unix的date命令。
exec
捕获错误
eval { $barney = $fred / $dino };
eval只是一个表达式,末尾加”;"
捕获到错误eval将返回undef,如果没有错误发生,$@就是空的
exit操作符会立即终止程度运行。
异常机制
die抛出异常
eval {
...;
die "An unexpected exception message" if $unexpected;
die "Bad denominator" if $dino == 0;
$barney = $fred / $dino;
}
if( $@ =~ /unexpected/ ){
...;
}
elsif( $@ =~ /denominator/ ){
...;
}
{
local $@;#不干扰高层错误
...
}
foreach( 1..1000){
push @odd_numbers,$_ if $_ % 2;
}
等价
my @odd_numbers = grep { $_ % 2 } 1..1000;
my @matching_lines = grep /\bfred\b/i,<$fh>;
my $line_count = @matching_lines;
my $line_count = grep /\bfred\b/i,<$fh>;
<!ELEMENT NXRMClientConfiguration (LocationArray,Log)>
<!ATTLIST NXRMClientConfiguration SchemaVersion CDATA #required>
<!ATTLIST NXRMClientConfiguration SN CDATA #required>
<!ATTLIST NXRMClientConfiguration Name CDATA #required>
<!ATTLIST NXRMClientConfiguration UpdateDate CDATA #required>
<!ELEMENT LocationArray (Location+)>
<!ELEMENT Location (#PCDATA)>
<!ATTLIST Location Name CDATA #Default>
<!ATTLIST Location Desc CDATA #required>
<!ELEMENT Log (#PCDATA)>
<!ATTLIST Log MaxLogSize CDATA #required>
#!/usr/bin/perl -w
#this sub function parser sub elment
#usage:
#$result = [];$subelement = "(A | (B,(C | (D,E))) | F)";
#Subelementparser($result,$subelement);
#return $result = AB,CB,D,EF
sub Subelementparser{
my($res,$temp)=@_;
my($prematch,$match,$postmatch);
my(@items);
$temp =~ s/\s*//g;# delete space
$temp =~ s/^\((.*)\)$/$1/e;#delete outside bracket
unless($temp =~ /\(/){#case inside bracket
if($temp =~ /\|/){
@items = split(/\|/,$temp);
foreach (@items){
push @$res,$_;
}
}
else{
push @$res,$temp;
}
}
else{#case:there exist is one or more bracket
$temp =~ m/\((.*)\)/;
$prematch = ${^PREMATCH};
$match = ${^MATCH};
$postmatch = ${^POSTMATCH};
$flag = "false";
if($prematch =~ /,/){
$flag = "true";
}
if($flag =~ /true/){#case: B,(D|E)
my($tempres) = [];
Subelementparser($tempres,$match);
foreach (@$tempres){
push @$res,"${prematch}$_";# $prematch = "B,"
}
}
else{
@items = split(/\|/,$prematch);
foreach (@items){
push @$res,"$_";
}
if($match =~ /./){
Subelementparser($res,$match);
}
}
@items = split(/\|/,$postmatch);
foreach (@items){
if(/./){
push @$res,$_;
}
}
}
}
sub ProcElement {
my($cname,$expan)=@_;
my($cinterdef,$cimpheader,$cimpcpp);
my($construc,$parser);
my($mem);
my($headerfile,$class_name);
my($subelements) = [];
Subelementparser($subelements,$expan);
# here start generate .h file without attribute part and } end part
$cinterdef = "// <!ELEMENT ${cname} ${expan}>\n";
$cinterdef .= "class I$cname\n{\npublic:\n";
$cinterdef .= "\tvirtual bool WriteToXML(const std::string& XMLPath) = 0;\n";
$cinterdef .= "\tvirtual bool ReadFromXML(const std::string& XMLPath) = 0;\n";
$cinterdef .= "\tvirtual void Reset(void) = 0;\n";
$cinterdef .= "\tvirtual void Release(void) = 0;\n\n";
$construc = "";
$cimpheader = "class $cname : public I$cname\n{\npublic:\n";
$cimpheader .= "\t$cname(void);\n";
$cimpheader .= "\t$cname(const Node& node);\n";
$cimpheader .= "\t~$cname(void);\n";
$cimpheader .= "\tbool WriteToXML(const std::string& XMLPath);\n";
$cimpheader .= "\tbool ReadFromXML(const std::string& XMLPath);\n";
$cimpheader .= "\tvoid Reset(void);\n";
$cimpheader .= "\tvoid Release(void);\n\n";
$cimpcpp = "${cname}::${cname}() : m_node(Node())\n{\n\tm_node.SetNodeName(\"${cname}\");\n}\n\n";
$cimpcpp .= "${cname}::${cname}(const Node& node) : m_node(node)\n{\n\tm_node.SetNodeName(\"${cname}\");\n}\n\n";
$cimpcpp .= "${cname}::~${cname}(void)\n{\n}\n\n";
$cimpcpp .= "bool ${cname}::WriteToXML(const std::string& XMLPath)\n{\n\treturn m_node.Print(XMLPath);\n}\n\n";
$cimpcpp .= "bool ${cname}::ReadFromXML(const std::string& XMLPath)\n{\n\tm_node = Node(XMLPath);\n\treturn true;\n}\n\n";
$cimpcpp .= "void ${cname}::Reset(void)\n{\n\tm_node = Node();\n\tm_node.SetNodeName(\"${cname}\");\n}\n\n";
$cimpcpp .= "void ${cname}::Release(void)\n{\n\tdelete this;\n}\n\n";
foreach (@$subelements){
@subclass = split(/,/,$_);
#$cdef .= "\t$cname(";
#$flag = "false";
foreach $mem (@subclass){
if($mem =~ /[?*+]/){
$mem =~ s/[*+?]//g;
$cinterdef .= "\t//Element $mem\n";
$cinterdef .= "\tvirtual unsigned int GetElem${mem}(void) = 0;\n";
$cinterdef .= "\tvirtual I${mem}* GetElem${mem}At(unsigned int index) = 0;\n";
$cinterdef .= "\tvirtual void AddElem${mem}(I${mem}* NewElem) = 0;\n";
$cinterdef .= "\tvirtual void AddElem${mem}At(unsigned int index,I${mem}* NewElem) = 0;\n";
$cinterdef .= "\tvirtual void RemoveElem${mem}At(unsigned int index) = 0;\n";
$cinterdef .= "\tvirtual void RemoveAllElem${mem}(void) = 0;\n\n";
$cimpheader .= "\t//Element $mem\n";
$cimpheader .= "\tunsigned int GetElem${mem}(void);\n";
$cimpheader .= "\tI${mem}* GetElem${mem}At(unsigned int index);\n";
$cimpheader .= "\tvoid AddElem${mem}(I${mem}* NewElem);\n";
$cimpheader .= "\tvoid AddElem${mem}At(unsigned int index,I${mem}* NewElem);\n";
$cimpheader .= "\tvoid RemoveElem${mem}At(unsigned int index);\n";
$cimpheader .= "\tvoid RemoveAllElem${mem}(void);\n\n";
$cimpcpp .= "//Element $mem\n";
$cimpcpp .= "unsigned int ${cname}::GetElem${mem}(void)\n{\n\treturn m_node.NumChilds();\n}\n\n";
$cimpcpp .= "I${mem}* ${cname}::GetElem${mem}At(unsigned int index)\n{\n";
$cimpcpp .= "\t${mem} *temp = NULL;\n\tunsigned int total = m_node.NumChilds();\n\tif(index < total)\n\t{\n";
$cimpcpp .= "\t\ttemp = new ${mem}(m_node.GetChildAt(index));\n\t}\n\treturn temp;\n}\n\n";
$cimpcpp .= "void ${cname}::AddElem${mem}(I${mem}* NewElem)\n{\n\tm_node.AppendChild(static_cast<${mem}*>(NewElem)->m_node);\n}\n\n";
$cimpcpp .= "void ${cname}::AddElem${mem}At(unsigned int index,I${mem}* NewElem)\n{\n\tm_node.AppendChildAt(index,static_cast<${mem}*>(NewElem)->m_node);\n}\n\n";
$cimpcpp .= "void ${cname}::RemoveElem${mem}At(unsigned int index)\n{\n\tm_node.RemoveChildAt(index);\n}\n\n";
$cimpcpp .= "void ${cname}::RemoveAllElem${mem}(void)\n{\n\tm_node.RemoveChilds();\n}\n\n";
}
elsif($mem =~ /#PCDATA/){
}
else{
$cinterdef .= "\t//Element $mem\n";
$cinterdef .= "\tvirtual I${mem}* GetElem${mem}(void) = 0;\n";
$cinterdef .= "\tvirtual void SetElem${mem}(I${mem}* ElemName) = 0;\n\n";
$cimpheader .= "\t//Element $mem\n";
$cimpheader .= "\tI${mem}* GetElem${mem}(void);\n";
$cimpheader .= "\tvoid SetElem${mem}(I${mem}* ElemName);\n\n";
$cimpcpp .= "//Element $mem\n";
$cimpcpp .= "I${mem}* ${cname}::GetElem${mem}(void)\n{\n\treturn new ${mem}(m_node.GetFirstChild());\n}\n\n";
$cimpcpp .= "void ${cname}::SetElem${mem}(I${mem}* ElemName)\n{\n\tm_node.AppendChild(static_cast<${mem}*>(ElemName)->m_node);\n}\n\n";
}
}
}
my(%hash) = ();
undef %hash;
foreach (@$subelements){
@subclass = split(/,$_);
foreach $mem (@subclass){
if(/#PCDATA/){
#$cdef .= "\tvoid addData( const std::string& data );\n";
}
else{
unless(exists( $hash{ $mem} ))
{
#$cdef .= "\tvoid addNode( $mem *the_$mem );\n";
$mem =~ s/[*+?]//g;
$headerfile .= "#include \"${mem}.h\"\n";
$class_name .= "class I${mem};\n";
$hash{$mem} = 1;
}
}
}
}
if($rootflag =~ /false/)
{
$construc .= "\nconst char* dtdData = \"$tempdtd\";\n\n";
#$cdef .= "\tbool Validate() const;\n";
#$cdef .= "\t$cname(const std::string& XMLFile);\n";
}
#$cdef .= "};\n\n";#wait for attribute
# here start generate .cpp file
undef %hash;
foreach (@$subelements){
$construc .= "${cname}::${cname}(";
@subclass = split(/,$_);
$flag = "false";
foreach $mem (@subclass){
if( $flag =~ /true/ ){
$construc .= ",";
}
if(/#PCDATA/){
$construc .= " const std::string& data";
$parser.= "void ${cname}::addData(const std::string& data)\n{\n";
$parser .= "\tSetData(data);\n}\n\n";
}
else{
$construc .= " $mem *the_$mem";
unless(exists( $hash{ $mem} ))
{
$parser.= "void ${cname}::addNode($mem *the_$mem)\n{\n";
$parser.= "\tAppendChild(*the_$mem);\n}\n\n";
$hash{$mem} = 1;
}
}
if( $flag =~ /false/ ){
$flag = "true";
}
}
if($rootflag =~ /false/)
{
$parser .= "bool ${cname}::Validate() const\n{\n";
$parser .= "\treturn ValidateDTD(dtdData);\n";
$parser .= "}\n\n";
$parser .= "${cname}::${cname}(const std::string& XMLFile):Node(XMLFile)\n{\n";
$parser .= "}\n\n";
$rootflag = "true";
}
$construc .= " ):Node()\n{\n";
$construc .= "\tSetNodeName(\"${cname}\");\n";
foreach $mem (@subclass){
if(/#PCDATA/){
$construc .= "\taddData(data);\n";
}
else{
$construc .= "\tAppendChild(*the_$mem);\n";
}
}
$construc .= "}\n\n";
}
push(@classes,$cname);
$interfacefile{ $cname } = $cinterdef;
$implementheaderfile{ $cname } = $cimpheader;
$implementcppfile { $cname } = $cimpcpp;
#$constructors{ $name } = $construc;
#$parsersvec{ $name } = $parser;
$headerlist{ $cname } = $headerfile;
$classdeflist{ $cname } = $class_name;
}
sub ProcAttList {
my($name,$attribs)=@_;
my($attrib,$atype,$ctype,$condit,$options,$deft);
my(@options);
my($builder);
my($elemtype,$arrlen,$subparse,$req);
die "ATTLIST $name without ELEMENT\n" if(!defined($interfacefile{ $name }));
# bin some whitespace
$attribs =~ s/^\s*//;
$attribs =~ s/\s*$//;
while(1){
if($attribs =~ /^(\w+)\s+(\w+)\s+\#(\w+)\s*(.*)/){# basic; whatever type
$attrib=$1;
$atype=$2;
$condit=$3;
$attribs=$4;
$interfacefile{ $name} .= "\t//Get/Set functions for attribute $attrib\n";
$interfacefile{ $name} .= "\tvirtual std::string Get$attrib(void) = 0;\n";
$interfacefile{ $name} .= "\tvirtual void Set$attrib( const std::string& value ) = 0;\n";
$implementheaderfile{ $name} .= "\t//Get/Set functions for attribute $attrib\n";
$implementheaderfile{ $name} .= "\tstd::string Get$attrib(void);\n";
$implementheaderfile{ $name} .= "\tvoid Set$attrib( const std::string& value );\n";
$implementcppfile{ $name} .= "//Get/Set functions for attribute $attrib\n";
$implementcppfile{ $name} .= "std::string ${name}::Get$attrib(void)\n{\n\treturn m_node.GetAttribute(\"$attrib\");\n}\n\n";
$implementcppfile{ $name} .= "void ${name}::Set$attrib( const std::string& value )\n{\n\tm_node.SetAttribute(\"$attrib\",value);\n}\n\n";
$builder .= "void ${name}::Set$attrib( const std::string& value ){\n\tSetAttribute(\"$attrib\",value);\n}\n\n";
#$attributparser{ $name } .= $builder;
}
else{
last;
}
}
}
# dtd on command line
$flag = "false";
$dtdf = undef();
my($curdir) = `pwd`;
chomp($curdir);
my($outdir) = undef();
my($cppfilename) = "xml_nxl";
$count = @ARGV;
if($count == 1){
if($ARGV[0] =~ m{\.dtd\z}i){
$dtdf = $ARGV[0];
}
else{
$flag = "true";
}
}
elsif($count == 3){
if($ARGV[0] =~ m{\A-o}i){
$outdir = $ARGV[1];
$dtdf = $ARGV[2];
}
else{
$flag = "true";
}
}
else{
$flag = "true";
}
die "Usage: dtd2cpp.pl [switches] <document>
-o <directory> Outputdir - specify output directory
-h Help - Show Class Generator usage help\n" if ($flag =~ /true/);
if(defined($outdir)){
die "the directory ${outdir} don't exist!!!\n" unless(-e ${outdir});
if($outdir =~ m{\/\z}){
mkdir "${outdir}/include",0700;
mkdir "${outdir}/src",0700;
}
else{
mkdir "${outdir}/include",0700;
}
}
else{
if($dtdf =~ /(.*)\/(.*)/){
$outdir = $1;
mkdir "${outdir}/include",0700;
}
else{
$outdir = $curdir;
mkdir "${outdir}/include",0700;
}
}
# input filename
open(DTD,$dtdf) || die "can't read $dtdf: $!\n";
$dtd=join('',<DTD>);
close(DTD);
$namespacename = "NxconInterface";
@classes=();
%interfacefile=();
%implementheaderfile=();
%implementcppfile=();
#%constructors=();
#%attributparser=();
#%parsersvec=();
#%headerlist=();
%classdeflist=();
$rootflag = "false";
sub GenerateTargetFile{
my($oriname)=@_;
my($intername) = ();
my($headername) = ();
my($cppname) = ();
# here generate interface header file
$intername = "I$oriname";
open (${intername},">${intername}.h") || die "Can't write ${intername}.h: $!\n";
print ${intername} "// this is generated code,do not edit\n";
print ${intername} "#pragma once\n\n";
print ${intername} "#include <string>\n\n";
#print ${name} "#include \"nxl_xml_node.h\"\n";
print ${intername} $headerlist{ $oriname } if defined($headerlist{ $oriname });
print ${intername} "namespace ${namespacename}\n{\n";
#debug output message
print "${intername}\n";
print ${intername} "$classdeflist{ $oriname }\n" if defined($classdeflist{ $oriname });
print ${intername} $interfacefile{ $oriname } . "};\n\n";
print ${intername} "extern \"C\" ${intername}* ${intername}_CreateNewInstance(void);\n\n}\n";
close(${intername});
# here generate implement header file
$headername = "$oriname";
open (${headername},">${headername}.h") || die "Can't write ${headername}.h: $!\n";
print ${headername} "// this is generated code,do not edit\n";
print ${headername} "#pragma once\n\n";
print ${headername} "#include \"I${headername}.h\"\n";
print ${headername} "#include \"nxl_xml_node.h\"\n";
print ${headername} "namespace ${namespacename}\n{\n";
print ${headername} $implementheaderfile{ $headername };
#print ${headername} "\nprivate:\n\tNode m_node;\n};\n\n}\n";
print ${headername} "\n\tNode m_node;\n};\n\n}\n";
close(${headername});
$cppname = $oriname;
# here generate implement cpp file
open (${cppname},">${cppname}.cpp") || die "Can't write ${cppname}.cpp: $!\n";
print ${cppname} "// this is generated code,do not edit\n\n\n";
print ${cppname} "#include \"${cppname}.h\"\n\n";
print ${cppname} "namespace ${namespacename}\n{\n";
#print ${name} $constructors{ ${name} } ;
#print ${name} $parsersvec{ ${name} } ;
#print ${name} $attributparser{ ${name} } if(defined($attributparser{ ${name} }));
print ${cppname} $implementcppfile{ ${cppname} };
print ${cppname} "\nI${cppname}* I${cppname}_CreateNewInstance(void)\n{\n\treturn new ${cppname}();\n}\n";
print ${cppname} "};\n";
close(${cppname});
use File::Copy ;
use strict ;
move("${curdir}/${intername}.h","${outdir}/include/${intername}.h")||warn "could not copy files :$!" ;
move("${curdir}/${headername}.h","${outdir}/include/${headername}.h")||warn "could not copy files :$!" ;
move("${curdir}/${cppname}.cpp","${outdir}/src/${cppname}.cpp")||warn "could not copy files :$!" ;
}
$tempdtd = $dtd;
$tempdtd =~ s/\r\n//g;
$dtd =~ s/\n/''/ge;
# run thru the DTD
while(1){
$dtd =~ s/^(.*?)</</;
#$dtd =~ s/[*+?]//g;
if($dtd =~ /^<(.*?)>(.*)$/){
$elem=$1;
$dtd=$2;
if($elem =~ /^\!ELEMENT\s+(\w+)\s+(.*)/){
print "==>ELEMENT $1,$2\n";
ProcElement($1,$2);
}
elsif($elem =~ /^\!ATTLIST\s+(\w+)\s+(.*)/){
#print "ATTLIST $1\n";
ProcAttList($1,$2);
}
elsif($elem =~ /^\!\-\-.*\-\-$/){
#print "comment\n";
}
else {
print "1111111111111\n";
warn "can't understand $elem\n";
}
}
else{
print "parser over\n" if defined($elem);
last;
}
}
# class declarations & code
for(@classes){
GenerateTargetFile($_);
}
# generate Makefile file
open(MAKEFILE,">Makefile") || die "Can't write Makefile: $!\n";
print MAKEFILE "#
# ! Don't modify this file
# Modify Makefile.inc instead
#
ifeq (\$(NLBUILDROOT),)
\$(error NLBUILDROOT undefined.)
endif
ifeq (\$(NLEXTERNALDIR),)
\$(error NLEXTERNALDIR undefined.)
endif
#
# Following master make file can be included:
# - master.cxx.mak
# - master.csharp.mak
# - master.java.mak
#
\$(info Include master makefile: \$(NLBUILDROOT)/scripts/make/master.cxx.mak)
include \$(NLBUILDROOT)/scripts/make/master.cxx.mak
";
close(MAKEFILE);
move("${curdir}/Makefile","${outdir}/Makefile")||warn "could not copy files :$!" ;
# generate Makefile.inc file
open(MAKEFILEINC,">Makefile.inc") || die "Can't write Makefile: $!\n";
print MAKEFILEINC
"
##############################################################################
#
# The Makefile.inc will be used by master Makefile
# under NLBUILDROOT/scripts/make directory.
#
##############################################################################
#
# The name of the target
#
TARGET_NAME=nxxmlconfig
\$(info Makefile.inc for project \$(TARGET_NAME))
#
# VERSION
#
VERSION_PRODUCT= \$(VERSION_PRODUCT_RMP)
VERSION_MAJOR= \$(VERSION_MAJOR_RMP)
VERSION_MINOR= \$(VERSION_MINOR_RMP)
VERSION_MAINTENANCE = \$(VERSION_MAINTENANCE_RMP)
VERSION_PATCH= \$(VERSION_PATCH_RMP)
#
# The type of target,could be one of following values:
# - exe: An executable file
# - lib: A static library (user/kernel mode)
# - dll: A dynamic link library (user/kernel mode)
# - sys: A kernel driver
#
TARGET_TYPE=dll
#
# The run mode of target
# - kernel
# - user
#
TARGET_MODE=user
# Make sure the sys target run at kernel mode
ifeq (\$(TARGET_TYPE),sys)
ifeq (\$(TARGET_MODE),user)
\$(error A sys target must run at kernel mode.)
endif
endif
#
# Additional settings for EXE
#
ifeq (\$(TARGET_TYPE),exe)
# Application type: CONSOLE or WIN32
# console: this is a console application
# win32: this is a win32 application
EXE_TYPE = console
#
# Do we need to elevate privilege?
# - Invoke
# - Administrator
#
EXE_PRIVILEGE = Invoke
#
# Is this a test app?
# - yes
# - no or empty
#
#EXE_TESTAPP = yes
endif
#
# Source file
#
SRC = \\";
foreach (@classes){
print MAKEFILEINC "
src/$_.cpp\\";
}
print MAKEFILEINC "
src/nxl_xml_node.cpp
#
# Resource file
# If this variable is empty,a default rc file will be used automatically
#
RCSRC =
#
# Additional include directories
#
INCPATH += \\
\$(NLEXTERNALDIR)/libxml2-2.7.8.win32/include\\
\$(NLEXTERNALDIR)/libxml2-2.7.8.win32/include/libxml\\
\$(NLEXTERNALDIR)/boost/boost_1_55_0
#
# Additional library directories
#
LIBPATH += \\
\$(NLEXTERNALDIR)/libxml2-2.7.8.win32/lib\\
\$(NLEXTERNALDIR)/boost/boost_1_55_0/libs/\$(BINDIR)\\
\$(NLBUILDROOT)/bin/\$(BINDIR)
#
# Additional librarys
#
LIBS +=\\
libxml2
";
close(MAKEFILEINC);
move("${curdir}/Makefile.inc","${outdir}/Makefile.inc")||warn "could not copy files :$!" ;
# generate nxxmlconfig.def file
open(DEFFILE,">nxxmlconfig.def") || die "Can't write nxxmlconfig.def: $!\n";
print DEFFILE "EXPORTS\n";
foreach $tem(@classes){
print DEFFILE "\tI${tem}_CreateNewInstance\n";
}
close(DEFFILE);
move("${curdir}/nxxmlconfig.def","${outdir}/src/nxxmlconfig.def")||warn "could not copy files :$!" ;
# generate nxxmlconfig_helper.h file
open(HELPERFILE,">nxxmlconfig_helper.h") || die "Can't write nxxmlconfig_helper.h: $!\n";
print HELPERFILE "#pragma once\n\n";
foreach (@classes){
print HELPERFILE "#include \"I$_.h\"\n";
}
close(HELPERFILE);
move("${curdir}/nxxmlconfig_helper.h","${outdir}/include/nxxmlconfig_helper.h")||warn "could not copy files :$!" ;
#testtest only for test need,copy main.cpp nxl_xml_node.cpp nxl_xml_node.h copy("C:/Snow/Ruby/dev/ruby_starter_140507/common/nxl_xml_node.cpp","${outdir}/src/nxl_xml_node.cpp" ) || warn "could not copy files:$!"; copy("C:/Snow/Ruby/dev/ruby_starter_140507/common/nxl_xml_node.h","${outdir}/include/nxl_xml_node.h" ) || warn "could not copy files:$!"; #testtest copy libxml dlls unless ( -e "${outdir}/debug_win_x86" ){ mkdir "${outdir}/debug_win_x86",0700; } copy("C:/Snow/Ruby/dev/ruby_starter_140507/common/iconv.dll","${outdir}/debug_win_x86/iconv.dll" ) || warn "could not copy files:$!"; copy("C:/Snow/Ruby/dev/ruby_starter_140507/common/zlib1.dll","${outdir}/debug_win_x86/zlib1.dll" ) || warn "could not copy files:$!"; copy("C:/Snow/Ruby/dev/ruby_starter_140507/common/libxml2.dll","${outdir}/debug_win_x86/libxml2.dll" ) || warn "could not copy files:$!";
原文链接:https://www.f2er.com/regex/360799.html