/tutorial/backtracking/expand_expression/abstract/expand_expression.e

http://github.com/tybor/Liberty · Specman e · 308 lines · 202 code · 22 blank · 84 comment · 15 complexity · c29b859bc133427ca0af536d11a9207c MD5 · raw file

  1. -- See the Copyright notice at the end of this file.
  2. --
  3. class EXPAND_EXPRESSION
  4. --
  5. -- That program shows the use of ABSTRACT_BACKTRACKING.
  6. --
  7. -- That program read expressions from the standard input and print the
  8. -- expansion of the read expression on the standard output.
  9. -- The expressions are composed of sequence and alternative of terms.
  10. -- The expansion is the list of all the sequences allowed when
  11. -- alternatives are removed.
  12. --
  13. -- For example the input expression "(0+1)(0+1)(0+1)" will give the
  14. -- following output:
  15. --
  16. -- (1) 0 0 0
  17. -- (2) 0 0 1
  18. -- (3) 0 1 0
  19. -- (4) 0 1 1
  20. -- (5) 1 0 0
  21. -- (6) 1 0 1
  22. -- (7) 1 1 0
  23. -- (8) 1 1 1
  24. --
  25. -- The grammar of the input expressions is in ABNF like:
  26. --
  27. -- expression ::= alternative
  28. -- alternative ::= sequence [ '+' sequence ]...
  29. -- sequence ::= term [ ['.'] term ]...
  30. -- term ::= | '(' alternative ')' | "[^().+]*"
  31. --
  32. inherit
  33. ABSTRACT_BACKTRACKING
  34. undefine default_create
  35. end
  36. MINI_PARSER_BUFFER
  37. -- a nicer name when inherited!
  38. rename next as next_character
  39. end
  40. EXPRESSION_ITEM_GLOBALS
  41. undefine default_create
  42. end
  43. insert
  44. EXCEPTIONS
  45. undefine default_create
  46. end
  47. create {ANY}
  48. make
  49. feature {ANY} -- make
  50. make
  51. -- read one line and treat it until end of input
  52. do
  53. from
  54. initialise
  55. io.read_line
  56. until
  57. io.end_of_input
  58. loop
  59. parse
  60. expand_all
  61. io.read_line
  62. end
  63. end
  64. initialise
  65. -- initialisation
  66. do
  67. create buffer.make(10)
  68. create stack.with_capacity(100)
  69. end
  70. feature {ANY} -- enumeration of expansions
  71. root, current_item: EXPRESSION_ITEM
  72. goto_item (item: like current_item)
  73. -- set the 'current_item' to 'item'
  74. do
  75. current_item := item
  76. ensure
  77. definition: current_item = item
  78. end
  79. stack: FAST_ARRAY[EXPRESSION_ITEM]
  80. expand_all
  81. -- print all the expansions of the root
  82. local
  83. i, n: INTEGER
  84. do
  85. from
  86. -- go to the first solution
  87. stack.clear_count
  88. goto_item(root)
  89. search_first
  90. until
  91. is_off
  92. loop
  93. -- print the solution using the path iterator
  94. if True then
  95. from
  96. n := n + 1
  97. io.put_string(once "%T(")
  98. io.put_integer(n)
  99. io.put_string(once ")%T")
  100. i := 0
  101. until
  102. i > stack.upper
  103. loop
  104. if i > 0 then
  105. io.put_character(' ')
  106. end
  107. io.put_string(stack.item(i).value)
  108. i := i + 1
  109. end
  110. io.put_new_line
  111. end
  112. -- go to the next solution
  113. search_next
  114. end
  115. io.flush
  116. end
  117. evaluate_current_state
  118. -- Here is how must be driven the and or explorer
  119. -- Only the basic features are called
  120. -- the evaluation of 'current_item' is made depending
  121. -- of its type.
  122. local
  123. alt: EXPAND_ALTERNATIVE; seq: EXPAND_SEQUENCE
  124. do
  125. -- print("evaluation of "+current_item.out+"%N")
  126. inspect
  127. current_item.type
  128. when And_item then
  129. -- should evaluate first and then
  130. -- should evaluate second.
  131. seq := sequence_pool.get_instance
  132. seq.make(current_item.second)
  133. push_sequence(seq)
  134. goto_item(current_item.first)
  135. -- note:
  136. -- goto_item changes current_item then it
  137. -- have to be called after push_and if no
  138. -- temporary variable is used
  139. when Or_item then
  140. -- should evaluate first or else
  141. -- should evaluate second.
  142. alt := alternative_pool.get_instance
  143. alt.make(current_item.second, stack.count)
  144. push_alternative(alt)
  145. goto_item(current_item.first)
  146. when Value_item then
  147. -- record the current item in the path
  148. -- and use continue to go to the next
  149. stack.add_last(current_item)
  150. continue
  151. when Empty_item, Success_item then
  152. -- nothing to do
  153. -- use continue to go to the next
  154. continue
  155. when Failure_item then
  156. -- cancel the evaluation
  157. backtrack
  158. end
  159. end
  160. context_clear, context_push, context_restore, context_restore_and_pop, context_cut
  161. do
  162. end
  163. feature {ANY} -- parsing
  164. parse
  165. -- initialise the mini_parser_buffer behavior
  166. -- then call parse and treat syntax errors with
  167. -- exceptions
  168. local
  169. cancelled: BOOLEAN
  170. do
  171. if not cancelled then
  172. initialize_with(io.last_string)
  173. skip_separators
  174. if end_reached then
  175. root := the_failure_item
  176. else
  177. root := parse_alternative
  178. if not end_reached then
  179. if current_character = ')' then
  180. raise(once "unbounded ')'")
  181. else
  182. raise(once "end not reached")
  183. end
  184. end
  185. end
  186. end
  187. ensure
  188. root /= Void
  189. rescue
  190. root := the_failure_item
  191. io.put_string("Syntax error: ")
  192. io.put_string(developer_exception_name)
  193. io.put_character('%N')
  194. io.last_string.replace_all('%T', ' ')
  195. io.put_string(io.last_string)
  196. io.put_character('%N')
  197. io.put_spaces(current_index - 1)
  198. io.put_character('^')
  199. io.put_character('%N')
  200. cancelled := True
  201. retry
  202. end
  203. parse_alternative: EXPRESSION_ITEM
  204. -- parse an alternative recursively to construct tree
  205. -- balanced to the right because it is more efficient
  206. do
  207. Result := parse_sequence
  208. if not end_reached and then current_character = '+' then
  209. next_character
  210. skip_separators
  211. create Result.make_or(Result, parse_alternative)
  212. end
  213. end
  214. parse_sequence: EXPRESSION_ITEM
  215. -- parse a sequence recursively to construct tree
  216. -- balanced to the right because it is more efficient
  217. do
  218. Result := parse_term
  219. if not end_reached and then not (once "+)").has(current_character) then
  220. create Result.make_and(Result, parse_sequence)
  221. end
  222. end
  223. parse_term: EXPRESSION_ITEM
  224. -- parse a term
  225. do
  226. -- skip any '.' that are noise
  227. from
  228. until
  229. end_reached or else current_character /= '.'
  230. loop
  231. next_character
  232. skip_separators
  233. end
  234. if end_reached or else (once "+)").has(current_character) then
  235. -- if already a termination, return the empty item
  236. Result := the_empty_item
  237. elseif current_character = '(' then
  238. -- parse a sub expression in parenthesis
  239. next_character
  240. skip_separators
  241. Result := parse_alternative
  242. if end_reached or else current_character /= ')' then
  243. raise(once "unbounded '('")
  244. end
  245. next_character
  246. skip_separators
  247. else
  248. -- parse a term
  249. from
  250. buffer.clear_count
  251. until
  252. end_reached or else current_character.is_separator or else (once "()+.").has(current_character)
  253. loop
  254. buffer.add_last(current_character)
  255. next_character
  256. end
  257. create Result.make_value(buffer.twin)
  258. skip_separators
  259. end
  260. end
  261. the_empty_item: EXPRESSION_ITEM
  262. once
  263. create Result.make_empty
  264. end
  265. the_failure_item: EXPRESSION_ITEM
  266. once
  267. create Result.make_failure
  268. end
  269. buffer: STRING
  270. end -- class EXPAND_EXPRESSION
  271. --
  272. -- ------------------------------------------------------------------------------------------------------------------------------
  273. -- Copyright notice below. Please read.
  274. --
  275. -- This file is free software, which comes along with SmartEiffel. This software is distributed in the hope that it will be
  276. -- useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  277. -- You can modify it as you want, provided this footer is kept unaltered, and a notification of the changes is added.
  278. -- You are allowed to redistribute it and sell it, alone or as a part of another product.
  279. --
  280. -- Copyright(C) 1994-2002: INRIA - LORIA (INRIA Lorraine) - ESIAL U.H.P. - University of Nancy 1 - FRANCE
  281. -- Copyright(C) 2003-2005: INRIA - LORIA (INRIA Lorraine) - I.U.T. Charlemagne - University of Nancy 2 - FRANCE
  282. --
  283. -- Authors: Dominique COLNET, Philippe RIBET, Cyril ADRIAN, Vincent CROIZIER, Frederic MERIZEN
  284. --
  285. -- http://SmartEiffel.loria.fr - SmartEiffel@loria.fr
  286. -- ------------------------------------------------------------------------------------------------------------------------------