PageRenderTime 54ms CodeModel.GetById 46ms app.highlight 3ms RepoModel.GetById 1ms app.codeStats 1ms

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