Current section
Files
Jump to
Current section
Files
src/xs_regex_parser.yrl
Nonterminals
regExp
branch
piece
quantity
quantifier
atom
charClass
charClassExpr
charGroup
posCharGroup
negCharGroup
charGroupPart
charGroupParts
singleChar
charRange
charClassEsc.
Terminals
'sub' '|' '?' '*' '+' '?:'
'{' '}' '(' ')' '[' ']' '-' '^' '$'
'BackReference'
'CatEsc'
'ComplEsc'
'MultiCharEsc'
'MultiCharComplEsc'
'NormalChar'
'QuantExact'
'QuantMin'
'QuantRange'
'SingleCharEsc'
'SingleCharNoEsc'
'WildcardEsc'.
Rootsymbol regExp.
Nonassoc 100 '|'.
Left 101 'charGroup'.
Left 102 'quantifier'.
%% Regular Expression
%[64] regExp ::= branch ( '|' branch )*
regExp -> branch : [{branch,'$1'}].
regExp -> branch '|' regExp : [{branch,'$1'}|'$3'].
%% Branch
%[65] branch ::= piece*
branch -> piece : ['$1'].
branch -> piece branch : ['$1'|'$2'].
%% Piece
% [66] piece ::= atom quantifier?
piece -> atom : {piece, '$1',one}.
piece -> atom quantifier : {piece, '$1','$2'}.
%% Quantifier
%[67] quantifier ::= ( [?*+] | ( '{' quantity '}' ) ) '?'?
quantifier -> '?' : {q,"?"}.
quantifier -> '?' '?' : {q,"??"}.
quantifier -> '*' : {q,"*"}.
quantifier -> '*' '?' : {q,"*?"}.
quantifier -> '+' : {q,"+"}.
quantifier -> '+' '?' : {q,"+?"}.
quantifier -> quantity : {q,'$1'}.
quantifier -> quantity '?': {q,'$1'++"?"}.
%[68] quantity ::= QuantRange | QuantMin | QuantExact
quantity -> 'QuantRange' : val('$1').
quantity -> 'QuantMin' : val('$1').
quantity -> 'QuantExact' : val('$1').
%% Atom
%[72] atom ::= NormalChar | charClass |
% ( '(' '?:'? regExp ')' ) | backReference
%[72a] backReference ::= "\" [1-9][0-9]*
atom -> 'NormalChar' : {char,val('$1')}.
atom -> '-' : {char,"-"}.
atom -> 'sub' : {char,"-"}.
atom -> charClass : '$1'.
atom -> '(' regExp ')' : {paren,'$2'}.
atom -> '(' ')' : {char,"()"}.
atom -> '(' '?:' regExp ')': {nc_paren,'$3'}.
atom -> '(' '?:' ')': {char,"(?:)"}.
atom -> 'BackReference' : {back_ref,list_to_integer(tl(val('$1')))}.
%% Character Class
%[74] charClass ::= SingleCharEsc | charClassEsc | charClassExpr |
% WildcardEsc | '^' | '$'
charClass -> 'SingleCharEsc' : {char, val('$1')}.
charClass -> charClassEsc : '$1'.
charClass -> charClassExpr : '$1'.
charClass -> 'WildcardEsc' : {char, val('$1')}.
charClass -> '^' : val('$1').
charClass -> '$' : val('$1').
%% Character Class Expression
%[75] charClassExpr ::= '[' charGroup ']'
charClassExpr -> '[' charGroup ']' : '$2'.
%% Character Group
%[76] charGroup ::= ( posCharGroup |
% negCharGroup ) ( '-' charClassExpr )?
charGroup -> posCharGroup :
{group,'$1'}.
charGroup -> posCharGroup 'sub' charClassExpr :
{subtract,{group,'$1'},'$3'}.
charGroup -> negCharGroup :
{neg_group,'$1'}.
charGroup -> negCharGroup 'sub' charClassExpr :
{subtract,{neg_group,'$1'},'$3'}.
%% Positive Character Group
%[77] posCharGroup ::= ( charGroupPart )+
posCharGroup -> charGroupParts : '$1'.
charGroupParts -> charGroupPart : ['$1'].
charGroupParts -> charGroupPart quantifier : ['$1'].
charGroupParts -> charGroupPart '|' charGroupParts : ['$1'|'$3'].
charGroupParts -> charGroupPart charGroupParts : ['$1'|'$2'].
%%Negative Character Group
%[78] negCharGroup ::= '^' posCharGroup
negCharGroup -> '^' posCharGroup : '$2'.
%% Character Group Part
%[79] charGroupPart ::= singleChar | charRange | charClassEsc
charGroupPart -> singleChar : char_group_part('$1').
charGroupPart -> '(' : {value,$(}.
charGroupPart -> ')' : {value,$)}.
charGroupPart -> '?' : {value,$?}.
charGroupPart -> charRange : '$1'.
charGroupPart -> charClassEsc : '$1'.
%[80] singleChar ::= SingleCharEsc | SingleCharNoEsc
singleChar -> 'SingleCharEsc' : val('$1').
singleChar -> 'SingleCharNoEsc' : val('$1').
singleChar -> 'NormalChar' : {char,val('$1')}.
singleChar -> 'WildcardEsc' : {char,val('$1')}.
singleChar -> '}' : {char,"}"}.
singleChar -> '{' : {char,"{"}.
singleChar -> '-' : {char,"-"}.
%% Character Range
%[81] charRange ::= singleChar '-' singleChar
charRange -> singleChar '-' singleChar : char_range('$1', '$3').
%% Character Class Escape
%[83] charClassEsc ::= ( MultiCharEsc | catEsc | complEsc )
charClassEsc -> 'MultiCharEsc' :
{char_class, val('$1')}.
charClassEsc -> 'MultiCharComplEsc' :
{neg_char_class, val('$1')}.
charClassEsc -> 'CatEsc' :
{char_class, strip_cat_brackets(val('$1'))}.
charClassEsc -> 'ComplEsc' :
{neg_char_class, strip_cat_brackets(val('$1'))}.
%% Category Escape ---- do these in the scanner as Terminals
%[85] catEsc ::= '\p{' charProp '}'
%[86] complEsc ::= '\P{' charProp '}'
%[87] charProp ::= IsCategory | IsBlock
%MultiCharEsc = \\[sSiIcCdDwW]
Expect 1. % one conflict
Erlang code.
%% -------------------------------------------------------------------
%%
%% xs_regex - XML Schema regex translation
%%
%% Copyright (c) 2017-2018 Zachary N. Dean All Rights Reserved.
%%
%% This file is provided to you under the Apache License,
%% Version 2.0 (the "License"); you may not use this file
%% except in compliance with the License. You may obtain
%% a copy of the License at
%%
%% http://www.apache.org/licenses/LICENSE-2.0
%%
%% Unless required by applicable law or agreed to in writing,
%% software distributed under the License is distributed on an
%% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
%% KIND, either express or implied. See the License for the
%% specific language governing permissions and limitations
%% under the License.
%%
%% -------------------------------------------------------------------
%% @doc REGEX parser (https://www.w3.org/TR/xmlschema11-2/#regex-branch).
-compile([{hipe,[{regalloc,linear_scan}]}]).
val({_,_,Token}) ->
Token.
strip_cat_brackets("\\p{" ++ Rest) ->
lists:droplast(Rest);
strip_cat_brackets("\\P{" ++ Rest) ->
lists:droplast(Rest).
char_range(Min, Min) when is_tuple(Min) -> {value,hd(element(2,Min))};
char_range(Min, Min) when length(Min) > 1 -> {value,hd(tl(Min))};
char_range(Min, Min) -> {value,hd(Min)};
char_range(Min, Max) when is_tuple(Min) andalso is_tuple(Max) ->
{range,hd(element(2,Min)),hd(element(2,Max))};
char_range(Min, Max) when is_tuple(Min) andalso length(Max) > 1 ->
{range,hd(element(2,Min)),hd(tl(Max))};
char_range(Min, Max) when is_tuple(Min) ->
{range,hd(element(2,Min)),hd(Max)};
char_range(Min, Max) when length(Min) > 1 andalso is_tuple(Max) ->
{range,hd(tl(Min)),hd(element(2,Max))};
char_range(Min, Max) when is_tuple(Max) ->
{range,hd(Min),hd(element(2,Max))};
char_range(Min, Max) when length(Min) > 1 andalso length(Max) > 1 ->
{range,hd(tl(Min)),hd(tl(Max))};
char_range(Min, Max) when length(Min) > 1 ->
{range,hd(tl(Min)),hd(Max)};
char_range(Min, Max) when length(Max) > 1 ->
{range,hd(Min),hd(tl(Max))};
char_range(Min, Max) ->
{range,hd(Min),hd(Max)}.
char_group_part(Val) when is_tuple(Val) ->
{value,hd(element(2,Val))};
char_group_part("\\n") -> {value,$\n};
char_group_part("\\r") -> {value,$\r};
char_group_part("\\t") -> {value,$\t};
char_group_part("\\|") -> {value,$|};
char_group_part("\\.") -> {value,$.};
char_group_part("\\?") -> {value,$?};
char_group_part("\\*") -> {value,$*};
char_group_part("\\+") -> {value,$+};
char_group_part("\\(") -> {value,$(};
char_group_part("\\)") -> {value,$)};
char_group_part("\\{") -> {value,${};
char_group_part("\\}") -> {value,$}};
char_group_part("\\-") -> {value,$-};
char_group_part("\\[") -> {value,$[};
char_group_part("\\]") -> {value,$]};
char_group_part("\\$") -> {value,$$};
char_group_part("\\^") -> {value,$^};
char_group_part(Val) -> {value,hd(Val)}.