PERL/LEX/YACC技术实现文本解析--XML解析

   2023-02-09 学习力0
核心提示:继周六的p_enum.pl后,再来一篇说说我用perl做的lex,yacc工具。之前说了,我学习lex和yacc的最初动机是为了做个C语言解释器的SHELL;但后来工作中的实际需要也是制作perl版lex和yacc的一个动机。Perl库里有lex和yacc,我没研究过,想来应该比我做的强大,不

继周六的p_enum.pl后,再来一篇说说我用perl做的lex,yacc工具。之前说了,我学习lex和yacc的最初动机是为了做个C语言解释器的SHELL;但后来工作中的实际需要也是制作perl版lex和yacc的一个动机。Perl库里有lex和yacc,我没研究过,想来应该比我做的强大,不过对新手来说,未必能容易入手。

我的第一个应用场景是做一个xml配置文件的排序。XML是标签标记语言,同一级下,TAG顺序本身是无所谓的;但对于测试工作来说,经常要通过文本比较工作来确定两个配置文件差别。如果没有办法将配置文件内容正确排序,对比一个几十K的配置文件,就会耗费个把钟头。对于有频繁对比内容的测试需要来说,这绝对是无法忍受。

那期间,我正在研究编译原理,以及lex和yacc,自然萌生了做个xml解析器的想法。有了xml解析器,就能将xml内容按hash、array组合方式在perl里表达成对应的数据结构,而排序也就自然不再是个问题。

工具及xml示例下载地址:
https://files.cnblogs.com/files/hhao020/perl_zlib_re0.001.rar

要做xml的解析,首先需要定义lex词法文件xml.lex:

%%prioritized from top to bottom
<!--.*-->  := comment
<\?.*?>    := version
</.*?>       := end
<.*?/ >      := sigton
<.*>         := begin
         := value

接着,需要定义yacc的语法文件xml.yacc:

%yacc%
%%prioritized from bottom to top
xml := version EOF       { Xml_Version }
     | version pair EOF  { Xml_VersionPair }
pair := pair pair        { Pair_PairPair }
pair := begin end        { Pair_BeginEnd }
     | begin value end       { Pair_BeginValueEnd }
     | begin pair end        { Pair_BeginPairEnd }
     | begin value pairs end { Pair_BeginValuePairEnd }
     | sigton                { Pair_Sigton }
     | comment               { Pair_Comment }     

%code%
package xml;
use strict;
use warnings;

sub _XmlAlarmMock
{
  print @_;
}
sub _XmlDebugMock
{
  my $debugInfo = shift;
  #print "$debugInfo\n";
  
  sub _printMock{print @_;};
  #&zDebug::DataDump(\&_printMock, \@_);
}

sub _XmlCheckNode
{
  my $refNode = shift;
  
  if($refNode->{BEGIN})
  {
    my $begin = $refNode->{BEGIN}->{TEXT};
    my $end  = $refNode->{END}->{TEXT};

    printf("##### check node $begin, $end.\n");

    $begin =~ /^<([a-zA-Z_0-9]+)/;
    my $a = $1;
    $end =~ /^<\/([a-zA-Z_0-9]+)/;
    my $b = $1;
  
    if($a ne $b)
    {
      &zDebug::DataDump(\&_XmlAlarmMock, $refNode);
      &zDebug::DataDump(\&_XmlAlarmMock, $refNode->{BEGIN});
      &zDebug::DataDump(\&_XmlAlarmMock, $refNode->{END});
      my $line = $refNode->{BEGIN}->{LINE};
      print "\nBEGIN <$a> at LINE [$line] missing END!!!\n";
      exit(0);
    }
  }
=pod  
  if($refNode->{VALUE})
  {
    my $value = $refNode->{VALUE}->{TEXT};
  
    if($value =~ /[<>]/)
    {
      &zDebug::DataDump(\&_XmlAlarmMock, $refNode);
      &zDebug::DataDump(\&_XmlAlarmMock, $refNode->{VALUE});
    
      print "\nVALUE contains <>!!!\n";
      exit(0);
    }
  }
=cut  
}

sub _XmlCheckValue
{
  my $refNode = shift;
  
  
}

sub Xml_Version
{
  my @params = @_;  
  &_XmlDebugMock(&zError::FunName().' ['.&zError::FileLine().']', \@_);
      
  my @pair;
  my %xml = (VERSION=>$params[0], PAIR=>\@pair);
  
  return \%xml;
}

sub Xml_VersionPair
{
  my @params = @_;  
  &_XmlDebugMock(&zError::FunName().' ['.&zError::FileLine().']', \@_);
  
  my %xml = (VERSION=>$params[0], PAIR=>$params[1]);
  return $params[0];
}

sub Pair_BeginEnd
{
  my @params = @_;  
  &_XmlDebugMock(&zError::FunName().' ['.&zError::FileLine().']', \@_);
  
  my %node;
  $node{BEGIN} = $params[0];
  $node{END} = $params[1];
  
  &_XmlCheckNode(\%node);
  
  my @pair = (\%node,);
  return \@pair;
}

sub Pair_BeginValueEnd
{
  my @params = @_;  
  &_XmlDebugMock(&zError::FunName().' ['.&zError::FileLine().']', \@_);
    
  my %node;
  $node{BEGIN} = $params[0];
  $node{VALUE} = $params[1];
  $node{END} = $params[2];
  
  &_XmlCheckNode(\%node);
  
  my @pair = (\%node,);
  return \@pair;
}

sub Pair_Sigton
{
  my @params = @_;  
  &_XmlDebugMock(&zError::FunName().' ['.&zError::FileLine().']', \@_);
    
  my %node;
  $node{SIGTON} = $params[0];
  
  my @pair = ($params[0],);
  return \@pair;
}

sub Pair_Comment
{
  my @params = @_;  
  &_XmlDebugMock(&zError::FunName().' ['.&zError::FileLine().']', \@_);
    
  my %node;
  $node{COMMENT} = $params[0];
  
  my @pair = (\%node,);
  return \@pair;
}

sub Pair_BeginPairEnd
{
  my @params = @_;  
  &_XmlDebugMock(&zError::FunName().' ['.&zError::FileLine().']', \@_);
    
  my %node;
  $node{BEGIN} = $params[0];
  $node{PAIR} = $params[1];
  $node{END} = $params[2];
  
  &_XmlCheckNode(\%node);
  
  my @pair = (\%node,);
  return \@pair;
}

sub Pair_BeginValuePairEnd
{
  my @params = @_;  
  &_XmlDebugMock(&zError::FunName().' ['.&zError::FileLine().']', \@_);
    
  my %node;
  $node{BEGIN} = $params[0];
  $node{VALUE} = $params[1];
  $node{PAIR} = $params[2];
  $node{END} = $params[3];
  
  &_XmlCheckNode(\%node);
  
  my @pair = (\%node,);
  return \@pair;
}

sub Pair_PairPair
{
  my @params = @_;    
  &_XmlDebugMock(&zError::FunName().' ['.&zError::FileLine().']', \@_);
  
  push @{$params[0]}, @{$params[1]};
    
  return $params[0];
}
View Code
 
反对 0举报 0 评论 0
 

免责声明:本文仅代表作者个人观点,与乐学笔记(本网)无关。其原创性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容、文字的真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
    本网站有部分内容均转载自其它媒体,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责,若因作品内容、知识产权、版权和其他问题,请及时提供相关证明等材料并与我们留言联系,本网站将在规定时间内给予删除等相关处理.

  • Linux下安装Perl和Perl的DBI模块
    今天在虚拟机测试shell脚本的时候,有些命令使用不了。比如说 mysqlhotcopy ,它提示Perl的版本太低。我用的 RedHat9 的Perl才5.8.0版本。。。(2002年以前的)严重过时。所以重新安装了新版本的 Perl,过程记录如下: 1、在官方网站下载新版本的源码包:http:
    03-16
  • Perl 与Form
    说明事项: 這個範例用來說明如何經由網頁上的HTML form 表單元件來呼叫伺服器端的perl 程式。这个范例用来说明如何经由网页上的HTML form 表单元件来呼叫伺服器端的perl 程式。首先在網頁上設計表單元件,這個範例是設計一個按鈕,其原始碼如下:首先在网页
    02-10
  • Perl学习 perl培训
    http://www.sun126.com/perl5/perl5-1.htm翻译: flamephoenix 第一章 概述一、Perl是什么?二、Perl在哪里?三、运行四、注释一、Perl是什么?  Perl是Practical Extraction and Report Language的缩写,它是由Larry Wall设计的,并由他不断更新和维护,用
    02-10
  • - calm_水手">Perl中的箭头符-> - calm_水手
    Perl中的箭头符-2012-05-21 17:14 calm_水手 阅读(623) 评论(0) 编辑 收藏 举报  有两种用法,都和解引用有关。第一种用法,就是解引用。根据 - 后面跟的符号的不同,解不同类型的引用,-[] 表示解数组引用,-{} 表示解散列引用,-() 表示解子程序引
    02-09
  • Regex in Perl
    Regex in Perl
    regex literal   代表正则文字, 就是 m/regex/ 部分中的 regex, 这部分有自己的解析规则. 用 Perl 的行话就是 "表示正则含义的双引号字符串(regx-aware double-quoted string)", 及处理后传递给正则引擎的结果. 正则文字支持的特性:  1. 变量插值.    
    02-09
  • perl脚本语言学习 perl脚本调用perl脚本
    来公司的第二个星期便看了一下perl语言,发现掌握一门脚本语言还是非常有用的。到现在为止已经入职两个月,用perl脚本做了这些活:1. 修改了公司的一个爬取网页源代码的脚本2. 改进了一个出特征库的脚本,根据svn status的状态,来优化,将只需要添加的DB的数
    02-09
  • Perl模块的安装方法 perl 安装模块
    1. 下载离线安装包 *.tar.gz的形式解包后,#perl Makefile.PL#make#make install2. 在联网的情况下,通过CPAN安装# perl -MCPAN -e shellcpan install PAR::Packer 
    02-09
  • Perl像C一样强大,像awk、sed等脚本描述语言一
    Perl是由Larry Wall设计的,并由他不断更新和维护的编程语言。Perl具有高级语言(如C)的强大能力和灵活性。事实上,你将看到,它的许多特性是从C语言中借用来的。Perl与 脚本语言一样,Perl不需要编译器和链接器来运行代码,你要做的只是写出程序并告诉Perl
    02-09
  • 27-Perl 进程管理
    1.Perl 进程管理Perl 中你可以以不同的方法来创建进程。本教程将讨论一些进程的管理方法。你可以使用特殊变量 $$ 或 $PROCESS_ID 来获取进程 ID。%ENV 哈希存放了父进程,也就是shell中的环境变量,在Perl中可以修改这些变量。exit() 通常用于退出子进程,主
    02-09
  • 在perl中简单的正则匹配 正则匹配或的使用
    (一)、在perl中关于元字符的匹配元字符代表含义点号( .)匹配处换行符以外的任何单字符星号(*)匹配前面的内容零次或多次反斜线屏蔽元字符的特殊含义。\\代表\,\.匹配点号.*匹配所有的字符串加号(+)匹配前一个条目一次以上问号(?)表示前面一个条目可
    02-09
点击排行