/src/lib/parse/parse_nt_node.e

http://github.com/tybor/Liberty · Specman e · 468 lines · 141 code · 8 blank · 319 comment · 14 complexity · 545f744bc651b8e0add00191661604fa MD5 · raw file

  1. -- This file is part of a Liberty Eiffel library.
  2. -- See the full copyright at the end.
  3. --
  4. class PARSE_NT_NODE
  5. --
  6. -- An internal class used by PARSE_NON_TERMINAL that implements the LL(n) parsing algorithm.
  7. --
  8. insert
  9. TRISTATE_VALUES
  10. redefine
  11. copy, is_equal, out_in_tagged_out_memory
  12. end
  13. LOGGING
  14. redefine
  15. copy, is_equal, out_in_tagged_out_memory
  16. end
  17. creation {PARSE_NON_TERMINAL}
  18. root
  19. creation {PARSE_NT_NODE}
  20. make
  21. feature {ANY}
  22. out_in_tagged_out_memory is
  23. local
  24. i: INTEGER
  25. do
  26. if prefix_name /= Void then
  27. tagged_out_memory.extend('"')
  28. tagged_out_memory.append(prefix_name)
  29. tagged_out_memory.extend('"')
  30. end
  31. if suffices /= Void then
  32. tagged_out_memory.extend('(')
  33. from
  34. i := suffices.lower
  35. until
  36. i > suffices.upper
  37. loop
  38. if i > suffices.lower then
  39. tagged_out_memory.extend('|')
  40. end
  41. suffices.item(i).out_in_tagged_out_memory
  42. i := i + 1
  43. end
  44. tagged_out_memory.extend(')')
  45. end
  46. if end_of_rule then
  47. tagged_out_memory.extend('$')
  48. end
  49. end
  50. feature {PARSE_NON_TERMINAL}
  51. add (rule: TRAVERSABLE[FIXED_STRING]; a_action: PROCEDURE[TUPLE[FIXED_STRING, TRAVERSABLE[FIXED_STRING]]]) is
  52. local
  53. node: PARSE_NT_NODE; name: FIXED_STRING
  54. do
  55. check
  56. is_root: prefix_name = Void
  57. end
  58. if rule.is_empty then
  59. -- a non-terminal with Epsilon
  60. if a_action /= Void then
  61. action := agent call_non_terminal_builder(a_action, rule)
  62. end
  63. end_of_rule := True
  64. else
  65. name := rule.first.intern
  66. node := suffices.fast_reference_at(name)
  67. if node = Void then
  68. create node.make(name, nt)
  69. suffices.add(node, name)
  70. end
  71. node.do_add(a_action, rule, rule.lower)
  72. end
  73. end
  74. parse (buffer: MINI_PARSER_BUFFER; actions: COLLECTION[PARSE_ACTION]): TRISTATE is
  75. local
  76. parse_action: PARSE_ACTION
  77. do
  78. check
  79. is_root: prefix_name = Void
  80. end
  81. Result := parse_suffices(buffer, actions)
  82. if Result /= yes and then end_of_rule then
  83. -- Epsilon
  84. Result := yes
  85. create parse_action.make(action)
  86. debug ("parse")
  87. parse_action.set_name(once "Reduce %"" + nt.name + once "%"")
  88. end
  89. actions.add_last(parse_action)
  90. end
  91. ensure
  92. actions.count >= old actions.count
  93. ;(Result /= yes) implies buffer.current_index = old buffer.current_index and then actions.count = old actions.count
  94. end
  95. feature {PARSE_NON_TERMINAL, PARSE_NT_NODE}
  96. is_coherent: BOOLEAN is
  97. local
  98. i: INTEGER
  99. do
  100. if prefix_name = Void then
  101. Result := True
  102. else
  103. Result := nt.table.has(prefix_name)
  104. end
  105. if suffices /= Void then
  106. from
  107. i := suffices.lower
  108. until
  109. not Result or else i > suffices.upper
  110. loop
  111. Result := suffices.item(i).is_coherent
  112. i := i + 1
  113. end
  114. end
  115. ensure
  116. must_be_coherent: Result
  117. end
  118. set_default_tree_builder (non_terminal_builder: PROCEDURE[TUPLE[FIXED_STRING, TRAVERSABLE[FIXED_STRING]]]; path: COLLECTION[FIXED_STRING]) is
  119. require
  120. non_terminal_builder /= Void
  121. local
  122. i: INTEGER
  123. do
  124. if end_of_rule and then action = Void then
  125. debug ("parse")
  126. log.trace.put_string(once "Setting default non-terminal tree builder for %"")
  127. log.trace.put_string(nt.name)
  128. log.trace.put_string(once "%": ")
  129. if prefix_name = Void then
  130. -- root
  131. check
  132. path.is_empty
  133. end
  134. log.trace.put_line(once "Epsilon")
  135. else
  136. from
  137. i := path.lower
  138. until
  139. i > path.upper
  140. loop
  141. log.trace.put_character('"')
  142. log.trace.put_string(path.item(i))
  143. log.trace.put_character('"')
  144. log.trace.put_character(' ')
  145. i := i + 1
  146. end
  147. log.trace.put_character('"')
  148. log.trace.put_string(prefix_name)
  149. log.trace.put_character('"')
  150. log.trace.put_character('>')
  151. log.trace.put_new_line
  152. end
  153. end
  154. if prefix_name /= Void then
  155. path.add_last(prefix_name)
  156. action := agent call_non_terminal_builder(non_terminal_builder, path.twin)
  157. path.remove_last
  158. else
  159. -- Epsilon rule
  160. check
  161. path.is_empty
  162. end
  163. action := agent call_non_terminal_builder(non_terminal_builder, path.twin)
  164. end
  165. end
  166. if suffices /= Void then
  167. if prefix_name = Void then
  168. -- root
  169. check
  170. path.is_empty
  171. end
  172. from
  173. i := suffices.lower
  174. until
  175. i > suffices.upper
  176. loop
  177. suffices.item(i).set_default_tree_builder(non_terminal_builder, path)
  178. i := i + 1
  179. end
  180. else
  181. path.add_last(Void)
  182. from
  183. i := suffices.lower
  184. until
  185. i > suffices.upper
  186. loop
  187. path.put(prefix_name, path.upper)
  188. suffices.item(i).set_default_tree_builder(non_terminal_builder, path)
  189. i := i + 1
  190. end
  191. path.remove_last
  192. end
  193. end
  194. end
  195. set_non_terminal (a_non_terminal: like nt) is
  196. local
  197. i: INTEGER
  198. do
  199. nt := a_non_terminal
  200. if suffices /= Void then
  201. from
  202. i := suffices.lower
  203. until
  204. i > suffices.upper
  205. loop
  206. suffices.item(i).set_non_terminal(a_non_terminal)
  207. i := i + 1
  208. end
  209. end
  210. ensure
  211. nt = a_non_terminal
  212. end
  213. feature {PARSE_NT_NODE}
  214. do_add (a_action: PROCEDURE[TUPLE[FIXED_STRING, TRAVERSABLE[FIXED_STRING]]]; rule: TRAVERSABLE[FIXED_STRING]; i: INTEGER) is
  215. require
  216. rule.valid_index(i)
  217. rule.item(i) = prefix_name
  218. local
  219. name: FIXED_STRING; node: PARSE_NT_NODE
  220. do
  221. if i < rule.upper then
  222. name := rule.item(i + 1).intern
  223. if suffices = Void then
  224. create suffices.make
  225. end
  226. node := suffices.fast_reference_at(name)
  227. if node = Void then
  228. create node.make(name, nt)
  229. suffices.add(node, name)
  230. end
  231. node.do_add(a_action, rule, i + 1)
  232. else
  233. check
  234. i = rule.upper
  235. end
  236. if a_action /= Void then
  237. action := agent call_non_terminal_builder(a_action, rule)
  238. end
  239. end_of_rule := True
  240. end
  241. end
  242. do_parse (buffer: MINI_PARSER_BUFFER; actions: COLLECTION[PARSE_ACTION]): TRISTATE is
  243. require
  244. not_root: prefix_name /= Void
  245. local
  246. memo, old_count: INTEGER; atom: PARSE_ATOM
  247. parse_action: PARSE_ACTION
  248. do
  249. memo := buffer.memo
  250. old_count := actions.count
  251. atom := nt.table.item(prefix_name)
  252. check
  253. atom /= Void
  254. end
  255. Result := atom.parse(buffer, actions)
  256. check
  257. suffices = Void implies end_of_rule
  258. end
  259. if Result = yes then
  260. if suffices = Void then
  261. create parse_action.make(action)
  262. debug ("parse")
  263. parse_action.set_name(once "Reduce %"" + nt.name + once "%"")
  264. end
  265. actions.add_last(parse_action)
  266. else
  267. Result := parse_suffices(buffer, actions)
  268. if Result /= yes and then end_of_rule then
  269. -- that's fine: we can end here
  270. Result := yes
  271. create parse_action.make(action)
  272. debug ("parse")
  273. parse_action.set_name(once "Reduce %"" + nt.name + once "%"")
  274. end
  275. actions.add_last(parse_action)
  276. end
  277. end
  278. end
  279. if Result /= yes then
  280. buffer.restore(memo)
  281. if actions.count > old_count then
  282. actions.remove_tail(actions.count - old_count)
  283. end
  284. end
  285. ensure
  286. (Result /= yes) implies buffer.current_index = old buffer.current_index and then actions.count = old actions.count
  287. end
  288. feature {}
  289. parse_suffices (buffer: MINI_PARSER_BUFFER; actions: COLLECTION[PARSE_ACTION]): TRISTATE is
  290. require
  291. suffices /= Void
  292. local
  293. memo, old_count, i: INTEGER; node: PARSE_NT_NODE; parsenode: TRISTATE; perhaps: BOOLEAN
  294. do
  295. debug ("parse")
  296. log.trace.put_string(once "Scanning non-terminal %"")
  297. log.trace.put_string(nt.name)
  298. log.trace.put_character('"')
  299. if prefix_name /= Void then
  300. log.trace.put_string(once " for a suffix of %"")
  301. log.trace.put_string(prefix_name)
  302. log.trace.put_character('"')
  303. end
  304. log.trace.put_new_line
  305. end
  306. memo := buffer.memo
  307. old_count := actions.count
  308. from
  309. i := suffices.lower
  310. Result := no
  311. until
  312. Result = yes or else i > suffices.upper
  313. loop
  314. node := suffices.item(i)
  315. parsenode := node.do_parse(buffer, actions)
  316. if parsenode = yes then
  317. Result := yes
  318. else
  319. if parsenode = maybe then
  320. perhaps := True
  321. end
  322. buffer.restore(memo)
  323. if actions.count > old_count then
  324. actions.remove_tail(actions.count - old_count)
  325. end
  326. debug ("parse")
  327. log.trace.put_string(once "Still scanning non-terminal %"")
  328. log.trace.put_string(nt.name)
  329. log.trace.put_character('"')
  330. if prefix_name /= Void then
  331. log.trace.put_string(once " for a suffix of %"")
  332. log.trace.put_string(prefix_name)
  333. log.trace.put_character('"')
  334. end
  335. log.trace.put_string(once " (%"")
  336. log.trace.put_string(suffices.key(i))
  337. log.trace.put_line(once "%" did not match)")
  338. end
  339. i := i + 1
  340. end
  341. end
  342. if Result = no and then perhaps then
  343. Result := maybe
  344. end
  345. ensure
  346. (Result /= yes) implies buffer.current_index = old buffer.current_index and then actions.count = old actions.count
  347. end
  348. feature {}
  349. call_non_terminal_builder (non_terminal_builder: PROCEDURE[TUPLE[FIXED_STRING, TRAVERSABLE[FIXED_STRING]]]; path: TRAVERSABLE[FIXED_STRING]) is
  350. do
  351. non_terminal_builder.call([nt.name, path])
  352. end
  353. feature {}
  354. make (a_prefix_name: like prefix_name; a_nt: like nt) is
  355. require
  356. a_prefix_name /= Void
  357. a_nt /= Void
  358. do
  359. prefix_name := a_prefix_name
  360. nt := a_nt
  361. ensure
  362. prefix_name = a_prefix_name
  363. nt = a_nt
  364. end
  365. root (a_nt: like nt) is
  366. require
  367. a_nt /= Void
  368. do
  369. nt := a_nt
  370. create suffices.make
  371. ensure
  372. nt = a_nt
  373. suffices /= Void
  374. is_root: prefix_name = Void
  375. end
  376. feature {ANY}
  377. copy (other: like Current) is
  378. local
  379. i: INTEGER
  380. do
  381. nt := other.nt
  382. prefix_name := other.prefix_name
  383. action := other.action
  384. end_of_rule := other.end_of_rule
  385. if other.suffices /= Void then
  386. create suffices.with_capacity(other.suffices.capacity)
  387. from
  388. i := other.suffices.lower
  389. until
  390. i > other.suffices.upper
  391. loop
  392. suffices.add(other.suffices.item(i).twin, other.suffices.key(i))
  393. i := i + 1
  394. end
  395. end
  396. end
  397. is_equal (other: like Current): BOOLEAN is
  398. local
  399. i: INTEGER
  400. do
  401. Result := prefix_name = other.prefix_name
  402. and then action = other.action
  403. and then end_of_rule = other.end_of_rule
  404. if Result and then other.suffices /= Void then
  405. Result := suffices /= Void and then suffices.count = other.suffices.count
  406. from
  407. i := suffices.lower
  408. until
  409. not Result or else i > suffices.upper
  410. loop
  411. Result := suffices.fast_reference_at(other.suffices.key(i)).is_equal(other.suffices.item(i))
  412. i := i + 1
  413. end
  414. end
  415. end
  416. feature {PARSE_NT_NODE}
  417. prefix_name: FIXED_STRING
  418. suffices: HASHED_DICTIONARY[PARSE_NT_NODE, FIXED_STRING]
  419. nt: PARSE_NON_TERMINAL
  420. action: PROCEDURE[TUPLE]
  421. end_of_rule: BOOLEAN
  422. invariant
  423. backlinked: nt /= Void
  424. end -- class PARSE_NT_NODE
  425. --
  426. -- Copyright (c) 2009 by all the people cited in the AUTHORS file.
  427. --
  428. -- Permission is hereby granted, free of charge, to any person obtaining a copy
  429. -- of this software and associated documentation files (the "Software"), to deal
  430. -- in the Software without restriction, including without limitation the rights
  431. -- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  432. -- copies of the Software, and to permit persons to whom the Software is
  433. -- furnished to do so, subject to the following conditions:
  434. --
  435. -- The above copyright notice and this permission notice shall be included in
  436. -- all copies or substantial portions of the Software.
  437. --
  438. -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  439. -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  440. -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  441. -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  442. -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  443. -- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  444. -- THE SOFTWARE.