1%%---------------------------------------------------------------------- 2%% 3%% %CopyrightBegin% 4%% 5%% Copyright Ericsson AB 1999-2016. All Rights Reserved. 6%% 7%% Licensed under the Apache License, Version 2.0 (the "License"); 8%% you may not use this file except in compliance with the License. 9%% You may obtain a copy of the License at 10%% 11%% http://www.apache.org/licenses/LICENSE-2.0 12%% 13%% Unless required by applicable law or agreed to in writing, software 14%% distributed under the License is distributed on an "AS IS" BASIS, 15%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16%% See the License for the specific language governing permissions and 17%% limitations under the License. 18%% 19%% %CopyrightEnd% 20%% 21%% 22%%---------------------------------------------------------------------- 23%% File : cosNotification_Scanner.erl 24%% Purpose : Scan and pre-process a grammar. 25%%---------------------------------------------------------------------- 26 27-module('cosNotification_Scanner'). 28 29-export([scan/1]). 30 31scan(Str) -> 32 RSL = scan(Str, 1, [], any), 33 {ok, lists:reverse(RSL)}. 34 35 36%% Guard macros used at top scan functions only 37-define(is_number(X), X >= $0, X =< $9). 38-define(is_upper(X), X >= $A, X =< $Z). 39-define(is_lower(X), X >= $a, X =< $z). 40 41%%---------------------------------------------------------------------- 42%% scan 43%% 44%% A-Z 45scan([X|Str], Line, Out, Type) when ?is_upper(X) -> 46 scan_name(Str, [X], Line, Out, Type); 47%% a-z 48scan([X|Str], Line, Out, Type) when ?is_lower(X) -> 49 scan_name(Str, [X], Line, Out, Type); 50%% 0-9 51scan([X|Str], Line, Out, Type) when ?is_number(X) -> 52 scan_number(Str, [X], Line, Out, Type); 53 54%% RELOP:s == != <= >= > < 55scan([$=,$= | Str], Line, Out, _Type) -> 56 scan(Str, Line, [{'RELOP', '=='} | Out], any); 57scan([$!,$= | Str], Line, Out, _Type) -> 58 scan(Str, Line, [{'RELOP', '!='} | Out], any); 59scan([$<,$= | Str], Line, Out, _Type) -> 60 scan(Str, Line, [{'RELOP', '<='} | Out], any); 61scan([$>,$= | Str], Line, Out, _Type) -> 62 scan(Str, Line, [{'RELOP', '>='} | Out], any); 63scan([$> | Str], Line, Out, _Type) -> 64 scan(Str, Line, [{'RELOP', '>'} | Out], any); 65scan([$< | Str], Line, Out, _Type) -> 66 scan(Str, Line, [{'RELOP', '<'} | Out], any); 67 68%% ADDOP:s + - 69scan([$+ | Str], Line, Out, Type) -> 70 scan(Str, Line, [{'ADDOP', '+'} | Out], Type); 71scan([$- | Str], Line, Out, Type) -> 72 scan(Str, Line, [{'ADDOP', '-'} | Out], Type); 73 74%% MULOP:s * / 75scan([$* | Str], Line, Out, _Type) -> 76 scan(Str, Line, [{'MULOP', '*'} | Out], any); 77scan([$/ | Str], Line, Out, _Type) -> 78 scan(Str, Line, [{'MULOP', '/'} | Out], any); 79 80%% TAB 81scan([9| T], Line, Out, Type) -> scan(T, Line, Out, Type); 82%% SP 83scan([32| T], Line, Out, Type) -> scan(T, Line, Out, Type); 84%% CR 85scan([$\r|Str], Line, Out, Type) -> 86 scan(Str, Line, Out, Type); 87%% LF 88scan([$\n|Str], Line, Out, Type) -> 89 scan(Str, Line+1, Out, Type); 90%% \\ 91scan([92, 92 | Str], Line, Out, Type) -> 92 scan(Str, Line, [{'dbslsh', Line} | Out], Type); 93%% \' 94scan([92, 39 | Str], Line, Out, Type) -> 95 scan(Str, Line, [{'bslshd', Line} | Out], Type); 96%% '\' 97scan([92 | Str], Line, Out, Type) -> 98 scan(Str, Line, [{'bslsh', Line} | Out], Type); 99%% '_' 100scan([$_ | Str], Line, Out, dollar) -> 101 scan_name(Str, [$_], Line, Out, dollar); 102%% '$' 103scan([$$, 92 | Str], Line, Out, _Type) -> 104 scan(Str, Line, [{'bslsh', Line}, {'dollar', Line} | Out], dollar); 105scan([$$ | Str], Line, Out, _Type) -> 106 scan(Str, Line, [{'dollar', Line} | Out], dollar); 107scan([$"|Str], Line, Out, Type) -> 108 scan_const(char, Str, [], Line, Out, Type); 109scan([$'|Str], Line, Out, Type) -> 110 scan_const(string, Str, [], Line, Out, Type); 111 112%% Writing '+.<CompDot>' is not allowed ('+' or '-' are only allowed 113%% as unary for <UnionVal> (within a component) which must be en integer). 114scan([$. | Str], Line, [{'ADDOP', Op}|Out], _) -> 115 scan_frac(Str, [$.], Line, [{'ADDOP', Op}|Out], any); 116%% Must be a <CompDot> 117scan([$. | Str], Line, Out, dollar) -> 118 scan(Str, Line, [{'.',Line} | Out], dollar); 119%% Number 120scan([$. | Str], Line, Out, Type) -> 121 scan_frac(Str, [$.], Line, Out, Type); 122scan([C|Str], Line, Out, Type) -> 123 scan(Str, Line, [{list_to_atom([C]), Line} | Out], Type); 124 125scan([], _Line, Out, _Type) -> 126 Out. 127 128%%---------------------------------------------------------------------- 129%% scan_name 130%% 131 132scan_number([X|Str], Accum, Line, Out, Type) when ?is_number(X) -> 133 scan_number(Str, [X|Accum], Line, Out, Type); 134scan_number([X|Str], Accum, Line, Out, dollar) when X==$. -> 135 scan(Str, Line, [{'.', Line}, 136 {'int', list_to_integer(lists:reverse(Accum))} | Out], dollar); 137scan_number([X|Str], Accum, Line, Out, Type) when X==$. -> 138 scan_frac(Str, [X|Accum], Line, Out, Type); 139scan_number([X|Str], Accum, Line, Out, Type) when X==$e -> 140 scan_exp(Str, [X|Accum], Line, Out, Type); 141scan_number([X|Str], Accum, Line, Out, Type) when X==$E -> 142 scan_exp(Str, [X|Accum], Line, Out, Type); 143scan_number(Str, Accum, Line, Out, Type) -> 144 scan(Str, Line, [{'int', list_to_integer(lists:reverse(Accum))} | Out], Type). 145 146 147%% Floating point number scan. 148%% 149%% Non trivial scan. A float consists of an integral part, a 150%% decimal point, a fraction part, an e or E and a signed integer 151%% exponent. Either the integer part or the fraction part but not 152%% both may be missing, and either the decimal point or the 153%% exponent part but not both may be missing. The exponent part 154%% must consist of an e or E and a possibly signed exponent. 155%% 156%% Analysis shows that "1." ".7" "1e2" ".5e-3" "1.7e2" "1.7e-2" 157%% is allowed and "1" ".e9" is not. The sign is only allowed just 158%% after an e or E. The scanner reads a number as an integer 159%% until it encounters a "." so the integer part only error case 160%% will not be caught in the scanner (but rather in expression 161%% evaluation) 162 163scan_frac([$e | _Str], [$.], _Line, _Out, _Type) -> 164 {error, "illegal_float"}; 165scan_frac([$E | _Str], [$.], _Line, _Out, _Type) -> 166 {error, "illegal_float"}; 167scan_frac(Str, Accum, Line, Out, Type) -> 168 scan_frac2(Str, Accum, Line, Out, Type). 169 170scan_frac2([X|Str], Accum, Line, Out, Type) when ?is_number(X) -> 171 scan_frac2(Str, [X|Accum], Line, Out, Type); 172scan_frac2([X|Str], Accum, Line, Out, Type) when X==$e -> 173 scan_exp(Str, [X|Accum], Line, Out, Type); 174scan_frac2([X|Str], Accum, Line, Out, Type) when X==$E -> 175 scan_exp(Str, [X|Accum], Line, Out, Type); 176%% Since '.2' is allowed, we add '0' in front to be sure (erlang do not allow 177%% list_to_float(".2") and list_to_float("0.2") eq. list_to_float("00.2")). 178scan_frac2(Str, Accum, Line, Out, Type) -> 179 scan(Str, Line, [{'num', list_to_float([$0|lists:reverse(Accum)])} | Out], Type). 180 181scan_exp([X|Str], Accum, Line, Out, Type) when X==$- -> 182 scan_exp2(Str, [X|Accum], Line, Out, Type); 183scan_exp(Str, Accum, Line, Out, Type) -> 184 scan_exp2(Str, Accum, Line, Out, Type). 185 186scan_exp2([X|Str], Accum, Line, Out, Type) when ?is_number(X) -> 187 scan_exp2(Str, [X|Accum], Line, Out, Type); 188%% Since '.2' is allowed, we add '0' in front to be sure (erlang do not allow 189%% list_to_float(".2")). 190scan_exp2(Str, Accum, Line, Out, Type) -> 191 scan(Str, Line, [{'num', list_to_float([$0|lists:reverse(Accum)])} | Out], Type). 192 193 194scan_name([X|Str], Accum, Line, Out, Type) when ?is_upper(X) -> 195 scan_name(Str, [X|Accum], Line, Out, Type); 196scan_name([X|Str], Accum, Line, Out, Type) when ?is_lower(X) -> 197 scan_name(Str, [X|Accum], Line, Out, Type); 198scan_name([X|Str], Accum, Line, Out, Type) when ?is_number(X) -> 199 scan_name(Str, [X|Accum], Line, Out, Type); 200scan_name([$_|Str], Accum, Line, Out, dollar) -> 201 scan_name(Str, [$_|Accum], Line, Out, dollar); 202scan_name(S, Accum, Line, [{bslsh,LL} | Out], Type) -> 203 %% An escaped identifier. 204 L = lists:reverse(Accum), 205 scan(S, Line, [{'ident', L}, {bslsh,LL} | Out], Type); 206scan_name(S, Accum, Line, Out, Type) -> 207 L = lists:reverse(Accum), 208 {X, NewType} = case check_name(L) of 209 false -> 210 {{'ident', L}, Type}; 211 _ -> 212 {{list_to_atom(L), Line}, any} 213 end, 214 scan(S, Line, [X | Out], NewType). 215 216%% Shall scan a constant 217scan_const(char, [$" | Rest], Accum, Line, Out, Type) -> 218 scan(Rest, Line, 219 [{'ident', list_to_atom(lists:reverse(Accum))} | Out], Type); 220scan_const(char, [], _Accum, _Line, Out, _Type) -> %% Bad string 221% {error, "bad_string"}; 222 Out; 223scan_const(string, [$' | Rest], Accum, Line, Out, Type) -> 224 scan(Rest, Line, 225 [{'string', lists:reverse(Accum)} | Out], Type); 226scan_const(Mode, [$\\, C | Rest], Accum, Line, Out, Type) -> 227 case escaped_char(C) of 228 error -> 229 %% Bad escape character 230 %% {error, "bad_escape_character"}; 231 scan_const(Mode, Rest, [C | Accum], Line, Out, Type); 232 EC -> 233 scan_const(Mode, Rest, [EC | Accum], Line, Out, Type) 234 end; 235scan_const(Mode, [C | Rest], Accum, Line, Out, Type) -> 236 scan_const(Mode, Rest, [C | Accum], Line, Out, Type). 237 238%% Escaped character. Escaped chars are repr as two characters in the 239%% input list of letters and this is translated into one char. 240escaped_char($n) -> $\n; 241escaped_char($t) -> $\t; 242escaped_char($v) -> $\v; 243escaped_char($b) -> $\b; 244escaped_char($r) -> $ ; 245escaped_char($f) -> $\f; 246escaped_char($a) -> $\a; 247escaped_char($\\) -> $\\; 248escaped_char($?) -> $?; 249escaped_char($') -> $'; 250escaped_char($") -> $"; 251%% Error 252escaped_char(_Other) -> error. 253 254 255check_name("exist") -> true; 256check_name("default") -> true; 257check_name("_length") -> true; 258check_name("_d") -> true; 259check_name("_type_id") -> true; 260check_name("_repos_id") -> true; 261check_name("not") -> true; 262check_name("or") -> true; 263check_name("and") -> true; 264check_name("FALSE") -> true; 265check_name("TRUE") -> true; 266check_name("in") -> true; 267check_name(_) -> false. 268 269 270