source: ruby/trunk/lib/adl_parser/lib/adl_scanner.rb

Last change on this file was 369, checked in by KOBAYASHI, Shinji, 14 years ago

merge from branches/0.5

File size: 38.3 KB
Line 
1require 'rubygems'
2require 'logger'
3require 'adl_parser.rb'
4require 'open_ehr'
5require 'util.rb'
6
7
8module OpenEhr
9 module ADL
10 module Scanner
11# LOGGER = Logger.new('log/scanner.log')
12 LOGGER = Logger.new('log/parser.log')
13 LOGGER.level = Logger::DEBUG
14
15 class Base
16 attr_accessor :adl_type, :lineno
17 def initialize(adl_type, filename, lineno = 1)
18 @adl_type = adl_type
19 @filename = filename
20 @lineno = lineno
21 end
22
23 def scan(data)
24 raise
25 end
26 end
27
28 #
29 # ADLScanner
30 #
31 class ADLScanner < Base
32 attr_accessor :adl_type, :lineno, :cadl_scanner, :dadl_scanner, :regex_scanner, :term_constraint_scanner
33
34 @@logger = OpenEhr::ADL::Scanner::LOGGER #Logger.new('log/scanner.log')
35 RESERVED = {
36 'archetype' => :SYM_ARCHETYPE,
37 'adl_version' => :SYM_ADL_VERSION,
38 'controlled' => :SYM_IS_CONTROLLED,
39 'specialize' => :SYM_SPECIALIZE,
40 'concept' => :SYM_CONCEPT,
41 'language' => :SYM_LANGUAGE,
42 'description' => :SYM_DESCRIPTION,
43 'definition' => :SYM_DEFINITION,
44 'invariant' => :SYM_INVARIANT,
45 'ontology' => :SYM_ONTOLOGY,
46 'matches' => :SYM_MATCHES,
47 'is_in' => :SYM_MATCHES,
48 'occurrences' => :SYM_OCCURRENCES,
49 'true' => :SYM_TRUE, #[Tt][Rr][Uu][Ee] -- -> SYM_TRUE
50 'false' => :SYM_FALSE, # [Ff][Aa][Ll][Ss][Ee] -- -> SYM_FALSE
51 'infinity' => :SYM_INFINITY # [Ii][Nn][Ff][Ii][Nn][Ii][Tt][Yy] -- -> SYM_INFINITY
52 }
53 REGEX_PATTERN = Hash[:CarriageReturn => /\A\n/,
54 :WhiteSpace => /\A[ \t\r\f]+/,
55 :SingleCommentLine => /\A--.*/,
56 :V_ISO8601_DURATION => /\AP([0-9]+[yY])?([0-9]+[mM])?([0-9]+[wW])?([0-9]+[dD])?T([0-9]+[hH])?([0-9]+[mM])?([0-9]+[sS])?|\AP([0-9]+[yY])?([0-9]+[mM])?([0-9]+[wW])?([0-9]+[dD])?/ #V_ISO8601_DURATION PnYnMnWnDTnnHnnMnnS
57 ]
58
59 def initialize(adl_type, filename, lineno = 1)
60 super(adl_type, filename, lineno)
61 @in_interval = false
62 end
63
64 #
65 # ADLScanner#scan
66 #
67 def scan(data)
68 @@logger.debug("#{__FILE__}:#{__LINE__}: Entering ADLScanner#scan at #{@filename}:#{@lineno}: data = #{data.inspect}")
69 until data.nil? do
70 case @adl_type.last
71 when :adl
72 case data
73# when /\A\n/ # carriage return
74 when REGEX_PATTERN[:CarriageReturn] # carriage return
75 @lineno += 1
76 ;
77# when /\A[ \t\r\f]+/ #just drop it
78 when REGEX_PATTERN[:WhiteSpace] # carriage return
79 ;
80# when /\A--.*/ # single line comment
81 when REGEX_PATTERN[:SingleCommentLine] # carriage return
82 @lineno += 1
83 @@logger.debug("ADLScanner#scan: COMMENT = #{$&} at #{@filename}:#{@lineno}")
84 ;
85 when /\Adescription/ # description
86 yield :SYM_DESCRIPTION, :SYM_DESCRIPTION
87 when /\Adefinition/ # definition
88 yield :SYM_DEFINITION, :SYM_DEFINITION
89 ###----------/* symbols */ -------------------------------------------------
90 when /\A[A-Z][a-zA-Z0-9_]*/
91 yield :V_TYPE_IDENTIFIER, $&
92 when /\A(\w+)-(\w+)-(\w+)\.(\w+)((?:-\w+)*)\.(v\w+)/ #V_ARCHETYPE_ID
93 object_id, rm_originator, rm_name, rm_entity, concept_name, specialisation, version_id = $&, $1, $2, $3, $4, $5, $6
94 archetype_id = OpenEhr::RM::Support::Identification::ArchetypeID.new(:concept_name => concept_name, :rm_name => rm_name, :rm_entity => rm_entity, :rm_originator => rm_originator, :specialisation => specialisation, :version_id => version_id)
95 yield :V_ARCHETYPE_ID, archetype_id
96 when /\A[a-z][a-zA-Z0-9_]*/
97 word = $&
98 if RESERVED[word]
99 @@logger.debug("ADLScanner#scan: RESERVED = #{RESERVED[word]} at #{@filename}:#{@lineno}")
100 yield RESERVED[word], RESERVED[word]
101 elsif #/\A[A-Z][a-zA-Z0-9_]*/
102 @@logger.debug("ADLScanner#scan: V_ATTRIBUTE_IDENTIFIER = #{$&} at #{@filename}:#{@lineno}")
103 yield :V_ATTRIBUTE_IDENTIFIER, $&
104 end
105 when /\A\=/ # =
106 yield :SYM_EQ, :SYM_EQ
107 when /\A\>=/ # >=
108 yield :SYM_GE, :SYM_GE
109 when /\A\<=/ # <=
110 yield :SYM_LE, :SYM_LE
111 when /\A\</ # <
112 if @in_interval
113 yield :SYM_LT, :SYM_LT
114 else
115 @adl_type.push(:dadl)
116 yield :SYM_START_DBLOCK, $&
117 end
118 when /\A\>/ # >
119 if @in_interval
120 yield :SYM_GT, :SYM_GT
121 else
122 adl_type = @adl_type.pop
123 assert_at(__FILE__,__LINE__){adl_type == :dadl}
124 yield :SYM_END_DBLOCK, :SYM_END_DBLOCK
125 end
126 when /\A\{/ # {
127 @adl_type.push(:cadl)
128 @@logger.debug("ADLScanner#scan: SYM_START_CBLOCK")
129 yield :SYM_START_CBLOCK, :SYM_START_CBLOCK
130 when /\A\}/ # }
131 adl_type = @adl_type.pop
132 assert_at(__FILE__,__LINE__){adl_type == :cadl}
133 @@logger.debug("ADLScanner#scan: SYM_END_CBLOCK")
134 yield :SYM_END_CBLOCK, $&
135 when /\A\-/ # -
136 yield :Minus_code, :Minus_code
137 when /\A\+/ # +
138 yield :Plus_code, :Plus_code
139 when /\A\*/ # *
140 yield :Star_code, :Star_code
141 when /\A\// # /
142 yield :Slash_code, :Slash_code
143 when /\A\^/ # ^
144 yield :Caret_code, :Caret_code
145 when /\A\=/ # =
146 yield :Equal_code, :Equal_code
147 when /\A\.\.\./ # ...
148 yield :SYM_LIST_CONTINUE, :SYM_LIST_CONTINUE
149 when /\A\.\./ # ..
150 yield :SYM_ELLIPSIS, :SYM_ELLIPSIS
151 when /\A\./ # .
152 yield :Dot_code, :Dot_code
153 when /\A\;/ # ;
154 yield :Semicolon_code, :Semicolon_code
155 when /\A\,/ # ,
156 yield :Comma_code, :Comma_code
157 when /\A\:/ # :
158 yield :Colon_code, :Colon_code
159 when /\A\!/ # !
160 yield :Exclamation_code, :Exclamation_code
161 when /\A\(/ # (
162 yield :Left_parenthesis_code, :Left_parenthesis_code
163 when /\A\)/ # )
164 yield :Right_parenthesis_code, :Right_parenthesis_code
165 when /\A\$/ # $
166 yield :Dollar_code, :Dollar_code
167 when /\A\?\?/ # ??
168 yield :SYM_DT_UNKNOWN, :SYM_DT_UNKNOWN
169 when /\A\?/ # ?
170 yield :Question_mark_code, :Question_mark_code
171 when /\A[0-9]+\.[0-9]+(\.[0-9]+)*/ # ?
172 yield :V_VERSION_STRING, $&
173 when /\A\|/ # |
174 if @in_interval
175 @in_interval = false
176 else
177 @in_interval = true
178 end
179 yield :SYM_INTERVAL_DELIM, :SYM_INTERVAL_DELIM
180 when /\A\[([a-zA-Z0-9()\._-]+::[a-zA-Z0-9\._-]+)\]/ #V_QUALIFIED_TERM_CODE_REF form such as [ICD10AM(1998)::F23]
181 yield :V_QUALIFIED_TERM_CODE_REF, $1
182 when /\A\[([a-zA-Z0-9][a-zA-Z0-9._\-]*)\]/ #V_LOCAL_TERM_CODE_REF
183 yield :V_LOCAL_TERM_CODE_REF, $1
184 when /\A\[/ # [
185 yield :Left_bracket_code, :Left_bracket_code
186 when /\A\]/ # ]
187 yield :Right_bracket_code, :Right_bracket_code
188 when /\A"([^"]*)"/m #V_STRING
189 yield :V_STRING, $1
190 when /\A\[[a-zA-Z0-9._\- ]+::[a-zA-Z0-9._\- ]+\]/ #ERR_V_QUALIFIED_TERM_CODE_REF
191 yield :ERR_V_QUALIFIED_TERM_CODE_REF, $&
192 when /\Aa[ct][0-9.]+/ #V_LOCAL_CODE
193 yield :V_LOCAL_CODE, $&
194 when /\A[0-9]{4}-[0-1][0-9]-[0-3][0-9]T[0-2][0-9]:[0-6][0-9]:[0-6][0-9](,[0-9]+)?(Z|[+-][0-9]{4})?|[0-9]{4}-[0-1][0-9]-[0-3][0-9]T[0-2][0-9]:[0-6][0-9](Z|[+-][0-9]{4})?|[0-9]{4}-[0-1][0-9]-[0-3][0-9]T[0-2][0-9](Z|[+-][0-9]{4})?/ #V_ISO8601_EXTENDED_DATE_TIME YYYY-MM-DDThh:mm:ss[,sss][Z|+/- -n-n-n-n-]-
195 yield :V_ISO8601_EXTENDED_DATE_TIME, $&
196 when /\A[0-2][0-9]:[0-6][0-9]:[0-6][0-9](,[0-9]+)?(Z|[+-][0-9]{4})?|[0-2][0-9]:[0-6][0-9](Z|[+-][0-9]{4})? / #V_ISO8601_EXTENDED_TIME hh:mm:ss[,sss][Z|+/-nnnn]
197 yield :V_ISO8601_EXTENDED_TIME, $&
198 when /\A[0-9]{4}-[0-1][0-9]-[0-3][0-9]|[0-9]{4}-[0-1][0-9]/ #V_ISO8601_EXTENDED_DATE YYYY-MM-DD
199 yield :V_ISO8601_EXTENDED_DATE, $&
200 when /\A[A-Z][a-zA-Z0-9_]*<[a-zA-Z0-9,_<>]+>/ #V_GENERIC_TYPE_IDENTIFIER
201 yield :V_GENERIC_TYPE_IDENTIFIER, $&
202 when /\A[0-9]+|[0-9]+[eE][+-]?[0-9]+/ #V_INTEGER
203 @@logger.debug("ADLScanner#scan: V_INTEGER = #{$&}")
204 yield :V_INTEGER, $&
205 when /\A[0-9]+\.[0-9]+|[0-9]+\.[0-9]+[eE][+-]?[0-9]+ / #V_REAL
206 yield :V_REAL, $&
207 # when /\A"((?:[^"\\]+|\\.)*)"/ #V_STRING
208 when /\A[a-z]+:\/\/[^<>|\\{}^~"\[\] ]*/ #V_URI
209 yield :V_URI, $&
210 when /\AP([0-9]+[yY])?([0-9]+[mM])?([0-9]+[wW])?([0-9]+[dD])?T([0-9]+[hH])?([0-9]+[mM])?([0-9]+[sS])?/ #V_ISO8601_DURATION PnYnMnWnDTnnHnnMnnS
211 yield :V_ISO8601_DURATION, $&
212 when /\AP([0-9]+[yY])?([0-9]+[mM])?([0-9]+[wW])?([0-9]+[dD])?/ #V_ISO8601_DURATION PnYnMnWnDTnnHnnMnnS
213 yield :V_ISO8601_DURATION, $&
214 when /\A\S/ #UTF8CHAR
215 yield :UTF8CHAR, $&
216 end
217 data = $' # variable $' receives the string after the match
218 when :dadl
219 dadl_scanner = OpenEhr::ADL::Scanner::DADLScanner.new(@adl_type, @filename, @lineno)
220 data = dadl_scanner.scan(data) do |sym, val|
221 yield sym, val
222 end
223 when :cadl
224 cadl_scanner = OpenEhr::ADL::Scanner::CADLScanner.new(@adl_type, @filename, @lineno)
225 data = cadl_scanner.scan(data) do |sym, val|
226 yield sym, val
227 end
228 when :regexp
229 regex_scanner = OpenEhr::ADL::Scanner::RegexScanner.new(@adl_type, @filename, @lineno)
230 data = regex_scanner.scan(data) do |sym, val|
231 yield sym, val
232 end
233 when :term_constraint
234 term_constraint_scanner = OpenEhr::ADL::Scanner::TermConstraintScanner.new(@adl_type, @filename, @lineno)
235 data = term_constraint_scanner.scan(data) do |sym, val|
236 yield sym, val
237 end
238 else
239 raise
240 end
241 end
242 end
243 end # of ADLScanner
244
245 #
246 # DADLScanner
247 #
248 class DADLScanner < ADLScanner
249 attr_accessor :in_interval, :in_c_domain_type, :dblock_depth
250 @@logger = OpenEhr::ADL::Scanner::LOGGER #Logger.new('log/scanner.log')
251 RESERVED = {
252 'true' => :SYM_TRUE, #[Tt][Rr][Uu][Ee] -- -> SYM_TRUE
253 'false' => :SYM_FALSE, # [Ff][Aa][Ll][Ss][Ee] -- -> SYM_FALSE
254 'infinity' => :SYM_INFINITY # [Ii][Nn][Ff][Ii][Nn][Ii][Tt][Yy] -- -> SYM_INFINITY
255 }
256
257 def initialize(adl_type, filename, lineno = 1)
258 super(adl_type, filename, lineno)
259 @in_interval = false
260 @in_c_domain_type = false
261 @dblock_depth = 0
262 end
263
264 #
265 # DADLScanner#scan
266 #
267 def scan(data)
268 @@logger.debug("Entering DADLScanner#scan at #{@filename}:#{@lineno}: @adl_type = #{@adl_type.inspect}, data = #{data.inspect}")
269 until data.nil? do
270 @@logger.debug("#{@filename}:#{@lineno}: DADLScanner#scan:loop data = #{data.inspect}")
271 @@logger.debug("#{@filename}:#{@lineno}: DADLScanner#scan:loop self = \n#{self.to_yaml}")
272 case @adl_type.last
273 when :dadl
274 case data
275# when /\A\n/ # carriage return
276 when REGEX_PATTERN[:CarriageReturn] # carriage return
277 @lineno += 1
278 ;
279# when /\A[ \t\r\f]+/ #just drop it
280 when REGEX_PATTERN[:WhiteSpace]
281 ##@@logger.debug("DADLScanner#scan: white space, data = #{data.inspect}")
282 ;
283# when /\A--.*/ # single line comment
284 when REGEX_PATTERN[:SingleCommentLine]
285 @@logger.debug("DADLScanner#scan: COMMENT = #{$&} at #{@filename}:#{@lineno}")
286 ;
287 when /\A[a-z]+:\/\/[^<>|\\{}^~"\[\] ]*/ #V_URI
288 yield :V_URI, $&
289 when /\A[a-z][a-zA-Z0-9_]*/
290 word = $&.dup
291 if RESERVED[word.downcase]
292 yield RESERVED[word.downcase], RESERVED[word.downcase]
293 else
294 @@logger.debug("DADLScanner#scan: V_ATTRIBUTE_IDENTIFIER = #{word} at #{@filename}:#{@lineno}")
295 yield :V_ATTRIBUTE_IDENTIFIER, word #V_ATTRIBUTE_IDENTIFIER /\A[a-z][a-zA-Z0-9_]*/
296 end
297 ###----------/* symbols */ -------------------------------------------------
298 when /\A\=/ # =
299 yield :SYM_EQ, :SYM_EQ
300 when /\A\>\=/ # >=
301 yield :SYM_GE, :SYM_GE
302 when /\A\<\=/ # <=
303 yield :SYM_LE, :SYM_LE
304 when /\A\</ # <
305 if @in_interval
306 yield :SYM_LT, :SYM_LT
307 else
308 unless @in_c_domain_type
309 @adl_type.push(:dadl)
310 else
311 @dblock_depth += 1
312 end
313 yield :SYM_START_DBLOCK, :SYM_START_DBLOCK
314 end
315 when /\A\>/ # >
316 if @in_interval
317 yield :SYM_GT, :SYM_GT
318 else
319 if @in_c_domain_type
320 assert_at(__FILE__,__LINE__){@adl_type.last == :dadl}
321 @dblock_depth -= 1
322 if @dblock_depth < 0
323 @adl_type.pop
324 @in_c_domain_type = false
325 yield :END_V_C_DOMAIN_TYPE_BLOCK, :END_V_C_DOMAIN_TYPE_BLOCK
326 else
327 yield :SYM_END_DBLOCK, :SYM_END_DBLOCK
328 end
329 else
330 adl_type = @adl_type.pop
331 assert_at(__FILE__,__LINE__){adl_type == :dadl}
332 yield :SYM_END_DBLOCK, $&
333 end
334 end
335 when /\A\-/ # -
336 yield :Minus_code, :Minus_code
337 when /\A\+/ # +
338 yield :Plus_code, :Plus_code
339 when /\A\*/ # *
340 yield :Star_code, :Star_code
341 when /\A\// # /
342 yield :Slash_code, :Slash_code
343 when /\A\^/ # ^
344 yield :Caret_code, :Caret_code
345 when /\A\.\.\./ # ...
346 yield :SYM_LIST_CONTINUE, :SYM_LIST_CONTINUE
347 when /\A\.\./ # ..
348 yield :SYM_ELLIPSIS, :SYM_ELLIPSIS
349 when /\A\./ # .
350 yield :Dot_code, :Dot_code
351 when /\A\;/ # ;
352 yield :Semicolon_code, :Semicolon_code
353 when /\A\,/ # ,
354 @@logger.debug("DADLScanner#scan: Comma_code")
355 yield :Comma_code, :Comma_code
356 when /\A\:/ # :
357 yield :Colon_code, :Colon_code
358 when /\A\!/ # !
359 yield :Exclamation_code, :Exclamation_code
360 when /\A\(/ # (
361 yield :Left_parenthesis_code, :Left_parenthesis_code
362 when /\A\)/ # )
363 yield :Right_parenthesis_code, :Right_parenthesis_code
364 when /\A\$/ # $
365 yield :Dollar_code, :Dollar_code
366 when /\A\?\?/ # ??
367 yield :SYM_DT_UNKNOWN, :SYM_DT_UNKNOWN
368 when /\A\?/ # ?
369 yield :Question_mark_code, :Question_mark_code
370 when /\A\|/ # |
371 @@logger.debug("DADLScanner#scan: @in_interval = #{@in_interval} at #{@filename}:#{@lineno}")
372 if @in_interval
373 @in_interval = false
374 else
375 @in_interval = true
376 end
377 @@logger.debug("DADLScanner#scan: SYM_INTERVAL_DELIM at #{@filename}:#{@lineno}")
378 yield :SYM_INTERVAL_DELIM, :SYM_INTERVAL_DELIM
379 when /\A\[([a-zA-Z0-9()\._-]+::[a-zA-Z0-9\._-]+)\]/ #V_QUALIFIED_TERM_CODE_REF form [ICD10AM(1998)::F23]
380 yield :V_QUALIFIED_TERM_CODE_REF, $1
381 when /\A\[/ # [
382 @@logger.debug("DADLScanner#scan: Left_bracket_code at #{@filename}:#{@lineno}")
383 yield :Left_bracket_code, :Left_bracket_code
384 when /\A\]/ # ]
385 @@logger.debug("DADLScanner#scan: Right_bracket_code at #{@filename}:#{@lineno}")
386 yield :Right_bracket_code, :Right_bracket_code
387 when /\A"((?:[^"\\]+|\\.)*)"/ #V_STRING
388 @@logger.debug("DADLScanner#scan: V_STRING, #{$1}")
389 yield :V_STRING, $1
390 when /\A"([^"]*)"/m #V_STRING
391 @@logger.debug("DADLScanner#scan: V_STRING, #{$1}")
392 yield :V_STRING, $1
393 when /\A[0-9]{4}-[0-1][0-9]-[0-3][0-9]T[0-2][0-9]:[0-6][0-9]:[0-6][0-9](,[0-9]+)?(Z|[+-][0-9]{4})?|[0-9]{4}-[0-1][0-9]-[0-3][0-9]T[0-2][0-9]:[0-6][0-9](Z|[+-][0-9]{4})?|[0-9]{4}-[0-1][0-9]-[0-3][0-9]T[0-2][0-9](Z|[+-][0-9]{4})?/ #V_ISO8601_EXTENDED_DATE_TIME YYYY-MM-DDThh:mm:ss[,sss][Z|+/- -n-n-n-n-]-
394 @@logger.debug("DADLScanner#scan: V_ISO8601_EXTENDED_DATE_TIME")
395 yield :V_ISO8601_EXTENDED_DATE_TIME, $&
396 when /\A[0-2][0-9]:[0-6][0-9]:[0-6][0-9](,[0-9]+)?(Z|[+-][0-9]{4})?|[0-2][0-9]:[0-6][0-9](Z|[+-][0-9]{4})? / #V_ISO8601_EXTENDED_TIME hh:mm:ss[,sss][Z|+/-nnnn]
397 @@logger.debug("DADLScanner#scan: V_ISO8601_EXTENDED_TIME")
398 yield :V_ISO8601_EXTENDED_TIME, $&
399 when /\A\d{4}-[0-1][0-9]-[0-3][0-9]|[0-9]{4}-[0-1][0-9]/ #V_ISO8601_EXTENDED_DATE YYYY-MM-DD
400 @@logger.debug("DADLScanner#scan: V_ISO8601_EXTENDED_DATE, #{$&}")
401 yield :V_ISO8601_EXTENDED_DATE, $&
402 when /\A[A-Z][a-zA-Z0-9_]*<[a-zA-Z0-9,_<>]+>/ #V_GENERIC_TYPE_IDENTIFIER
403 yield :V_GENERIC_TYPE_IDENTIFIER, $&
404 when /\A[0-9]+\.[0-9]+|[0-9]+\.[0-9]+[eE][+-]?[0-9]+ / #V_REAL
405 yield :V_REAL, $&
406 when /\A[0-9]+|[0-9]+[eE][+-]?[0-9]+/ #V_INTEGER
407 @@logger.debug("DADLScanner#scan: V_INTEGER = #{$&}")
408 yield :V_INTEGER, $&
409 when /\A\S/ #UTF8CHAR
410 yield :UTF8CHAR, $&
411 end
412 data = $' # variable $' receives the string after the match
413 when :adl
414 adl_scanner = OpenEhr::ADL::Scanner::ADLScanner.new(@adl_type, @filename, @lineno)
415 data = adl_scanner.scan(data) do |sym, val|
416 yield sym, val
417 end
418 when :cadl
419 cadl_scanner = OpenEhr::ADL::Scanner::CADLScanner.new(@adl_type, @filename, @lineno)
420 data = cadl_scanner.scan(data) do |sym, val|
421 yield sym, val
422 end
423 when :regexp
424 regex_scanner = OpenEhr::ADL::Scanner::RegexScanner.new(@adl_type, @filename, @lineno)
425 data = regex_scanner.scan(data) do |sym, val|
426 yield sym, val
427 end
428 when :term_constraint
429 @@logger.debug("#{__FILE__}:#{__LINE__}: scan_dadl: Entering scan_term_constraint at #{@filename}:#{@lineno}: data = #{data.inspect}")
430 term_constraint_scanner = OpenEhr::ADL::Scanner::TermConstraintScanner.new(@adl_type, @filename, @lineno)
431 data = term_constraint_scanner.scan(data) do |sym, val|
432 yield sym, val
433 end
434 else
435 raise
436 end
437 end
438 end
439 end # of DADLScanner
440
441 class CADLScanner < ADLScanner
442
443 @@logger = OpenEhr::ADL::Scanner::LOGGER #Logger.new('log/scanner.log') #Logger.new('log/scanner.log')
444 RESERVED = {
445 'then' => :SYM_THEN, # [Tt][Hh][Ee][Nn]
446 'else' => :SYM_ELSE, # [Ee][Ll][Ss][Ee]
447 'and' => :SYM_AND, # [Aa][Nn][Dd]
448 'or' => :SYM_OR, # [Oo][Rr]
449 'xor' => :SYM_XOR, # [Xx][Oo][Rr]
450 'not' => :SYM_NOT, # [Nn][Oo][Tt]
451 'implies' => :SYM_IMPLIES, # [Ii][Mm][Pp][Ll][Ii][Ee][Ss]
452 'true' => :SYM_TRUE, #[Tt][Rr][Uu][Ee] -- -> SYM_TRUE
453 'false' => :SYM_FALSE, # [Ff][Aa][Ll][Ss][Ee] -- -> SYM_FALSE
454 'forall' => :SYM_FORALL, # [Ff][Oo][Rr][_][Aa][Ll][Ll]
455 'exists' => :SYM_EXISTS, # [Ee][Xx][Ii][Ss][Tt][Ss]
456 'existence' => :SYM_EXISTENCE, # [Ee][Xx][Iu][Ss][Tt][Ee][Nn][Cc][Ee]
457 'occurrences' => :SYM_OCCURRENCES, # [Oo][Cc][Cc][Uu][Rr][Rr][Ee][Nn][Cc][Ee][Ss]
458 'cardinality' => :SYM_CARDINALITY, # [Cc][Aa][Rr][Dd][Ii][Nn][Aa][Ll][Ii][Tt][Yy]
459 'ordered' => :SYM_ORDERED, # [Oo][Rr][Dd][Ee][Rr][Ee][Dd]
460 'unordered' => :SYM_UNORDERED, # [Uu][Nn][Oo][Rr][Dd][Ee][Rr][Ee][Dd]
461 'unique' => :SYM_UNIQUE, # [Uu][Nn][Ii][Qq][Uu][Ee]
462 'matches' => :SYM_MATCHES, # [Mm][Aa][Tt][Cc][Hh][Ee][Ss]
463 'is_in' => :SYM_MATCHES, # [Ii][Ss][_][Ii][Nn]
464 'invariant' => :SYM_INVARIANT, # [Ii][Nn][Vv][Aa][Rr][Ii][Aa][Nn][Tt]
465 'infinity' => :SYM_INFINITY, # [Ii][Nn][Ff][Ii][Nn][Ii][Tt][Yy] -- -> SYM_INFINITY
466 'use_node' => :SYM_USE_NODE, # [Uu][Ss][Ee][_][Nn][Oo][Dd][Ee]
467 'use_archetype' => :SYM_ALLOW_ARCHETYPE, # [Uu][Ss][Ee][_][Aa][Rr][Cc][Hh][Ee][Tt][Yy][Pp][Ee]
468 'allow_archetype' => :SYM_ALLOW_ARCHETYPE, # [Aa][Ll][Ll][Oo][Ww][_][Aa][Rr][Cc][Hh][Ee][Tt][Yy][Pp][Ee]
469 'include' => :SYM_INCLUDE, # [Ii][Nn][Cc][Ll][Uu][Dd][Ee]
470 'exclude' => :SYM_EXCLUDE # [Ee][Xx][Cc][Ll][Uu][Dd][Ee]
471 }
472
473 def initialize(adl_type, filename, lineno = 1)
474 super(adl_type, filename, lineno)
475 @in_interval = false
476 end
477
478 #
479 # CADLScanner#scan
480 #
481 def scan(data)
482 @@logger.debug("#{__FILE__}:#{__LINE__}: Entering CADLScanner#scan at #{@filename}:#{@lineno}: data = #{data.inspect}")
483 until data.nil? do
484 @@logger.debug("CADLScanner#scan: loop data = #{data.inspect}")
485 case @adl_type.last
486 when :cadl
487 case data
488# when /\A\n/ # carriage return
489 when REGEX_PATTERN[:CarriageReturn] # carriage return
490 @lineno += 1
491 ;
492 #yield :CR, :CR
493# when /\A[ \t\r\f]+/ #just drop it
494 when REGEX_PATTERN[:WhiteSpace]
495 ;
496# when /\A--.*\n/ # single line comment
497 when REGEX_PATTERN[:SingleCommentLine]
498 @lineno += 1
499 ;
500 ###----------/* symbols */ -------------------------------------------------
501 when /\A\=/ # =
502 yield :SYM_EQ, :SYM_EQ
503 when /\A\>=/ # >=
504 yield :SYM_GE, :SYM_GE
505 when /\A\<=/ # <=
506 yield :SYM_LE, :SYM_LE
507 when /\A\</ # <
508 if @in_interval
509 yield :SYM_LT, :SYM_LT
510 else
511 @adl_type.push(:dadl)
512 yield :SYM_START_DBLOCK, $&
513 end
514 when /\A\>/ # >
515 if @in_interval
516 yield :SYM_GT, :SYM_GT
517 else
518 adl_type = @adl_type.pop
519 assert_at(__FILE__,__LINE__){adl_type == :dadl}
520 yield :SYM_END_DBLOCK, :SYM_END_DBLOCK
521 end
522 when /\A\-/ # -
523 yield :Minus_code, :Minus_code
524 when /\A\+/ # +
525 yield :Plus_code, :Plus_code
526 when /\A\=/ # =
527 yield :Equal_code, :Equal_code
528 when /\A\*/ # *
529 yield :Star_code, :Star_code
530 when /\A\^/ # ^
531 yield :Caret_code, :Caret_code
532 when /\A\.\.\./ # ...
533 yield :SYM_LIST_CONTINUE, :SYM_LIST_CONTINUE
534 when /\A\.\./ # ..
535 yield :SYM_ELLIPSIS, :SYM_ELLIPSIS
536 when /\A\./ # .
537 yield :Dot_code, :Dot_code
538 when /\A\;/ # ;
539 yield :Semicolon_code, :Semicolon_code
540 when /\A\,/ # ,
541 yield :Comma_code, :Comma_code
542 when /\A\:/ # :
543 yield :Colon_code, :Colon_code
544 when /\A\!/ # !
545 yield :Exclamation_code, :Exclamation_code
546 when /\A\(/ # (
547 yield :Left_parenthesis_code, :Left_parenthesis_code
548 when /\A\)/ # )
549 yield :Right_parenthesis_code, :Right_parenthesis_code
550 when /\A\// # /
551 @@logger.debug("CADLScanner#scan: Slash_code #{@filename}:#{@lineno}")
552 yield :Slash_code, :Slash_code
553 when /\A\{\// # REGEXP_HEAD {/
554 assert_at(__FILE__,__LINE__){ @adl_type.last != :regexp}
555 # @in_regexp = true
556 @@logger.debug("CADLScanner#scan: REGEXP_HEAD:")
557 @adl_type.push(:cadl)
558 @adl_type.push(:regexp)
559 # yield :START_REGEXP_BLOCK, :START_REGEXP_BLOCK
560 yield :REGEXP_HEAD, :REGEXP_HEAD
561 when /\A\{/ # {
562 @adl_type.push(:cadl)
563 #@@logger.debug("CADLScanner#scan: entering cADL at #{@filename}:#{@lineno}")
564 yield :SYM_START_CBLOCK, :SYM_START_CBLOCK
565 when /\A\}/ # }
566 adl_type = @adl_type.pop
567 assert_at(__FILE__,__LINE__){adl_type == :cadl}
568 @@logger.debug("CADLScanner#scan: exiting cADL at #{@filename}:#{@lineno}")
569 yield :SYM_END_CBLOCK, :SYM_END_CBLOCK
570 when /\A\$/ # $
571 yield :Dollar_code, :Dollar_code
572 when /\A\?\?/ # ??
573 yield :SYM_DT_UNKNOWN, :SYM_DT_UNKNOWN
574 when /\A\?/ # ?
575 yield :Question_mark_code, :Question_mark_code
576 when /\A\|/ # |
577 if @in_interval
578 @in_interval = false
579 else
580 @in_interval = true
581 end
582 @@logger.debug("CADLScanner#scan: @in_interval = #{@in_interval} at #{@filename}:#{@lineno}")
583 @@logger.debug("CADLScanner#scan: SYM_INTERVAL_DELIM at #{@filename}:#{@lineno}")
584 yield :SYM_INTERVAL_DELIM, :SYM_INTERVAL_DELIM
585
586 when /\A\[([a-zA-Z0-9()\._-]+::[a-zA-Z0-9\._-]+)\]/ #V_QUALIFIED_TERM_CODE_REF form [ICD10AM(1998)::F23]
587 yield :V_QUALIFIED_TERM_CODE_REF, $1
588 when /\A\[[a-zA-Z0-9._\- ]+::[a-zA-Z0-9._\- ]+\]/ #ERR_V_QUALIFIED_TERM_CODE_REF
589 yield :ERR_V_QUALIFIED_TERM_CODE_REF, $&
590 when /\A\[([a-zA-Z0-9\(\)\._\-]+)::[ \t\n]*/
591 @adl_type.push(:term_constraint)
592 yield :START_TERM_CODE_CONSTRAINT, $1
593 when /\A\[([a-zA-Z0-9][a-zA-Z0-9._\-]*)\]/ #V_LOCAL_TERM_CODE_REF
594 yield :V_LOCAL_TERM_CODE_REF, $1
595 when /\A\[/ # [
596 yield :Left_bracket_code, :Left_bracket_code
597 when /\A\]/ # ]
598 yield :Right_bracket_code, :Right_bracket_code
599 when /\A[A-Z][a-zA-Z0-9_]*<[a-zA-Z0-9,_<>]+>/ #V_GENERIC_TYPE_IDENTIFIER
600 yield :V_GENERIC_TYPE_IDENTIFIER, $&
601 when /\A[yY][yY][yY][yY]-[mM?X][mM?X]-[dD?X][dD?X][Tt][hH?X][hH?X]:[mM?X][mM?X]:[sS?X][sS?X]/
602 yield :V_ISO8601_DATE_TIME_CONSTRAINT_PATTERN, $&
603 when /\A[yY][yY][yY][yY]-[mM?X][mM?X]-[dD?X][dD?X]/
604 yield :V_ISO8601_DATE_CONSTRAINT_PATTERN, $&
605 when /\A[hH][hH]:[mM?X][mM?X]:[sS?X][sS?X]/
606 yield :V_ISO8601_TIME_CONSTRAINT_PATTERN, $&
607 when /\AP[yY]?[mM]?[wW]?[dD]?T[hH]?[mM]?[sS]?/ #V_ISO8601_DURATION_CONSTRAINT_PATTERN
608 if $&.length == 2
609 case data
610 when /\AP([0-9]+[yY])?([0-9]+[mM])?([0-9]+[wW])?([0-9]+[dD])?T([0-9]+[hH])?([0-9]+[mM])?([0-9.]+[sS])?/ #V_ISO8601_DURATION PnYnMnWnDTnnHnnMnnS
611 yield :V_ISO8601_DURATION, $&
612 else
613 yield :V_ISO8601_DURATION_CONSTRAINT_PATTERN, $&
614 end
615 else
616 yield :V_ISO8601_DURATION_CONSTRAINT_PATTERN, $&
617 end
618 when /\AP[yY]?[mM]?[wW]?[dD]?/ #V_ISO8601_DURATION_CONSTRAINT_PATTERN
619 if $&.length == 1
620 case data
621 when /\AP([0-9]+[yY])?([0-9]+[mM])?([0-9]+[wW])?([0-9]+[dD])?/ #V_ISO8601_DURATION PnYnMnWnDTnnHnnMnnS
622 yield :V_ISO8601_DURATION, $&
623 else
624 yield :V_ISO8601_DURATION_CONSTRAINT_PATTERN, $&
625 end
626 else
627 yield :V_ISO8601_DURATION_CONSTRAINT_PATTERN, $&
628 end
629 when /\AP[yY]?[mM]?[wW]?[dD]?/ #V_ISO8601_DURATION_CONSTRAINT_PATTERN
630 yield :V_ISO8601_DURATION_CONSTRAINT_PATTERN, $&
631 when /\A[a-z][a-zA-Z0-9_]*/
632 word = $&.dup
633 if RESERVED[word.downcase]
634 @@logger.debug("ADLScanner#scan: RESERVED = #{RESERVED[word]} at #{@filename}:#{@lineno}")
635 yield RESERVED[word.downcase], RESERVED[word.downcase]
636 else
637 @@logger.debug("CADLScanner#scan: V_ATTRIBUTE_IDENTIFIER = #{word} at #{@filename}:#{@lineno}")
638 yield :V_ATTRIBUTE_IDENTIFIER, word #V_ATTRIBUTE_IDENTIFIER /\A[a-z][a-zA-Z0-9_]*/
639 end
640 when /\A([A-Z][a-zA-Z0-9_]*)[ \n]*\</ # V_C_DOMAIN_TYPE
641 @in_c_domain_type = true
642 @adl_type.push(:dadl)
643 yield :START_V_C_DOMAIN_TYPE_BLOCK, $1
644 when /\A[A-Z][a-zA-Z0-9_]*/
645 word = $&.dup
646 if RESERVED[word.downcase]
647 yield RESERVED[word.downcase], RESERVED[word.downcase]
648 else
649 yield :V_TYPE_IDENTIFIER, $&
650 end
651 when /\Aa[ct][0-9.]+/ #V_LOCAL_CODE
652 yield :V_LOCAL_CODE, $&
653 when /\A[0-9]{4}-[0-1][0-9]-[0-3][0-9]T[0-2][0-9]:[0-6][0-9]:[0-6][0-9](,[0-9]+)?(Z|[+-][0-9]{4})?/ #V_ISO8601_EXTENDED_DATE_TIME YYYY-MM-DDThh:mm:ss[,sss][Z|+/- -n-n-n-n-]-
654 yield :V_ISO8601_EXTENDED_DATE_TIME, $&
655 when /\A[0-9]{4}-[0-1][0-9]-[0-3][0-9]T[0-2][0-9]:[0-6][0-9](Z|[+-][0-9]{4})?/
656 yield :V_ISO8601_EXTENDED_DATE_TIME, $&
657 when /\A[0-9]{4}-[0-1][0-9]-[0-3][0-9]T[0-2][0-9](Z|[+-][0-9]{4})?/
658 yield :V_ISO8601_EXTENDED_DATE_TIME, $&
659 when /\A[0-2][0-9]:[0-6][0-9]:[0-6][0-9](,[0-9]+)?(Z|[+-][0-9]{4})?/ #V_ISO8601_EXTENDED_TIME hh:mm:ss[,sss][Z|+/-nnnn]
660 yield :V_ISO8601_EXTENDED_TIME, $&
661 when /\A[0-2][0-9]:[0-6][0-9](Z|[+-][0-9]{4})?/ #V_ISO8601_EXTENDED_TIME hh:mm:ss[,sss][Z|+/-nnnn]
662 yield :V_ISO8601_EXTENDED_TIME, $&
663 when /\A[0-9]{4}-[0-1][0-9]-[0-3][0-9]/ #V_ISO8601_EXTENDED_DATE YYYY-MM-DD
664 yield :V_ISO8601_EXTENDED_DATE, $&
665 when /\A[0-9]{4}-[0-1][0-9]/ #V_ISO8601_EXTENDED_DATE YYYY-MM-DD
666 yield :V_ISO8601_EXTENDED_DATE, $&
667 when /\A"((?:[^"\\]+|\\.)*)"/ #V_STRING
668 yield :V_STRING, $1
669 when /\A"([^"]*)"/m #V_STRING
670 yield :V_STRING, $1
671 when /\A[0-9]+\.[0-9]+|[0-9]+\.[0-9]+[eE][+-]?[0-9]+ / #V_REAL
672 yield :V_REAL, $&
673 when /\A[0-9]+|[0-9]+[eE][+-]?[0-9]+/ #V_INTEGER
674 @@logger.debug("CADLScanner#scan: V_INTEGER = #{$&}")
675 yield :V_INTEGER, $&
676 when /\A[a-z]+:\/\/[^<>|\\{}^~"\[\] ]*/ #V_URI
677 yield :V_URI, $&
678 when /\A\S/ #UTF8CHAR
679 yield :UTF8CHAR, $&
680 when /\A.+/ #
681 raise OpenEhr::ADL::Exception::CADLScanner::Base.new, "can't handle #{data.inspect}"
682 end
683 data = $' # variable $' receives the string after the match
684 when :adl
685 adl_scanner = OpenEhr::ADL::Scanner::ADLScanner.new(@adl_type, @filename, @lineno)
686 data = adl_scanner.scan(data) do |sym, val|
687 yield sym, val
688 end
689 when :dadl
690 dadl_scanner = OpenEhr::ADL::Scanner::DADLScanner.new(@adl_type, @filename, @lineno)
691 dadl_scanner.in_c_domain_type = @in_c_domain_type
692 data = dadl_scanner.scan(data) do |sym, val|
693 yield sym, val
694 end
695 when :regexp
696 regex_scanner = OpenEhr::ADL::Scanner::RegexScanner.new(@adl_type, @filename, @lineno)
697 data = regex_scanner.scan(data) do |sym, val|
698 yield sym, val
699 end
700 when :term_constraint
701 term_constraint_scanner = OpenEhr::ADL::Scanner::TermConstraintScanner.new(@adl_type, @filename, @lineno)
702 data = term_constraint_scanner.scan(data) do |sym, val|
703 yield sym, val
704 end
705 else
706 raise OpenEhr::ADL::Exception::CADLScanner.new, "unexpected adl_type: #{@adl_type.last}"
707 end
708 end # of until
709 end
710 end # of CADLScanner
711
712
713 #
714 # RegexScanner
715 #
716 class RegexScanner < Base
717
718 @@logger = OpenEhr::ADL::Scanner::LOGGER #Logger.new('log/scanner.log') #Logger.new('log/scanner.log')
719
720 def initialize(adl_type, filename, lineno = 1)
721 super(adl_type, filename, lineno)
722 end
723
724 def scan(data)
725 @@logger.debug("#{__FILE__}:#{__LINE__}: Entering RegexScanner::scan at #{@filename}:#{@lineno}: data = #{data.inspect}")
726 until data.nil? do
727 case @adl_type.last
728 when :regexp
729 case data
730 when /\A(.*)\// # REGEXP_BODY
731 @adl_type.pop
732 @@logger.debug("#{__FILE__}:#{__LINE__}: RegexScanner::scan REGEXP_BODY = #{$1}")
733 yield :REGEXP_BODY, $1
734 end
735 data = $' # variable $' receives the string after the match
736 when :adl
737 adl_scanner = OpenEhr::ADL::Scanner::ADLScanner.new(@adl_type, @filename, @lineno)
738 data = adl_scanner.scan(data) do |sym, val|
739 yield sym, val
740 end
741 when :dadl
742 dadl_scanner = OpenEhr::ADL::Scanner::DADLScanner.new(@adl_type, @filename, @lineno)
743 data = dadl_scanner.scan(data) do |sym, val|
744 yield sym, val
745 end
746 when :cadl
747 cadl_scanner = OpenEhr::ADL::Scanner::CADLScanner.new(@adl_type, @filename, @lineno)
748 data = cadl_scanner.scan(data) do |sym, val|
749 yield sym, val
750 end
751 when :term_constraint
752 #@@logger.debug("#{__FILE__}:#{__LINE__}: scan_regexp: Entering scan_term_constraint at #{@filename}:#{@lineno}")
753 term_constraint_scanner = OpenEhr::ADL::Scanner::TermConstraintScanner.new(@adl_type, @filename, @lineno)
754 data = term_constraint_scanner.scan(data) do |sym, val|
755 yield sym, val
756 end
757 else
758 raise
759 end
760 end
761 end
762 end # of RegexScanner
763
764 #
765 # TermConstraintScanner
766 #
767 class TermConstraintScanner < Base
768 @@logger = OpenEhr::ADL::Scanner::LOGGER #Logger.new('log/scanner.log') #Logger.new('log/scanner.log')
769 def initialize(adl_type, filename, lineno = 1)
770 super(adl_type, filename, lineno)
771 end
772
773 def scan(data)
774 @@logger.debug("#{__FILE__}:#{__LINE__}: Entering scan_term_constraint")
775 until data.nil? do
776 case @adl_type.last
777 when :term_constraint
778 case data
779 when /\A\n/ # carriage return
780 @lineno += 1
781 ;
782 when /\A[ \t\r\f]+/ #just drop it
783 ;
784 when /\A--.*$/ # single line comment
785 @lineno += 1
786 @@logger.debug("#{__FILE__}:#{__LINE__}: scan_term_constraint: COMMENT = #{$&} at #{@filename}:#{@lineno}")
787 ;
788 when /\A([a-zA-Z0-9\._\-])+[ \t]*,/ # match any line, with ',' termination
789 yield :TERM_CODE, $1
790 when /\A([a-zA-Z0-9\._\-])+[ \t]*;/ # match second last line with ';' termination (assumed value)
791 yield :TERM_CODE, $1
792 when /\A([a-zA-Z0-9\._\-])*[ \t]*\]/ # match final line, terminating in ']'
793 adl_type = @adl_type.pop
794 assert_at(__FILE__,__LINE__){adl_type == :term_constraint}
795 yield :END_TERM_CODE_CONSTRAINT, $1
796# else
797# raise "data = #{data}"
798 end
799 data = $' # variable $' receives the string after the match
800 when :adl
801 adl_scanner = OpenEhr::ADL::Scanner::ADLScanner.new(@adl_type, @filename, @lineno)
802 data = adl_scanner.scan(data) do |sym, val|
803 yield sym, val
804 end
805 when :dadl
806 dadl_scanner = OpenEhr::ADL::Scanner::DADLScanner.new(@adl_type, @filename, @lineno)
807 data = dadl_scanner.scan(data) do |sym, val|
808 yield sym, val
809 end
810 when :cadl
811 cadl_scanner = OpenEhr::ADL::Scanner::CADLScanner.new(@adl_type, @filename, @lineno)
812 data = cadl_scanner.scan(data) do |sym, val|
813 yield sym, val
814 end
815 else
816 raise
817 end
818 end
819 end
820 end # of TermConstraintScanner
821
822 end
823 end
824end
825
826__END__
827
828
829
Note: See TracBrowser for help on using the repository browser.