此词法分析器允许您使用F#计算表达式以非常声明的方式定义基于正则表达式的规则。

F#
打开  Lexer
 让  定义=
    lexerDefinitions {
        做!addNextlineDefinition  “NEWLINE”  @ “(\ n \ r)| \ n | \ r”“
        做!addIgnoreDefinition  “WS”         @ “\ s”
        做!addDefinition  “让”              “让”
        做!addDefinition  “ID”               “(?i)[az] [a-z0-9] *”
        做!addDefinition  “FLOAT”            @ “[0-9] + \。[0-9] +”
        做!addDefinition  “INT”              “[0-9] +”
        做!addDefinition  “OPERATOR”         @ “[+ * =!/&| <> \ ^ \  - ] +”
    }

通过这些定义,您可以执行词法分析器:

F#
打开  Lexer
 让  lex输入=
     试试
        让  y = Lexer.tokenize定义输入
        printfn  “%A”  y
     与  e  - > printf  “%s”  e.Message
lex  “让a = 5”

这将导致:

F#
seq [
{name =  “LET”  ; text =  “let” ; pos =  0 ; column =  0 ; line =  0 ;};
{name =  “ID” ; text =  “a” ; pos =  4 ; column =  4 ; line =  0 ;};
{name =  “OPERATOR” ; text =  “=” ; pos =  6 ;列=  6 ; line =  0 ;};
{name =  “INT” ; text =  “5” ; pos =  8 ; column =  8 ; line =  0 ;}]

词法分析器的代码分为三个部分。第一部分是使用F#计算表达式的状态monad。这使得声明性方法(见上文)能够设置词法分析器规则。

F#
模块  StateMonad
 类型  State <'s,'a> = State  of  ('s  - >('a *'s))
 let  runState(State f)= f
 type  StateBuilder()=
     member  b.Return(x)= State(fun  s  - >(x,s))
     member  b.Delay(f)= f():State <'s,'a>
     member  b.Zero()= State(fun  s  - >((),s))
     成员  b.Bind(状态p,休息)=状态(有趣的  s  - >  让  v,s2 = p s  in   (runState(rest v))s2)
     成员  b.Get()=状态(有趣  的 - >(s,s) ))
     成员 b.Put s = State(fun  _  - >((),s))

第二部分是用于定义词法分析器规则的组合器。有三个主要组合器: AddDefinition允许您定义名称/正则表达式对, AddIgnoreDefinition允许您定义词法分析器应忽略的字符, AddNextlineDefinition允许您定义哪些字符确定新行。

F#
输入  LexDefinitions =
  {regexes:string list;
   名称:字符串列表;
   nextlines:布尔列表;
   忽略:布尔列表; } 

让  buildDefinition命名模式nextLine ignore =
    州{
        让!x = state.Get()
         做!state.Put {regexes = x.regexes @ [sprintf @ “(?<%s>%s)”  name pattern];
                        names = x.names @ [name];
                        nextlines = x.nextlines @ [nextLine];
                        ignores = x.ignores @ [ignore]}
    }
让  addDefinition名模式= buildDefinition名字模式  假 虚假
让利  addIgnoreDefinition名模式= buildDefinition名字模式  假 真
让  addNextlineDefinition名模式= buildDefinition名称模式  真 真实

最后一部分是执行标记化的代码。它使用Seq.unfold方法创建令牌列表。Unfold是一个函数,它接受一个项目并从中生成一个新项目列表。它与Seq.fold相反,它接受一个项目列表并将其转换为单个项目。tokenize函数使用Seq.unfold生成每个标记,同时跟踪当前行号,该行中的位置以及输入字符串中的位置。

F#
类型  Token =
    {name:string;
      text:string;
      pos:int;
      column:int;
      line:int} 

让  createLexDefs pb =(runState pb){regexes = []; names = []; nextlines = []; ignores = []} |> snd
 let  tokenize lexerBuilder(str:string)=
     let  patterns = createLexDefs lexerBuilder
     let  combinedRegex = Regex(List.fold(fun  acc reg  - > acc +  “|”  + reg)(List.head patterns。 regexes)(List.tail patterns.regexes))
     让  nextlineMap = List.zip patterns.names patterns.nextlines |> Map.ofList
     let  ignoreMap = List.zip patterns.names patterns.ignores |> Map.ofList
     let  tokenizeStep(pos, line,lineStart)=
         if  pos> = str.Length  then
            没有
        否则
            让  getMatchedGroupName(grps:GroupCollection)names = List.find(fun  (name:string) - > grps。[name] .Length>  0)名称
             匹配  combinedRegex.Match(str,pos)  with
                | 公吨  时  mt.Success && POS = mt.Index - >
                     让  组名= getMatchedGroupName mt.Groups patterns.names
                     让  柱= mt.Index - lineStart
                     让  nextPos = POS + mt.Length
                     让  (nextLine,nextLineStart)=  如果  nextlineMap.Item groupName  然后  (行+  1,nextPos)  else  (line,lineStart)
                     let  token =  if  ignoreMap.Item groupName
                                 then  None
                                 else  Some {
                                        name = groupName;
                                        text = mt.Value;
                                        post = post;
                                        line = line;
                                        column = column; }
                    一些(令牌,(nextPos,nextLine,nextLineStart))
                | 否则 - >
                    let  textAroundError = str.Substring(pos,min(pos +  5)str.Length)
                    raise(ArgumentException(sprintf  “Lexing error in line:%d and column:%d near text:%s”  line(pos  -  lineStart)textAroundError))
    Seq.unfold tokenizeStep(0,  0,  0)|> Seq.filter(有趣  X - > x.IsSome)|> Seq.map(有趣  X - > x.Value)

最后,这是使用XUnit.Net编写的单元测试:

F#
模块  LexerFacts
 开放  的xUnit
 开放  词法
 开放  System.Linq的
 让  simpleDefs =
    州{
        做!addNextlineDefinition  “NextLine”            “/”
        做!addIgnoreDefinition  “IgnoredSymbol”         “= +”
        做!addDefinition  “String”                      “[a-zA-Z] +”
        做!addDefinition  “Number”                      “\ d +”
        做!addDefinition  “名称”                        “马特”
    } 

[<事实>]
让  Will_return_no_tokens_for_empty_string()=
     让  令牌= Lexer.tokenize simpleDefs  “”
    Assert.Equal(0,tokens.Count()) 

[<事实>]
让  Will_throw_exception_for_invalid_token()=
     让  代币= Lexer.tokenize simpleDefs  “ - ”
    让  EX = Assert.ThrowsDelegateWithReturn(乐趣  () - >  向上转型  tokens.Count())|> Record.Exception
    Assert.NotNull(前)
    Assert.True(例如:?System.ArgumentException) 

[<事实>]
让  Will_ignore_symbols_defined_as_ignore_symbols()=
     让  令牌= Lexer.tokenize simpleDefs  “=========”
    Assert.Equal(0,tokens.Count()) 

[<事实>]
let  Will_get_token_with_correct_position_and_type()=
     let  tokens = Lexer.tokenize simpleDefs  “1one = 2 = two”
    Assert.Equal(“Number”,tokens.ElementAt(2).name)
    Assert.Equal(“2”,tokens.ElementAt(2).text)
    Assert.Equal(5,tokens.ElementAt(2).pos)
    Assert.Equal(5,tokens.ElementAt(2).column)
    Assert.Equal(0,tokens.ElementAt(2).line) 

[<事实>]
let  Will_tokenize_string_with_alernating_numbers_and_strings()=
     let  tokens = Lexer.tokenize simpleDefs  “1one2two”
    Assert.Equal(“1”,tokens.ElementAt(0).text)
    Assert.Equal(“one”,tokens.ElementAt(1).text)
    Assert.Equal(“2”,tokens.ElementAt(2).text)
    Assert.Equal(“two”,tokens.ElementAt(3).text) 

[<事实>]
let  Will_increment_line_with_newline_symbol()=
     let  tokens = Lexer.tokenize simpleDefs  “1one /
    2two ” Assert.Equal(“Number”,tokens.ElementAt(2).name)
    Assert.Equal(“2”,tokens.ElementAt(2).text)
    Assert.Equal(5,tokens.ElementAt(2).pos)
    Assert.Equal(0,tokens.ElementAt(2).column)
    Assert.Equal(1,tokens.ElementAt(2).line) 

[<事实>]
let  Will_give_priority_to_lexer_definitions_defined_earlier()=
     let  tokens = Lexer.tokenize simpleDefs  “Matt”
    Assert.Equal(“String”,tokens.ElementAt(0).name)

F#正则表达式的更多相关文章

  1. Codeforce727B --- Bill Total Value(字符串处理 正则表达式)

    先说一下正则表达式 %*[a-z]表示忽略前面的小写字符,%[0-9]表示把紧接着非字符的连续数字存入t字符串中去; 从"abc123de4f"中得到"123" ...

  2. JQuery中trim函数的具体实现代码

    由于Javascript 1.8.1 之前的版本,没有内置 trim 函数,所以 JQuery 对它有自己的实现.不同的JQuery版本,trim函数的实现也不尽相同. 阅读本文需要掌握正则表达式用法 ...

  3. vimer

    vimer 第1.0章.统一概念   不管学什么技术,我都深信概念是最重要的.是影响整个学习轨迹,决定能在这个技术领域高度. 当然如果你现在的目的不是在学习而在于解决问题(很多人不愿意承认,或者没发现 ...

  4. WinMerge 过滤器用法

    WinMerge是一款开源的文件对比合并工具.http://winmerge.org/WinMerge提供了“过滤器”功能,可以在对比时排除特定的目录或文件. 1.编辑过滤规则工具 -> 过滤器 ...

  5. 菜鸟vimer成长记——第1章、统一概念

    不管学什么技术,我都深信概念是最重要的.是影响整个学习轨迹,决定能在这个技术领域高度. 当然如果你现在的目的不是在学习而在于解决问题(很多人不愿意承认,或者没发现),那概念就暂时没那么重要了. 目的 ...

  6. pkill命令详解

    基础命令学习目录首页 原文链接:http://www.mamicode.com/info-detail-2315063.html 一:含义: 是ps命令和kill命令的结合,按照进程名来杀死指定进程, ...

  7. pkill详解

    pkill详解 一:含义: 是ps命令和kill命令的结合,按照进程名来杀死指定进程,pkill和killall应用方法差不多,也是直接杀死运行中的程序:如果您想杀掉单个进程,请用kill来杀掉. 二 ...

  8. mongodb增删改查操作

    Note:mongodb存储的是文档,且文档是json格式的对象,所以增删改查都必须是json格式对象. 注:mongodb常用库和表操作,但mongodb在插入数据时,不需要先创建表. show d ...

  9. Mysql_以案例为基准之查询

    查询数据操作

  10. F#之旅9 - 正则表达式

    今天,cozy群有个群友发了条正则,问正则匹配相关的问题.虽然他的问题用html selector去处理可能更好,但是我也再一次发现:我忘了正则怎么写的了! 忘掉正则是有原因的,这篇文章会简单记录下F ...

随机推荐

  1. Axios 中文说明

    Axios 是一个基于 promise 的 HTTP 库,可以用在浏览器和 node.js 中. Features 从浏览器中创建 XMLHttpRequests 从 node.js 创建 http  ...

  2. python3中使用builtwith的方法(很详细)

    1. 首先通过pip install builtwith安装builtwith C:\Users\Administrator>pip install builtwith Collecting b ...

  3. spring boot actuator专题

    spring-boot-starter-actuator模块的实现对于实施微服务的中小团队来说,可以有效地减少监控系统在采集应用指标时的开发量.当然,它也并不是万能的,有时候我们也需要对其做一些简单的 ...

  4. AWS的区域和可用区概念解释

    AWS的每个区域一般由多个可用区(AZ)组成,而一个可用区一般是由多个数据中心组成.AWS引入可用区设计主要是为了提升用户应用程序的高可用性.因为可用区与可用区之间在设计上是相互独立的,也就是说它们会 ...

  5. jquery的$.extend和$.fn.extend作用及区别/用span实现进度条/腾讯云IIS端口号修改

    jQuery为开发插件提拱了两个方法,分别是: jQuery.fn.extend(); jQuery.extend(); 虽然 javascript 没有明确的类的概念,但是用类来理解它,会更方便. ...

  6. Yii整合ucenter实现单点登录

    原文:http://www.php2.cc/article-1349-1.html 准备工作 1.下载ucenter源码,并安装好 2.下载ucenter开发源码,根据自己的项目下载对应版本(utf- ...

  7. python高级编程1

    1.如何在列表,字典,集合中根据条件筛选数据? 如: 过滤列表[3, 9, -1, 10, 20, -2...]中的负数 筛出字典{‘小明’:70, 'Jim':88,'Tom':98...}中值高于 ...

  8. dirlock_windows.go

    package dirlock type DirLock struct {     dir string } func New(dir string) *DirLock {     return &a ...

  9. 渐进式Web应用(PWA)入门教程(下)

    上篇文章我们对渐进式Web应用(PWA)做了一些基本的介绍. 渐进式Web应用(PWA)入门教程(上) 在这一节中,我们将介绍PWA的原理是什么,它是如何开始工作的. 第一步:使用HTTPS 渐进式W ...

  10. oracle改造常见问题

    一. to_char: 将数值型或者日期型转化为字符型 (string) 日期到字符操作 select to_char(sysdate,'yyyy-MM-dd HH24:mi:ss') from du ...