Index: src/uk/me/parabola/mkgmap/main/StyleTester.java
===================================================================
--- src/uk/me/parabola/mkgmap/main/StyleTester.java	(revision 3436)
+++ src/uk/me/parabola/mkgmap/main/StyleTester.java	(working copy)
@@ -679,6 +679,11 @@
 			public void printStats(String header) {
 				// TODO Auto-generated method stub
 			}
+
+			@Override
+			public int getRuleId() {
+				return 0; // identifies a set
+			}
 		}
 
 		/**
@@ -695,6 +700,7 @@
 			private ReferenceRuleSet finalizeRules;
 			private TokenScanner scanner;
 			private boolean inFinalizeSection = false;
+			private int ruleId;
 
 			public SimpleRuleFileReader(FeatureKind kind, LevelInfo[] levels, ReferenceRuleSet rules) {
 				this.rules = rules;
@@ -736,7 +742,9 @@
 					else if (actions == null)
 						throw new SyntaxException(scanner, "No type definition given");
 
+					ruleId++;
 					saveRule(expr, actions, type);
+					
 					scanner.skipSpace();
 				}
 				if (finalizeRules != null) {
@@ -778,9 +786,9 @@
 			private void saveRule(Op op, ActionList actions, GType gt) {
 				Rule rule;
 				if (actions.isEmpty())
-					rule = new ExpressionRule(op, gt);
+					rule = new ExpressionRule(op, gt, ruleId);
 				else
-					rule = new ActionRule(op, actions.getList(), gt);
+					rule = new ActionRule(op, actions.getList(), gt, ruleId);
 
 				if (inFinalizeSection) 
 					finalizeRules.add(rule);
Index: src/uk/me/parabola/mkgmap/osmstyle/ActionRule.java
===================================================================
--- src/uk/me/parabola/mkgmap/osmstyle/ActionRule.java	(revision 3436)
+++ src/uk/me/parabola/mkgmap/osmstyle/ActionRule.java	(working copy)
@@ -41,6 +41,7 @@
 	private Op expression;
 	private final List<Action> actions;
 	private final GType type;
+	private final int ruleId;
 	private Rule finalizeRule;
 	private long numEval; // count how often the expression was evaluated 
 	private long numTrue; // count how often the evaluation returned true
@@ -52,18 +53,20 @@
 		}
 	};	
 	
-	public ActionRule(Op expression, List<Action> actions, GType type) {
+	public ActionRule(Op expression, List<Action> actions, GType type, int ruleId) {
 		assert actions != null;
 		this.expression = expression;
 		this.actions = actions;
 		this.type = type;
+		this.ruleId = ruleId;
 	}
 
-	public ActionRule(Op expression, List<Action> actions) {
+	public ActionRule(Op expression, List<Action> actions, int ruleId) {
 		assert actions != null;
 		this.expression = expression;
 		this.actions = actions;
 		this.type = null;
+		this.ruleId = ruleId;
 	}
 	
 	
@@ -178,6 +181,11 @@
 	@Override
 	public void printStats(String header) {
 		if (statsLog.isInfoEnabled())
-			statsLog.info(header,"stats (rule/evals/true)", this.toString() + "/" + numEval + "/" + numTrue);
+			statsLog.info(header,"stats (rule/evals/true) rule-id:", this.ruleId, this.toString() + "/" + numEval + "/" + numTrue);
 	}
+
+	@Override
+	public int getRuleId() {
+		return ruleId;
+	}
 }
Index: src/uk/me/parabola/mkgmap/osmstyle/ExpressionRule.java
===================================================================
--- src/uk/me/parabola/mkgmap/osmstyle/ExpressionRule.java	(revision 3436)
+++ src/uk/me/parabola/mkgmap/osmstyle/ExpressionRule.java	(working copy)
@@ -35,6 +35,7 @@
 	private Op expression;
 	private final GType gtype;
 	private Rule finalizeRule;
+	private final int ruleId;
 	private long numEval; // count how often the expression was evaluated 
 	private long numTrue; // count how often the evaluation returned true
 
@@ -45,9 +46,10 @@
 		}
 	};
 	
-	public ExpressionRule(Op expression, GType gtype) {
+	public ExpressionRule(Op expression, GType gtype, int ruleId) {
 		this.expression = expression;
 		this.gtype = gtype;
+		this.ruleId = ruleId;
 	}
 
 	
@@ -108,4 +110,10 @@
 		if (statsLog.isInfoEnabled())
 			statsLog.info(header,"stats (rule/evals/true)", this.toString() + "/" + numEval + "/" + numTrue);
 	}
+
+
+	@Override
+	public int getRuleId() {
+		return ruleId;
+	}
 }
Index: src/uk/me/parabola/mkgmap/osmstyle/RuleFileReader.java
===================================================================
--- src/uk/me/parabola/mkgmap/osmstyle/RuleFileReader.java	(revision 3436)
+++ src/uk/me/parabola/mkgmap/osmstyle/RuleFileReader.java	(working copy)
@@ -66,6 +66,7 @@
 	private final Map<Integer, List<Integer>> overlays;
 
 	private boolean inFinalizeSection = false;
+	private int ruleId;
 	
 	public RuleFileReader(FeatureKind kind, LevelInfo[] levels, RuleSet rules, boolean performChecks, 
 			Map<Integer, List<Integer>> overlays) {
@@ -102,7 +103,7 @@
 
 		ExpressionReader expressionReader = new ExpressionReader(scanner, kind);
 		ActionReader actionReader = new ActionReader(scanner);
-
+		
 		// Read all the rules in the file.
 		scanner.skipSpace();
 		while (!scanner.isEndOfFile()) {
@@ -123,6 +124,7 @@
 			else if (actionList == null)
 				throw new SyntaxException(scanner, "No type definition given");
 
+			ruleId++;
 			saveRule(scanner, expr, actionList, type);
 			scanner.skipSpace();
 		}
@@ -241,6 +243,7 @@
 	 * for expressions that are in the correct basket.  For each expression
 	 * in a basket we know that the first term is true so we can drop that
 	 * from the expression.
+	 * @param ruleId 
 	 */
 	private void saveRule(TokenScanner scanner, Op op, ActionList actions, GType gt) {
 		log.debug("EXP", op, ", type=", gt);
@@ -543,9 +546,9 @@
 
 		Rule rule;
 		if (actions.isEmpty()) 
-			rule = new ExpressionRule(expr, gt);
+			rule = new ExpressionRule(expr, gt, ruleId);
 		else
-			rule = new ActionRule(expr, actions.getList(), gt);
+			rule = new ActionRule(expr, actions.getList(), gt, ruleId);
 
 		if (inFinalizeSection)
 			finalizeRules.add(keystring, rule, actions.getChangeableTags());
Index: src/uk/me/parabola/mkgmap/osmstyle/RuleSet.java
===================================================================
--- src/uk/me/parabola/mkgmap/osmstyle/RuleSet.java	(revision 3436)
+++ src/uk/me/parabola/mkgmap/osmstyle/RuleSet.java	(working copy)
@@ -87,11 +87,19 @@
 			if (rules != null && !rules.isEmpty() )
 				candidates.or(rules);
 		}
+		int lastMatchedRuleId = -1;
 		for (int i = candidates.nextSetBit(0); i >= 0; i = candidates.nextSetBit(i + 1)) {			
 			a.reset();
-			cacheId = rules[i].resolveType(cacheId, el, a);
+			Rule rule = rules[i];
+			if (lastMatchedRuleId >= 0 && lastMatchedRuleId == rule.getRuleId()){
+				log.debug("skipping part of rule",rule.getRuleId(),rule.toString(),"because previous part matched already for",el.toBrowseURL());
+				continue;
+			}
+			cacheId = rule.resolveType(cacheId, el, a);
 			if (a.isResolved())
 				return cacheId;
+			if (a.getMatched())
+				lastMatchedRuleId = rule.getRuleId();
 		}
 		return cacheId;
 	}
@@ -274,4 +282,10 @@
 			finalizeRule.printStats(header);
 	}
 
+
+	@Override
+	public int getRuleId() {
+		return 0;
+	}
+
 } 
\ No newline at end of file
Index: src/uk/me/parabola/mkgmap/reader/osm/Rule.java
===================================================================
--- src/uk/me/parabola/mkgmap/reader/osm/Rule.java	(revision 3436)
+++ src/uk/me/parabola/mkgmap/reader/osm/Rule.java	(working copy)
@@ -53,6 +53,12 @@
 	 */
 	public void setFinalizeRule(Rule finalizeRule);
 	
+	/**
+	 * @return the id that identifies a set of rules which was derived from
+	 * one rule.
+	 */
+	public int getRuleId();
+	
 	public void printStats(String header);
 	
 }
Index: src/uk/me/parabola/mkgmap/reader/osm/WatchableTypeResult.java
===================================================================
--- src/uk/me/parabola/mkgmap/reader/osm/WatchableTypeResult.java	(revision 3436)
+++ src/uk/me/parabola/mkgmap/reader/osm/WatchableTypeResult.java	(working copy)
@@ -24,6 +24,7 @@
 	private boolean found;
 	private boolean continued;
 	private int count;
+	private boolean matched;
 
 	private final TypeResult result;
 
@@ -32,6 +33,7 @@
 	}
 
 	public void add(Element el, GType type) {
+		matched = true;
 		if (type == null) {
 			actionsOnly = true;
 			return;
@@ -54,6 +56,14 @@
 	}
 
 	/**
+	 * 
+	 * @return True if any of the expressions matched since the last reset. 
+	 */
+	public boolean getMatched() {
+		return matched;
+	}
+
+	/**
 	 * Are we all done for this element?
 	 * @return True if we found a matching type and it did not have the continue
 	 * flag set.
@@ -74,5 +84,6 @@
 		actionsOnly = false;
 		continued = false;
 		found = false;
+		matched = false;
 	}
 }
Index: test/uk/me/parabola/mkgmap/osmstyle/ActionReaderTest.java
===================================================================
--- test/uk/me/parabola/mkgmap/osmstyle/ActionReaderTest.java	(revision 3436)
+++ test/uk/me/parabola/mkgmap/osmstyle/ActionReaderTest.java	(working copy)
@@ -41,7 +41,8 @@
  * These are run before any rule is finally matched.
  */
 public class ActionReaderTest {
-
+	private final static int FAKE_RULE_ID = 1;
+	
 	@Test
 	public void testSimpleSet() {
 		List<Action> actions = readActionsFromString("{set park=yes}");
@@ -120,7 +121,7 @@
 				"  '${ref}' | '${name}' ; }");
 		Element el = makeElement();
 		el.addTag("name", "Main St");
-		Rule rule = new ActionRule(null, actions);
+		Rule rule = new ActionRule(null, actions, FAKE_RULE_ID);
 		rule.resolveType(el, TypeResult.NULL_RESULT);
 		assertEquals("just name", "Main St", el.getName());
 	}
@@ -138,7 +139,7 @@
 
 		// Something that matches nothing in the first name command.
 		Element el = makeElement();
-		Rule rule = new ActionRule(null, actions);
+		Rule rule = new ActionRule(null, actions, FAKE_RULE_ID);
 		rule.resolveType(el, TypeResult.NULL_RESULT);
 		assertEquals("no tags, second action matches", "fred", el.getName());
 
@@ -165,7 +166,7 @@
 				"}\n");
 
 		Relation rel = makeRelation();
-		Rule rule = new ActionRule(null, actions);
+		Rule rule = new ActionRule(null, actions, FAKE_RULE_ID);
 		rule.resolveType(rel, TypeResult.NULL_RESULT);
 
 		assertNull("Tag not set on relation", rel.getTag("route"));
@@ -192,7 +193,7 @@
 				"set foo=bar; }}");
 
 		Relation rel = makeRelation();
-		Rule rule = new ActionRule(null, actions);
+		Rule rule = new ActionRule(null, actions, FAKE_RULE_ID);
 		rule.resolveType(rel, TypeResult.NULL_RESULT);
 
 		List<Map.Entry<String,Element>> elements = rel.getElements();
@@ -221,7 +222,7 @@
 		Element el1 = rel.getElements().get(0).getValue();
 		el1.addTag("route_no", "42");
 
-		Rule rule = new ActionRule(null, actions);
+		Rule rule = new ActionRule(null, actions, FAKE_RULE_ID);
 		rule.resolveType(rel, TypeResult.NULL_RESULT);
 		assertEquals("route_no taken from relation tags", "66", el1.getTag("route"));
 	}
@@ -238,7 +239,7 @@
 				"{set fred = '${park}' | 'default value'}");
 
 		Element el = makeElement();
-		Rule rule = new ActionRule(null, actions);
+		Rule rule = new ActionRule(null, actions, FAKE_RULE_ID);
 		rule.resolveType(el, TypeResult.NULL_RESULT);
 		assertEquals("first alternative", "no", el.getTag("fred"));
 	}
@@ -250,13 +251,13 @@
 
 		Element el = makeElement();
 		el.addTag("fred", "origvalue");
-		Rule rule = new ActionRule(null, actions);
+		Rule rule = new ActionRule(null, actions, FAKE_RULE_ID);
 		rule.resolveType(el, TypeResult.NULL_RESULT);
 		assertEquals("second alternative", "default value", el.getTag("fred"));
 	}
 
 	private Element stdElementRun(List<Action> actions) {
-		Rule rule = new ActionRule(null, actions);
+		Rule rule = new ActionRule(null, actions, FAKE_RULE_ID);
 		Element el = makeElement();
 		rule.resolveType(el, TypeResult.NULL_RESULT);
 		return el;
