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