• IC入职新同学必备技能手册②


    欢迎关注个人公众号摸鱼范式

    转载自:https://zhuanlan.zhihu.com/fpga-hw-discussion

    作者:知乎用户生的安格斯牛排

    PERL

    马上开始

    • 推荐一个online Perl editor,随写随执行,我经常用来验证吃不准的写法(间接说明Perl的蛋疼),免费的。
    • 后面所有代码都可以直接copy+paste到online editor里面试运行,边试边写才好。

    https://www.jdoodle.com/execute-perl-online

    然后再推荐一个中文Perl使用速查工具网站(很基本,但高级用法不全面)

    www.runoob.com

    Perl脚本的主要用途

    • 最重要的就是处理文本,和一些Hash类的config数据;
    • 因为Perl也支持类操作(简单的继承,貌似没有虚函数功能-就是类函数的重定义),因此,一些in-house的EDA flow会用Perl作为接口语言。比如nv的Clock design system.
    • 铺垫了很多Perl如何语法不严谨,但是,看完这篇文章,你会觉得Perl也就那么回事。注意,本文并没有提供特高级的Perl套路,仅仅用于普通IC工程师的普通操作。

    套路1:变量

    • Perl语言其实没有数据类型的区别,任何数据(整数、浮点数、字符、字符串)都一视同仁,随便处理。
    • Perl根据数据的组织形式,分为标量($)、数组(@)、哈希量(%)
    • 变量有作用域的区别,一般my表示局部变量(怎么局部,以code block决定,或者不管它,无脑my->my过一次就不能再my了。。);our表示全局标量
    # 普通变量(标量)
    my $var = 1;
    $var = 'abc'; 
     # 不能再my啦!双引号允许使用转义字符,单引号不行
     # 比如'
    ',就是认为是
    ,而不是换行符
    
    # 数组
    my @arr = ('a', 1, 'string a b');
    
    # 哈希
    # 很少使用%my_hash这样的形式定义hash, 这个叫显性定义
    # 更多的是使用所谓“隐性”定义,例如
    $my_hash = {
        'chip_name' => 'ga100',
        'tree_path' => {
            'current' => '/home/abc',
            'old'  => '/home/xyz',
        },
    };  # Perl语言对于白空格很随意,
        # 用分号结尾即可
    
    print $my_hash->{'chip_name'} , "
    "; 
    (结果是) ga100
    print $my_hash->{'tree_path'}->{'old'}, "
    ";
    (结果是) /home/xyz
    

    套路1.1:特殊功能和变量

    $_

    $_  # 可以将它理解为,
        #当前代码块的默认变量
        # 尤其常用于foreach
    # example
    my @arr = (a, b, c); 
      # 定义数组,字符可以忽略引号
    print $_, "
    " foreach @arr;  
      # 这里$_ foreach循环中的当前元素
    
    # 输出
    a
    b
    c
    

    @_

    @_  # 用于函数传参,
    # 对!Perl的子函数,没有C那样的参数列表,
    # 想传什么就传什么
    # 具体例子在函数套路中讲解
    

    die / unless

    die # 其实就是强制异常退出
    # 比如
    die ("Error happened!"); 
    # 这句话强制让脚本退出,
    # 且在terminal输出这句话,作为error msg.
    # ===========
    # 配合unless. unless其实的作用类似if语句
    # 比如
    die ("File $file_path is not found.") unless (-e $file_path); 
       # -e 是代表检测文件是否存在
       # 翻译过来就是,强制退出并提示信息,除非!$file_path文件存在.
    

    next/last : 用于循环中,顾名思义,next强制跳过当前循环,进入下一个。last表示,强制结束本次循环,跳出循环block(不管循环还有多少次结束)

    chomp : 非常常用!用于去掉字符串结尾的换行符,也就是 。为啥?

    my $path = `pwd`;  # ``表示执行shell命令
    die ("The folder not exist.") unless (-d $path);  
       # die/unless出现啦, -d表示检测文件夹是否存在
       # 但是!无论$path存在与否,这句话肯定会强制退出,
       # 因为`pwd`的返回字符串结尾有换行符,经常在这里吃亏。
    # ========================
    # 换种方式
    my $path = `pwd`;
    chomp($path);  # 去掉换行符
    die ("The folder not exist.") unless (-d $path); 
       # 这样就不会因为换行符的缘故,误退出了。
    

    套路2:逻辑分支(if..else.. foreach)

    if..else.. 巨简单。

    if ($var == 1) {
      # 对于数值量比较, == , <= , >= , < , > 都可以 
    } elsif {$var eq 'abc'}  {
      # 这里注意!第一,Perl使用elsif, 而不是elseif !
      # 注意这里用的是eq !
      # 对于字符串的相等,只能用eq (equal) 和 ne (not equal)。
    } else {
      # 嗯,else还是和其他语言类似的
    }
    

    foreach循环

    # foreach循环其实有两种套路
    # 普通的
    my @arr = (a , b , c);
    foreach my $elem (@arr)  {  
     # 注意:my的使用,因为$elem前面没定义,
     # 所以这里必须定义用my。
     # 其次, elem的作用域仅仅在这个foreach block
     # 括号()是标准格式哦,常常忘记
    
     print "Current elem is $elem 
    ";  # 常规用法
     # 为啥不能用$_ ?因为你都指定每个元素放在$elem里啦!
    }
    # 想用$_ ?
    foreach (@arr) {
       print "Current elem is $_    
    " ; 
        # 可以的。没必要为了用$_而用,看个人习惯。
    }
    

    ===

    # foreach循环最常用的是搭配哈希,
    # 为啥,因为IC环境里面,hash存储着大量的config数据,
    # 需要拿出来各种操作
    my $my_hash = {
           'ga100' => 'go_fab',
           'gv100' => 'shipped',
           'gm100' => 'shipped'
    }; 
    
    foreach my $chip_name (keys %{$my_hash}) {  
      # 这里有点复杂:
      # keys 是Perl內建命令,用于返回参数hash当前层次的所有key name
      # %{}  表示将隐性定义的hash强制转换为显性,
        # 为啥,因为keys只认显性hash
      # $my_hash 你会迷糊,$不是表示标量么?
      # 对,但这里的标量可以理解为hash数据结构的头指针
       
    print "$chip_name status:  $my_hash->{$chip_name} 
    " ;
    
    }
    
    (结果是)
    gm100 status:  shipped 
    ga100 status:  go_fab 
    gv100 status:  shipped 
    

    正则表达式 (regular expression -> regex)

    • 什么是正则表达式?(这个定义问题真的难到我了,以下来自百度)

    正则表达式通常被用来检索、替换那些符合某个模式(规则)的文本。

    • 正则表达式能用到哪些地方?

      • Perl/Tcl/etc (用于脚本中,对string进行搜索、替换,其表达式语法是通用的,并不因为脚本不同有区别)
      • sed/grep (Linux shell cmd)
      • vim/gvim (用于完成文本查找、替换)
    • 为什么要提到正则表达式

      • 因为Perl只所以被广泛使用,就是因为内建强大的正则表达式功能,配合灵活的语法,轻松完成脚本内文本匹配、搜索、替换等功能。

    正则表达式 (regex)难不难?

    对于刚刚接触它的同学来说,略不友好,其语法、各种各样的灵活组合,看起来有点像天书。如下举例:

    (?!(.*_PADCAL_MASK|.*HBM_MISR_MASK|.*POWER_CTL_MASK|.*RG_CTL_MASK))(.*MASK.*)
    

    有点懵逼,是吧。淡定,我选择了一个复杂度较高的例子。大部分日常使用的正则表达式并没有这么复杂。

    强烈推荐下面这个免费的regex tester:它提供了online的regex测试、解析,并且例举了全部的可用语法元素。当我碰到不确定的正则表达式 (regex),我就会来这里去验证。

    https://regex101.com/

    下面开始举例+学习 (for Perl)

    再次说明,只看不试是不行的,把下面的regex表达式copy到上面的Online tester里面试试。

    既然regex是用来做文本操作,那么我们先设置一个sample text

    # 在Perl中定义一个这样数组,4个元素
    my @path_arr = (
     '/home/scratch.john_gpu/gv100',
     '/home/scratch.mike_gpu/ga100',
     '/home/scratch.mike_gpu/lr10',
     '/home/scratch.ema_ate/regression' 
    );
    

    问题1: 找到所有含_gpu的元素

    foreach my $elem (@path_arr) {
     # foreach大家还记得吧
     if ($elem =~ /_gpu/ ) {
      print "$elem 
    ";
     }
    }
    #结果是:
    /home/scratch.john_gpu/gv100
    /home/scratch.mike_gpu/ga100
    /home/scratch.mike_gpu/lr10
    
    • 这个符号组合 =~ 是什么?

      • =~ 是Perl语言中使用正则表达式去判定“是否命中”
      • 同理,还有一个 !~ ,表示用Regex判定“是否没命中”
    • /_gpu/ 是啥?

      • / / 是正则表达式的边界符,里面的称之为“正则表达式”
      • _gpu 就是一个最简单的正则表达式,因为我想搜索哪个元素带有_gpu,那就直接用明文啦。

    问题2:找到所有含_gpu/ga100元素

    foreach my $elem (@path_arr) {
     if ($elem =~ /_gpu/ga100/ ) {
      print "$elem 
    ";
     }
    }
    #结果是:
    /home/scratch.mike_gpu/ga100
    
    • 正则表达式是啥? _gpu/ga100

    • 为毛不直接用 _gpu/ga100

      • 因为你想搜索的符号/与regex的边界符冲突,对于这种情况(即被搜索符号与regex的语法元素冲突),使用反斜杠 (back-slash)进行转义(escape-char)。类似换行符

    问题3:找到符合mike**ga100的元素 (*表示不在乎中间是什么字符)

    foreach my $elem (@path_arr) {
     if ($elem =~ /mike.*ga100/ ) {
      print "$elem 
    ";
     }
    }
    #结果是:
    /home/scratch.mike_gpu/ga100
    
    • 这是什么-> .*

      • 这是一个基础的正则表达式啦,要分开说:

      • . 表示任意单个字符 (无论是数字、字母、标点符号、任意的东西)

      • * 表示约束预期出现的个数,允许0-无穷

        • 有没有人想问,1-无穷用哪个? + 咯
      • .* 表示,匹配任意字符且出现任意个数。匹配任意东西。

    • 也许,到此为止,对 .* 还是不理解,那么:

      • /w* 首先,/w表示任意字母,还是表示任意个数。那么,/w 表示预期匹配任意个数的字母。
      • /d* /d表示0-9的任意数字,/d*就是预期匹配任意个数的数字啦。
      • /d+ /d表示0-9的任意数字,/d+就是预期匹配至少出现一次的数字啦。

    问题4:(变得稍微复杂啦) 找到所有g?100的元素(?定义为任意一个字母),并且将g?100这部分字段提取,并打印出来

    foreach my $elem (@path_arr) {
     if ($elem =~ /(gw100)/ ) {
      print "$1 
    ";
     }
    }
    #结果是:
    ga100
    gv100
    
    • w是啥,还记得吧,表示任意字母。

    • 为啥没*了

      • 因为题目要求只要一个文字呀
    • 这次怎么多了一个括号?

      • 这是关键点,这是Regex的匹配且提取
      • 提取什么?能匹配括号里regex的字段咯。
    • $1是什么?

      • 这是Perl语法,如果if语句中,能够发生匹配成功,则$1, $2, $3 ... 存储了每个括号中的匹配字段。
      • 能有$2么?能啊,如果有两个括号,且都匹配成功

    问题5:(我们要尝试替换啦) 找到所有g?100的元素,并且将g?100替换成lr10

    foreach my $elem (@path_arr) {
     $elem =~ s/gw100/lr10/ ;
     print "$elem 
    " ;
    }
    #结果是:
     /home/scratch.john_gpu/lr10
     /home/scratch.mike_gpu/lr10
     /home/scratch.mike_gpu/lr10   # 这个出现意外不
     /home/scratch.ema_ate/regression # 这个出现意外不
    
    • 意外吧,为啥后面两个也出来了?

      • 因为 $elem =~ s/gw100/lr10/ ; 这句话,只是匹配然后替换;如果没有匹配成功,自然不会发生替换。

      • s/// 是啥。

        • 这个是标准的regex替换表达式,s表示替换操作,/// 是分隔符,分隔出了两段空间。
        • 第一段空间是匹配表达式
        • 第二段空间的意义: 如果匹配成功,则将符合匹配的字符串替换成第二段空间的文字

    问题6:(再高级一点)找到所有g?100元素,并将原字段替换成大写的。

    foreach my $elem (@path_arr) {
     if ($elem =~ /gw100/) {
      $elem =~ s/(gw100)/U$1E/ ;
      print $elem, "
    " ;
     }
    }
    #结果是:
     /home/scratch.john_gpu/GV100
     /home/scratch.mike_gpu/GA100
    
    • print函数没用错,可以用逗号进行字符串拼接

    • s/// 出现啦:

      • 第一段中,为啥有括号,因为我们不光要匹配,还要抽取匹配的字段
      • 第二段,$1好理解吧,UE是一个搭配组合,表示中间的字段转换为大写。

    问题7:Perl常见的传参变量内容替换套路

    这样的代码很常见:传递过来一个变量A,我想对A中的字符串内容进行一些操作(比如替换),但我又不想更改A的内容,那么:

    my $A = 'my name is jason' ;
    (my $B = $A) =~ s/jason/emma/;
    print "A = $A 
    ";
    print "B = $B 
    ";
    
    #结果是:
    A = my name is jason
    B = my name is emma
    

    写在最后

    本篇内容重在抛砖引玉(cover的内容其实很浅),我墙裂建议学习regex的时候,将更多的尝试和验证放在online regex tester上,实践出真知嘛。

  • 相关阅读:
    http和https的区别与联系
    HTTP请求/响应报文结构
    Java并发包中Lock的实现原理
    Java多线程基础——Lock类
    深入理解Java并发之synchronized实现原理
    ConcurrentHashMap 的实现原理
    【Java集合学习】HashMap源码之“拉链法”散列冲突的解决
    趣谈Java变量的可见性问题
    Java中CAS详解
    LockSupport的park和unpark的基本使用,以及对线程中断的响应性
  • 原文地址:https://www.cnblogs.com/icparadigm/p/12958490.html
Copyright © 2020-2023  润新知