/tutorial/backtracking/expand_expression/abstract/expand_expression.e
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-- ------------------------------------------------------------------------------------------------------------------------------