// // Copyright (C) 2006 United States Government as represented by the // Administrator of the National Aeronautics and Space Administration // (NASA). All Rights Reserved. // // This software is distributed under the NASA Open Source Agreement // (NOSA), version 1.3. The NOSA has been approved by the Open Source // Initiative. See the file NOSA-1.3-JPF at the top of the distribution // directory tree for the complete NOSA document. // // THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF ANY // KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT // LIMITED TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO // SPECIFICATIONS, ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR // A PARTICULAR PURPOSE, OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT // THE SUBJECT SOFTWARE WILL BE ERROR FREE, OR ANY WARRANTY THAT // DOCUMENTATION, IF PROVIDED, WILL CONFORM TO THE SUBJECT SOFTWARE. // package gov.nasa.jpf.util.script; import java.util.LinkedList; import java.util.List; /** * utility class to expand regular expression like strings. We support * alternatives "<..|..>" and character categories "[.. X-Z ..]". Alternatives * can be nested, char categories can include '-' ranges * * e.g. "a<B|X[0-1]Y>z" => aBz, aX0Yz, aX1Yz * * <2do> this is awfully connected to ESParser - we should really make it more generic * (this is the reason why it was moved from the general gov.nasa.jpf.util to * this package) */ public class StringExpander { public static final char META_CHAR = '`'; // starts a symbol public static final char ALT_START_CHAR = '<'; public static final char ALT_END_CHAR = '>'; public static final char ALT_CHAR = '|'; public static final char CAT_START_CHAR = '['; public static final char CAT_END_CHAR = ']'; public static final char CAT_CHAR = '-'; static class Exception extends RuntimeException { Exception(String details){ super(details); } } static class Token { String value; Token (String value){ this.value = value; } int length() { return value.length(); } boolean isSymbol() { return false; } public String toString(){ return value; } } static class Symbol extends Token { Symbol (String s){ super(s); } boolean isSymbol(){ return true; } } // our symbol tokens static final Symbol CAT_START = new Symbol("CAT_START"); static final Symbol CAT_END = new Symbol("CAT_END"); static final Symbol ALT_START = new Symbol("ALT_START"); static final Symbol ALT_END = new Symbol("ALT_END"); static final Symbol ALT = new Symbol("ALT"); static final Symbol EOS = new Symbol("END"); final String src; final int len; Token token; int pos; /** // a quoted symbol char version - doesn't look nice, but is more general void nextToken () { int i = pos; int len = this.len; if (i>=len){ token = EOS; } else { if (src.charAt(i) == META_CHAR){ // symbol char c = src.charAt(++i); switch (c){ case CAT_START_CHAR: token = CAT_START; break; case CAT_END_CHAR: token = CAT_END; break; case ALT_START_CHAR: token = ALT_START; break; case ALT_CHAR: token = ALT; break; case ALT_END_CHAR: token = ALT_END; break; default: error("illegal symbol: " + c); } pos += 2; } else { // string literal int j = i + 1; for (; j < len && src.charAt(j) != META_CHAR; j++); pos = j; token = new Token(src.substring(i, j)); } } } **/ private boolean isMetaChar(char c){ return ((c == CAT_START_CHAR) || (c == CAT_END_CHAR) || (c == ALT_START_CHAR) || (c == ALT_END_CHAR) || (c == ALT_CHAR)); } void nextToken() { int i = pos; int len = this.len; if (i>=len){ token = EOS; } else { char c = src.charAt(i); switch (c){ case CAT_START_CHAR: token = CAT_START; pos++; break; case CAT_END_CHAR: token = CAT_END; pos++; break; case ALT_START_CHAR: token = ALT_START; pos++; break; case ALT_CHAR: token = ALT; pos++; break; case ALT_END_CHAR: token = ALT_END; pos++; break; default: int j = i + 1; for (; j < len && !isMetaChar(src.charAt(j)); j++); pos = j; token = new Token(src.substring(i, j)); } } } boolean match (Symbol sym){ if (token == sym){ nextToken(); return true; } else { return false; } } public StringExpander (String src){ this.src = src; this.len = src.length(); this.pos = 0; } List<String> addSeq (List<String> list, List<String> seq){ List<String> result = new LinkedList<String>(); if (list != null && list.size() > 0){ result.addAll(list); } result.addAll(seq); return result; } List<String> addLiteral (List<String> list, String s){ List<String> result = new LinkedList<String>(); if (list == null || list.size() == 0){ result.add(s); } else { for (String e : list) { result.add(e + s); } } return result; } List<String> addAlt (List<String> list, List<String>alt){ List<String> result = new LinkedList<String>(); if (list == null || list.size() == 0){ result.addAll(alt); } else { for (String e : list) { for (String p : alt) { result.add(e + p); } } } return result; } List<String> addCat (List<String> list, char[] cat){ List<String> result = new LinkedList<String>(); if (list == null || list.size() == 0){ for (char c : cat){ result.add(Character.toString(c)); } } else { for (String e : list) { for (char c : cat){ result.add(e + c); } } } return result; } void error (String msg){ throw new Exception(msg); } protected char[] createCategory(String cat){ char[] s = cat.toCharArray(); int l1 = s.length-1; char[] d = s; for (int i=0, j=0; i<s.length; i++){ char c = s[i]; if ((c == CAT_CHAR) && (i>0) && (i<l1)){ char c0 = s[i-1]; char c1 = s[i+1]; int n = c1 - c0; int len = j + n + (s.length-i-2); char[] dNew = new char[len]; System.arraycopy(d, 0, dNew, 0, j); d = dNew; for (int k=c0+1; k<=c1; k++){ d[j++] = (char)k; } i++; } else { d[j++] = c; } } return d; } // seq := {LIT | cat | alt}* // cat := `[ LIT `] // alt := `< spec {`| spec}* `> public List<String> expand() { return seq(); } List<String> seq() { List<String> result = null; for (nextToken(); token != EOS; ){ if (!token.isSymbol()){ result = addLiteral( result,token.value); nextToken(); } else if (token == ALT_START){ result = addAlt( result, alt()); } else if (token == CAT_START){ result = addCat( result, cat()); } else { break; } } return result; } List<String> alt() { List<String> result = null; assert token == ALT_START; do { result = addSeq(result, seq()); } while (token == ALT); if (!match(ALT_END)){ error("unterminated alternative"); } return result; } char[] cat() { char[] set = null; assert token == CAT_START; nextToken(); if (!token.isSymbol()){ set = createCategory(token.value); nextToken(); } if (!match(CAT_END)){ error("unterminated category"); } return set; } public static void main (String[] args) { //String a = "<B[0-3]C>"; String a = args[0]; System.out.println(a); StringExpander ex = new StringExpander(a); /** for (ex.nextToken(); ex.token != EOS; ex.nextToken()){ System.out.println(ex.token); } **/ /**/ for (String s : ex.expand()) { System.out.println(s); } /**/ /** System.out.println(new String(ex.createCategory(args[0]))); **/ } }