PageRenderTime 9ms CodeModel.GetById 1ms app.highlight 3ms RepoModel.GetById 2ms app.codeStats 0ms

/tutorial/backtracking/expand_expression/tree/expand_expression.e

http://github.com/tybor/Liberty
Specman e | 280 lines | 190 code | 24 blank | 66 comment | 15 complexity | cb36d321ac6545bc2d630d71e325eee5 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   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   BACKTRACKING_NODE_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         create context.with_capacity(100)
 75      end
 76
 77feature {ANY} -- enumeration of expansions
 78   root: BACKTRACKING_NODE
 79
 80   stack: FAST_ARRAY[STRING]
 81
 82   context: FAST_ARRAY[INTEGER]
 83
 84   top: INTEGER
 85
 86   expand_all
 87         -- print all the expansions of the root
 88      local
 89         i, n: INTEGER
 90      do
 91         from
 92            -- go to the first solution
 93            stack.clear_count
 94            set_current_node(root)
 95            search_first
 96         until
 97            is_off
 98         loop
 99            -- print the solution using the path iterator
100            if True then
101               from
102                  n := n + 1
103                  io.put_string(once "%T(")
104                  io.put_integer(n)
105                  io.put_string(once ")%T")
106                  i := 0
107               until
108                  i > stack.upper
109               loop
110                  if i > 0 then
111                     io.put_character(' ')
112                  end
113                  io.put_string(stack.item(i))
114                  i := i + 1
115               end
116               io.put_new_line
117            end
118            -- go to the next solution
119            search_next
120         end
121         io.flush
122      end
123
124   context_clear
125      do
126         context.clear_count
127         stack.clear_count
128         top := 0
129      end
130
131   context_push
132      do
133         context.add_last(top)
134         top := stack.count
135      end
136
137   context_restore
138      do
139         stack.resize(top)
140      end
141
142   context_restore_and_pop
143      do
144         stack.resize(top)
145         top := context.last
146         context.remove_last
147      end
148
149   context_cut
150         -- no cut allowed
151      do
152         check
153            False
154         end
155      end
156
157feature {ANY} -- parsing
158   parse
159         -- initialise the mini_parser_buffer behavior
160         -- then call parse and treat syntax errors with
161         -- exceptions
162      local
163         cancelled: BOOLEAN
164      do
165         if not cancelled then
166            initialize_with(io.last_string)
167            skip_separators
168            if end_reached then
169               root := the_false_node
170            else
171               root := parse_alternative
172               if not end_reached then
173                  if current_character = ')' then
174                     raise(once "unbounded ')'")
175                  else
176                     raise(once "end not reached")
177                  end
178               end
179            end
180         end
181      ensure
182         root /= Void
183      rescue
184         root := the_false_node
185         io.put_string("Syntax error: ")
186         io.put_string(developer_exception_name)
187         io.put_character('%N')
188         io.last_string.replace_all('%T', ' ')
189         io.put_string(io.last_string)
190         io.put_character('%N')
191         io.put_spaces(current_index - 1)
192         io.put_character('^')
193         io.put_character('%N')
194         cancelled := True
195         retry
196      end
197
198   parse_alternative: BACKTRACKING_NODE
199         -- parse an alternative recursively to construct tree
200         -- balanced to the right because it is more efficient
201      do
202         Result := parse_sequence
203         if not end_reached and then current_character = '+' then
204            next_character
205            skip_separators
206            create {BACKTRACKING_NODE_OR_PAIR} Result.make(Result, parse_alternative)
207         end
208      end
209
210   parse_sequence: BACKTRACKING_NODE
211         -- parse a sequence recursively to construct tree
212         -- balanced to the right because it is more efficient
213      do
214         Result := parse_term
215         if not end_reached and then not (once "+)").has(current_character) then
216            create {BACKTRACKING_NODE_AND_PAIR} Result.make(Result, parse_sequence)
217         end
218      end
219
220   parse_term: BACKTRACKING_NODE
221         -- parse a term
222      do
223         -- skip any '.' that are noise
224         from
225         until
226            end_reached or else current_character /= '.'
227         loop
228            next_character
229            skip_separators
230         end
231
232         if end_reached or else (once "+)").has(current_character) then
233            -- if already a termination, return the empty item
234            Result := the_true_node
235         elseif current_character = '(' then
236            -- parse a sub expression in parenthesis
237            next_character
238            skip_separators
239            Result := parse_alternative
240            if end_reached or else current_character /= ')' then
241               raise(once "unbounded '('")
242            end
243
244            next_character
245            skip_separators
246         else
247            -- parse a term
248            from
249               buffer.clear_count
250            until
251               end_reached or else current_character.is_separator or else (once "()+.").has(current_character)
252            loop
253               buffer.add_last(current_character)
254               next_character
255            end
256
257            create {STRING_NODE} Result.make(buffer.twin)
258            skip_separators
259         end
260      end
261
262   buffer: STRING
263
264end -- class EXPAND_EXPRESSION
265--
266-- ------------------------------------------------------------------------------------------------------------------------------
267-- Copyright notice below. Please read.
268--
269-- This file is free software, which comes along with SmartEiffel. This software is distributed in the hope that it will be
270-- useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
271-- You can modify it as you want, provided this footer is kept unaltered, and a notification of the changes is added.
272-- You are allowed to redistribute it and sell it, alone or as a part of another product.
273--
274-- Copyright(C) 1994-2002: INRIA - LORIA (INRIA Lorraine) - ESIAL U.H.P.       - University of Nancy 1 - FRANCE
275-- Copyright(C) 2003-2005: INRIA - LORIA (INRIA Lorraine) - I.U.T. Charlemagne - University of Nancy 2 - FRANCE
276--
277-- Authors: Dominique COLNET, Philippe RIBET, Cyril ADRIAN, Vincent CROIZIER, Frederic MERIZEN
278--
279-- http://SmartEiffel.loria.fr - SmartEiffel@loria.fr
280-- ------------------------------------------------------------------------------------------------------------------------------