From d4a2f58eb57b0ea1cf2763c9b16ea99ca2867a8d Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 11 Nov 2013 23:09:25 -0600 Subject: [PATCH] Regex: implement alternatives Now we support regular expressions like 'A|B|C'. Signed-off-by: Johannes Schindelin --- test/Regex.java | 2 ++ test/regex/Compiler.java | 39 ++++++++++++++++++++++++++++++++++++--- 2 files changed, 38 insertions(+), 3 deletions(-) diff --git a/test/Regex.java b/test/Regex.java index 56b1356d4f..b5545564e7 100644 --- a/test/Regex.java +++ b/test/Regex.java @@ -57,5 +57,7 @@ public class Regex { expectMatch("[0-9A-Fa-f]+", "08ef"); expectNoMatch("[0-9A-Fa-f]+", "08@ef"); expectGroups("(?:a)", "a"); + expectGroups("a|(b|c)", "a", (String)null); + expectGroups("a|(b|c)", "c", "c"); } } diff --git a/test/regex/Compiler.java b/test/regex/Compiler.java index a27a93388f..3b250ca640 100644 --- a/test/regex/Compiler.java +++ b/test/regex/Compiler.java @@ -143,9 +143,13 @@ class Compiler implements PikeVMOpcodes { private final boolean capturing; private ArrayList list = new ArrayList(); + private ArrayList alternatives; - public Group(boolean capturing) { + public Group(boolean capturing, ArrayList initialList) { this.capturing = capturing; + if (initialList != null) { + list.addAll(initialList); + } } public void push(Expression expr) { @@ -160,6 +164,14 @@ class Compiler implements PikeVMOpcodes { }); } + public void startAlternative() { + if (alternatives == null) { + alternatives = new ArrayList(); + } + alternatives.add(new Group(false, list)); + list.clear(); + } + public Expression pop() { Expression result = list.remove(list.size() - 1); return result; @@ -172,9 +184,27 @@ class Compiler implements PikeVMOpcodes { output.add(SAVE_OFFSET); output.add(2 * groupIndex); } + int[] jumps = null; + if (alternatives != null) { + jumps = new int[alternatives.size()]; + int i = 0; + for (Group alternative : alternatives) { + output.add(SPLIT); + int jump = output.markJump(); + alternative.writeCode(output); + output.add(JMP); + jumps[i++] = output.markJump(); + output.setJump(jump); + } + } for (Expression expr : list) { expr.writeCode(output); } + if (jumps != null) { + for (int jump : jumps) { + output.setJump(jump); + } + } if (capturing) { output.add(SAVE_OFFSET); output.add(2 * groupIndex + 1); @@ -186,7 +216,7 @@ class Compiler implements PikeVMOpcodes { private final Group group; public Group0() { - group = new Group(true); + group = new Group(true, null); } public void writeCode(Output output) { @@ -249,7 +279,7 @@ class Compiler implements PikeVMOpcodes { + regex.substring(index)); } } - current.push(groups.push(new Group(capturing))); + current.push(groups.push(new Group(capturing, null))); continue; } case ')': @@ -268,6 +298,9 @@ class Compiler implements PikeVMOpcodes { index = characterClassParser.getEndOffset() - 1; continue; } + case '|': + current.startAlternative(); + continue; default: throw new RuntimeException("Parse error @" + index + ": " + regex); }