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

Last change on this file since 323 was 323, checked in by Tatsukawa, Akimichi, 15 years ago

commit at the timing of leaving Pittsburgh

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