Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/regex/17.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Regex 如何在OCaml中将字符串解析为正则表达式类型_Regex_Ocaml - Fatal编程技术网

Regex 如何在OCaml中将字符串解析为正则表达式类型

Regex 如何在OCaml中将字符串解析为正则表达式类型,regex,ocaml,Regex,Ocaml,我们定义的正则表达式类型如下: type regex_t = | Empty_String | Char of char | Union of regex_t * regex_t | Concat of regex_t * regex_t | Star of regex_t 我们想写一个函数string\u到\u regex:string->regex\u t 空字符串的唯一字符是“E” Char的唯一字符是'a'..'z' “|”表示Union

我们定义的正则表达式类型如下:

type regex_t =
    | Empty_String
    | Char of char
    | Union of regex_t * regex_t 
    | Concat of regex_t * regex_t 
    | Star of regex_t 
我们想写一个函数
string\u到\u regex:string->regex\u t

  • 空字符串的唯一字符是“E”
  • Char
    的唯一字符是'a'..'z'
  • “|”表示
    Union
  • “*”表示
    Star
  • Concat
    假设用于连续解析
  • “(“/”)的优先级最高,然后是星,然后是concat,然后是union
比如说,

(a | E)*(a | b)

Concat(Star(Union(Char 'a',Empty_String)),Union(Char 'a',Char 'b'))


如何实现
string\u to_regex

ocamlex和menhir是编写lexer和解析器的极好工具

ast.mli

type regex_t =
| Empty
| Char of char
| Concat of regex_t * regex_t
| Choice of regex_t * regex_t
| Star of regex_t
lexer.mll

{ open Parser }

rule token = parse
| ['a'-'z'] as c { CHAR c }
| 'E' { EMPTY }
| '*' { STAR }
| '|' { CHOICE }
| '(' { LPAR }
| ')' { RPAR }
| eof { EOF }
open Ast

let rec format_regex = function
| Empty -> "Empty"
| Char c -> "Char " ^ String.make 1 c
| Concat(a, b) -> "Concat("^format_regex a^", "^format_regex b^")"
| Choice(a, b) -> "Choice("^format_regex a^", "^format_regex b^")"
| Star(a) -> "Star("^format_regex a^")"

let () =
  let s = read_line () in
  let r = Parser.main Lexer.token (Lexing.from_string s) in
  print_endline (format_regex r)
parser.mly

%{ open Ast %}

%token <char> CHAR
%token EMPTY STAR CHOICE LPAR RPAR CONCAT
%token EOF

%nonassoc LPAR EMPTY CHAR

%left CHOICE
%left STAR
%left CONCAT

%start main
%type <Ast.regex_t> main

%%

main: r = regex EOF { r }

regex:
| EMPTY { Empty }
| c = CHAR { Char c }
| LPAR r = regex RPAR { r }
| a = regex CHOICE b = regex { Choice(a, b) }
| r = regex STAR { Star r }
| a = regex b = regex { Concat(a, b) } %prec CONCAT
并进行编译

ocamllex lexer.mll
menhir parser.mly
ocamlc -c ast.mli
ocamlc -c parser.mli
ocamlc -c parser.ml
ocamlc -c lexer.ml
ocamlc -c main.ml
ocamlc -o regex parser.cmo lexer.cmo main.cmo
然后

$ ./regex
(a|E)*(a|b)
Concat(Star(Choice(Char a, Empty)), Choice(Char a, Char b))

ocamlex和menhir是编写lexer和解析器的极好工具

ast.mli

type regex_t =
| Empty
| Char of char
| Concat of regex_t * regex_t
| Choice of regex_t * regex_t
| Star of regex_t
lexer.mll

{ open Parser }

rule token = parse
| ['a'-'z'] as c { CHAR c }
| 'E' { EMPTY }
| '*' { STAR }
| '|' { CHOICE }
| '(' { LPAR }
| ')' { RPAR }
| eof { EOF }
open Ast

let rec format_regex = function
| Empty -> "Empty"
| Char c -> "Char " ^ String.make 1 c
| Concat(a, b) -> "Concat("^format_regex a^", "^format_regex b^")"
| Choice(a, b) -> "Choice("^format_regex a^", "^format_regex b^")"
| Star(a) -> "Star("^format_regex a^")"

let () =
  let s = read_line () in
  let r = Parser.main Lexer.token (Lexing.from_string s) in
  print_endline (format_regex r)
parser.mly

%{ open Ast %}

%token <char> CHAR
%token EMPTY STAR CHOICE LPAR RPAR CONCAT
%token EOF

%nonassoc LPAR EMPTY CHAR

%left CHOICE
%left STAR
%left CONCAT

%start main
%type <Ast.regex_t> main

%%

main: r = regex EOF { r }

regex:
| EMPTY { Empty }
| c = CHAR { Char c }
| LPAR r = regex RPAR { r }
| a = regex CHOICE b = regex { Choice(a, b) }
| r = regex STAR { Star r }
| a = regex b = regex { Concat(a, b) } %prec CONCAT
并进行编译

ocamllex lexer.mll
menhir parser.mly
ocamlc -c ast.mli
ocamlc -c parser.mli
ocamlc -c parser.ml
ocamlc -c lexer.ml
ocamlc -c main.ml
ocamlc -o regex parser.cmo lexer.cmo main.cmo
然后

$ ./regex
(a|E)*(a|b)
Concat(Star(Choice(Char a, Empty)), Choice(Char a, Char b))

@Thomas的注释非常完整,但实际上运算符的优先级不正确:解析
a | aa
将导致
Concat(Choice(Char a,Char a,Char a)
,即等于
(a | a)a
。要求
a | aa=a |(aa)
,这将导致
选择(Char a,Concat(Char a,Char a))
。问题是,
CONCAT
标记是一种黑客行为,即使在
parser.mly
文件中的
%left-CHOICE
之前指定了
%left-CHOICE
,这并不意味着优先权将得到尊重。一个可能的解决方案是执行,有效地使语法明确无误。如果要使用此方法,可以使用以下内容修改
parser.mly

%{ open Ast %}

%token <char> CHAR
%token EMPTY
%token STAR
%token CHOICE
%token LPAR
%token RPAR
%token EOF

%start main
%type <Ast.regex_t> main

%%

main: r = regex EOF { r }

regex:
| r = disjunction { r }

disjunction:
| a = disjunction CHOICE b = concat { Choice(a, b) }
| r = concat {r}

concat:
| a = concat b = repetition { Concat(a, b) } 
| r = repetition {r}

repetition:
| r = repetition STAR { Star r }
| r = atom { r }

atom:
| LPAR r = regex RPAR { r }
| c = CHAR { Char c }
| EMPTY { Empty }

%{open Ast%}
%令牌字符
%令牌为空
%象征之星
%代币选择
%令牌LPAR
%令牌RPAR
%令牌EOF
%起动总管
%类型主
%%
main:r=regex EOF{r}
正则表达式:
|r=析取{r}
析取:
|a=析取选择b=连接{选择(a,b)}
|r=concat{r}
康卡特:
|a=concat b=repeation{concat(a,b)}
|r=重复{r}
重复:
|r=重复星{starr}
|r=原子{r}
原子:
|LPAR r=regex RPAR{r}
|c=CHAR{CHAR c}
|空的{EMPTY}

这不会导致歧义(=不需要指定运算符的关联性和优先级),并将产生正确的结果。

Thomas的注释非常完整,但实际上运算符的优先级不正确:解析
a | aa
将导致
Concat(Choice(Char a,Char a),Char a)
,即等于
(a | a)a
。要求
a | aa=a |(aa)
,这将导致
选择(Char a,Concat(Char a,Char a))
。问题是,
CONCAT
标记是一种黑客行为,即使在
parser.mly
文件中的
%left-CHOICE
之前指定了
%left-CHOICE
,这并不意味着优先权将得到尊重。一个可能的解决方案是执行,有效地使语法明确无误。如果要使用此方法,可以使用以下内容修改
parser.mly

%{ open Ast %}

%token <char> CHAR
%token EMPTY
%token STAR
%token CHOICE
%token LPAR
%token RPAR
%token EOF

%start main
%type <Ast.regex_t> main

%%

main: r = regex EOF { r }

regex:
| r = disjunction { r }

disjunction:
| a = disjunction CHOICE b = concat { Choice(a, b) }
| r = concat {r}

concat:
| a = concat b = repetition { Concat(a, b) } 
| r = repetition {r}

repetition:
| r = repetition STAR { Star r }
| r = atom { r }

atom:
| LPAR r = regex RPAR { r }
| c = CHAR { Char c }
| EMPTY { Empty }

%{open Ast%}
%令牌字符
%令牌为空
%象征之星
%代币选择
%令牌LPAR
%令牌RPAR
%令牌EOF
%起动总管
%类型主
%%
main:r=regex EOF{r}
正则表达式:
|r=析取{r}
析取:
|a=析取选择b=连接{选择(a,b)}
|r=concat{r}
康卡特:
|a=concat b=repeation{concat(a,b)}
|r=重复{r}
重复:
|r=重复星{starr}
|r=原子{r}
原子:
|LPAR r=regex RPAR{r}
|c=CHAR{CHAR c}
|空的{EMPTY}

这不会导致歧义(=不需要指定运算符的关联性和优先级),并将产生正确的结果。

这只是一个解析问题,对吗?我想说gasche最近给你写了一些优秀的代码,你可以修改。@JeffreyScofield是的,我试着从他的代码中学习,但我不认为我能理解或修改。这个正则表达式解析比sexp解析更复杂。我不认为我真的明白,盖什的解决方案是。这很容易掌握。从写一点语法开始。@JeffreyScofield但是这个正则表达式解析涉及操作符,它适合递归下降解析吗?你可以使用递归下降为一种严肃的语言构建一个编译器。(第一个Pascal编译器就是这样编写的。)是的,它将适用于您的RE语言。这只是一个解析问题,对吗?我想说gasche最近给你写了一些优秀的代码,你可以修改。@JeffreyScofield是的,我试着从他的代码中学习,但我不认为我能理解或修改。这个正则表达式解析比sexp解析更复杂。我不认为我真的明白,盖什的解决方案是。这很容易掌握。从写一点语法开始。@JeffreyScofield但是这个正则表达式解析涉及操作符,它适合递归下降解析吗?你可以使用递归下降为一种严肃的语言构建一个编译器。(第一个Pascal编译器是这样编写的。)是的,它将适用于您的RE语言。@JacksonTale(OP)我不确定您真正想要的是什么,但很难打败这个解决方案!请注意,即使您的令牌都是1个字符长的,仍然需要进行非平凡的词法分析。也就是说,你需要对它们进行分类。@JeffreyScofield我实际上是在寻找一种将字符串解析为正则表达式类型的原始方法,而不是使用Ocamlex和menhirI。我不得不说,我不明白这一点,但你可以使用递归下降法解决几乎任何解析问题。@JeffreyScofield我在做这个练习:你可以使用相同的想法。也就是说,一个lexer可以处理输入流的“标记”,然后将其处理成正则表达式语言,就像
parser.mly
一样。所以你有,
input\u channel->token list
,和
token list->regexp
。你甚至可以很容易地使通道处理变得懒惰。@JacksonTale(OP)我不是