Not terminating loop possible with RX_PCRE_REGULAR_EXPRESSION.replace_all

Berend de Boer <[email protected]> Mon, 08 Jun 2009 19:09:26 +0200
Newsgroups gmane.comp.lang.eiffel.gobo.general
Message-ID <[email protected]>
Hi All,

I've encountered a regular expression that causes a loop not to
terminate. It happens when you want to insert something at the
beginning of a string, optionally replacing a prefix. Example code:

--------------------------------------------------
class

	TEST

create

	make

feature

	make is
		local
			rx: RX_PCRE_REGULAR_EXPRESSION
			s: STRING
		do
			create rx.make
			rx.compile ("^(bye\.)?")
			rx.match (" world")
			s := rx.replace_all ("hello")    -- <== problem
			print (s + "%N")
		end

end
--------------------------------------------------

If you run this program, hit Ctrl+C quickly, as it will eat up all
your CPU and memory very very quickly.

What it should do is emit "hello world" obviously.


The problem is in rx.replace_all. This calls
RX_REGULAR_EXPRESSION.append_replace_all_to_string, where we have this
loop:

			from until not has_matched loop
				STRING_.append_substring_to_string (a_string, subject, subject_start, captured_start_position (0) - 1)
				append_replacement_to_string (a_string, a_replacement)
				match_substring (subject, captured_end_position (0) + 1, subject_end)
			end

What happens is that the start position is 1, and the end position is
0. has_matched is always true. I'm not sure how to solve this. This
was what I have now:

			p: INTEGER
		do
			from until not has_matched loop
				STRING_.append_substring_to_string (a_string, subject, subject_start, captured_start_position (0) - 1)
				append_replacement_to_string (a_string, a_replacement)
				p := captured_end_position (0)
				if p = 0 then
					-- Get out of loop if we matched beginning
					match_count := 0
				else
					match_substring (subject, p + 1, subject_end)
				end
			end

Works for this particular case of course, but not sure of the
ramifications, or on how to solve it more generally.

Probably there should be a test that we are not advancing, and that
should terminate the loop as well. But I have currently no clue how to
write that code.


Here the compile_ge.xace to compile this sample:

--------------------------------------------------
<?xml version="1.0"?>

<system name="test">
	<root class="TEST" creation="make"/>
	<option name="assertion" value="none"/>
	<option name="finalize" value="true"/>
	<option name="garbage_collector" value="internal"/>
	<cluster name="test" location="."/>
	<cluster name="ge" location="${GOBO}/library"/>
	<cluster name="argument" location="${GOBO}/library/argument" prefix="ap_"/>
	<cluster name="kernel" location="${GOBO}/library/kernel" prefix="kl_">
		<option name="abstract" value="true"/>
		<cluster name="basic"/>
		<cluster name="io"/>
		<cluster name="misc"/>
		<cluster name="unicode"/>
		<cluster name="support"/>
		<cluster name="spec">
			<option name="abstract" value="true"/>
			<cluster name="ge" prefix="kl_spec_"/>
		</cluster>
	</cluster>
	<cluster name="lexical" location="${GOBO}/library/lexical" prefix="lx_">
		<option name="abstract" value="true"/>
		<cluster name="automaton"/>
		<cluster name="error"/>
		<cluster name="generation"/>
		<cluster name="lex"/>
		<cluster name="regexp"/>
		<cluster name="scanner"/>
		<cluster name="skeleton"/>
		<cluster name="support"/>
	</cluster>
	<cluster name="math" location="${GOBO}/library/math" prefix="ma_">
		<option name="abstract" value="true"/>
		<cluster name="decimal"/>
	</cluster>
	<cluster name="parse" location="${GOBO}/library/parse" prefix="pr_">
		<option name="abstract" value="true"/>
		<cluster name="error"/>
		<cluster name="fsm"/>
		<cluster name="generation"/>
		<cluster name="grammar"/>
		<cluster name="parser"/>
		<cluster name="skeleton"/>
		<cluster name="support"/>
		<cluster name="yacc"/>
	</cluster>
	<cluster name="pattern" location="${GOBO}/library/pattern" prefix="dp_">
		<option name="abstract" value="true"/>
		<cluster name="bridge"/>
		<cluster name="command"/>
	</cluster>
	<cluster name="regexp" location="${GOBO}/library/regexp" prefix="rx_">
		<option name="abstract" value="true"/>
		<cluster name="interface"/>
		<cluster name="pcre"/>
		<cluster name="support"/>
	</cluster>
	<cluster name="string" location="${GOBO}/library/string" prefix="st_">
		<option name="abstract" value="true"/>
		<cluster name="collation"/>
		<cluster name="unicode"/>
		<cluster name="support"/>
		<cluster name="date"/>
		<cluster name="formatter">
			<option name="abstract" value="true"/>
			<cluster name="general"/>
			<cluster name="parameter"/>
		</cluster>
	</cluster>
	<cluster name="structure" location="${GOBO}/library/structure" prefix="ds_">
		<option name="abstract" value="true"/>
		<cluster name="container"/>
		<cluster name="dispenser"/>
		<cluster name="list"/>
		<cluster name="set"/>
		<cluster name="sort"/>
		<cluster name="support"/>
		<cluster name="table"/>
	</cluster>
	<cluster name="test" location="${GOBO}/library/test" prefix="ts_">
		<option name="abstract" value="true"/>
		<cluster name="generation"/>
		<cluster name="harness"/>
	</cluster>
	<cluster name="time" location="${GOBO}/library/time" prefix="dt_">
		<option name="abstract" value="true"/>
		<cluster name="clock"/>
		<cluster name="date"/>
		<cluster name="stopwatch"/>
		<cluster name="time_zone"/>
	</cluster>
	<cluster name="tools" location="${GOBO}/library/tools" prefix="et_">
		<option name="abstract" value="true"/>
		<cluster name="eiffel" prefix="et_eiffel_">
			<option name="abstract" value="true"/>
			<cluster name="ast">
				<option name="abstract" value="true"/>
				<cluster name="agent"/>
				<cluster name="assertion"/>
				<cluster name="class"/>
				<cluster name="constant"/>
				<cluster name="expression"/>
				<cluster name="feature"/>
				<cluster name="group"/>
				<cluster name="instruction"/>
				<cluster name="misc"/>
				<cluster name="name"/>
				<cluster name="type"/>
			</cluster>
			<cluster name="compilation"/>
			<cluster name="dynamic"/>
			<cluster name="error"/>
			<cluster name="generation"/>
			<cluster name="parser"/>
			<cluster name="processor"/>
		</cluster>
		<cluster name="lace" prefix="et_lace_">
			<option name="abstract" value="true"/>
			<cluster name="ast"/>
			<cluster name="error"/>
			<cluster name="parser"/>
		</cluster>
		<cluster name="ecf" prefix="et_ecf_">
			<option name="abstract" value="true"/>
			<cluster name="ast"/>
			<cluster name="error"/>
			<cluster name="parser"/>
		</cluster>
		<cluster name="xace" prefix="et_xace_">
			<option name="abstract" value="true"/>
			<cluster name="ast"/>
			<cluster name="error"/>
			<cluster name="generator"/>
			<cluster name="parser"/>
			<cluster name="support"/>
		</cluster>
	</cluster>
	<cluster name="utility" location="${GOBO}/library/utility" prefix="ut_">
		<option name="abstract" value="true"/>
		<cluster name="error"/>
		<cluster name="formatter"/>
		<cluster name="config"/>
		<cluster name="support"/>
		<cluster name="transcoder"/>
		<cluster name="uri"/>
	</cluster>
	<cluster name="xml" location="${GOBO}/library/xml" prefix="xm_">
		<option name="abstract" value="true"/>
		<cluster name="position"/>
		<cluster name="source"/>
		<cluster name="general"/>
		<cluster name="event"/>
		<cluster name="tree"/>
		<cluster name="formatter"/>
		<cluster name="resolver">
			<option name="abstract" value="true"/>
			<cluster name="resolver_interface" location="interface" relative="true"/>
			<cluster name="catalog"/>
			<cluster name="simple"/>
			<cluster name="uri"/>
		</cluster>
		<cluster name="parser">
			<option name="abstract" value="true"/>
			<cluster name="interface"/>
			<cluster name="eiffel"/>
			<cluster name="no_expat"/>
		</cluster>
		<cluster name="xml_xpointer" location="${GOBO}/library/xml/xpointer">
			<option name="abstract" value="true"/>
			<cluster name="xpointer_common" location="common" relative="true"/>
			<cluster name="xpointer_event" location="event" relative="true"/>
		</cluster>
	</cluster>
	<cluster name="xml_xslt" location="${GOBO}/library/xml/xslt" prefix="xm_">
		<option name="abstract" value="true"/>
		<cluster name="pattern"/>
		<cluster name="xslt_function" location="function" relative="true"/>
		<cluster name="instruction"/>
		<cluster name="style"/>
		<cluster name="tracing"/>
		<cluster name="number"/>
		<cluster name="xslt_sort" location="sort" relative="true"/>
		<cluster name="xslt_event" location="event" relative="true"/>
		<cluster name="runtime"/>
		<cluster name="xslt_core" location="core" relative="true"/>
		<cluster name="xslt_serializer" location="serializer" relative="true"/>
	</cluster>
	<cluster name="xml_xpath" location="${GOBO}/library/xml/xpath" prefix="xm_">
		<option name="abstract" value="true"/>
		<cluster name="data_model"/>
		<cluster name="tinytree"/>
		<cluster name="xpath_tree" location="tree" relative="true"/>
		<cluster name="value"/>
		<cluster name="expression"/>
		<cluster name="xpath_event" location="event" relative="true"/>
		<cluster name="function"/>
		<cluster name="sort"/>
		<cluster name="stand_alone"/>
		<cluster name="node_test"/>
		<cluster name="type"/>
		<cluster name="xpath_xpointer" location="xpointer" relative="true"/>
		<cluster name="core"/>
	</cluster>
	<cluster name="free_elks" location="${GOBO}/library/free_elks" prefix="fe_">
		<option name="abstract" value="true"/>
		<cluster name="fake"/>
		<cluster name="kernel"/>
		<cluster name="refactoring"/>
		<cluster name="structures">
			<cluster name="access"/>
			<cluster name="cursor_tree"/>
			<cluster name="cursors"/>
			<cluster name="dispenser"/>
			<cluster name="iteration"/>
			<cluster name="list"/>
			<cluster name="set">
				<cluster name="strategies"/>
			</cluster>
			<cluster name="sort"/>
			<cluster name="storage"/>
			<cluster name="table"/>
			<cluster name="traversing"/>
			<cluster name="tree"/>
		</cluster>
		<cluster name="support"/>
	</cluster>
</system>
--------------------------------------------------


-- 
All the best,

Berend de Boer


------------------------------------

To Post a message, send it to:   [email protected]
To Unsubscribe, send a blank message to: [email protected]! Groups Links

<*> To visit your group on the web, go to:
    http://groups.yahoo.com/group/gobo-eiffel/

<*> Your email settings:
    Individual Email | Traditional

<*> To change settings online go to:
    http://groups.yahoo.com/group/gobo-eiffel/join
    (Yahoo! ID required)

<*> To change settings via email:
    mailto:[email protected] 
    mailto:[email protected]

<*> To unsubscribe from this group, send an email to:
    [email protected]

<*> Your use of Yahoo! Groups is subject to:
    http://docs.yahoo.com/info/terms/