From 6f2a5f3c57c9470ce95cd86e7315daa33c9f8b81 Mon Sep 17 00:00:00 2001 From: parrt Date: Tue, 9 Feb 2010 18:21:56 -0800 Subject: [PATCH] got initial scope parser copied from v3 [git-p4: depot-paths = "//depot/code/antlr4/main/": change = 6679] --- tool/src/org/antlr/v4/parse/ScopeParser.java | 242 ++++++++++++++++++ tool/src/org/antlr/v4/tool/Attribute.java | 32 +++ .../src/org/antlr/v4/tool/AttributeScope.java | 39 +++ 3 files changed, 313 insertions(+) create mode 100644 tool/src/org/antlr/v4/parse/ScopeParser.java create mode 100644 tool/src/org/antlr/v4/tool/Attribute.java create mode 100644 tool/src/org/antlr/v4/tool/AttributeScope.java diff --git a/tool/src/org/antlr/v4/parse/ScopeParser.java b/tool/src/org/antlr/v4/parse/ScopeParser.java new file mode 100644 index 000000000..14c05e087 --- /dev/null +++ b/tool/src/org/antlr/v4/parse/ScopeParser.java @@ -0,0 +1,242 @@ +package org.antlr.v4.parse; + +import org.antlr.tool.ErrorManager; +import org.antlr.v4.tool.Attribute; +import org.antlr.v4.tool.AttributeScope; + +import java.util.ArrayList; +import java.util.List; + +/** Parse args, return values, and dynamic scopes. + * + * rule[arg1, arg2, ..., argN] returns [ret1, ..., retN] + * scope { decl1; decl2; ... declN; } + * + * The ',' and ';' are significant. Use \, and \; to use within + * types if necessary like [Map foo, int y]. + * + * arg, ret, and decl are target language dependent. Java/C#/C/C++ would + * use "int i" but ruby/python would use "i". + */ +public class ScopeParser { + public static void main(String[] args) { + System.out.println(parseTypeList("int i")); + System.out.println(parseTypeList("int[] i, int j[]")); + System.out.println(parseTypeList("Map[] i, int j[]")); + System.out.println(parseTypeList("int i = 34+a[3], int j[] = new int[34]")); + System.out.println(parseTypeList("char *foo32[3] = {1\\,2\\,3}")); + System.out.println(); + System.out.println(parseDynamicScope("int i;")); + System.out.println(parseDynamicScope("int[] i; int j[];")); + System.out.println(parseDynamicScope("Map[] i; int j[];")); + System.out.println(parseDynamicScope("int i = 34+a[3]; int j[] = new int[34];")); + System.out.println(parseDynamicScope("char *foo32[] = {1,2,3};")); + } + + /** Given an arg or retval scope definition list like + * + * Map, int[] j3, char *foo32[3] + * + * or + * + * int i=3, j=a[34]+20 + * + * convert to an attribute scope. + */ + public static AttributeScope parseTypeList(String s) { return parse(s, ','); } + + public static AttributeScope parseDynamicScope(String s) { return parse(s, ';'); } + + public static AttributeScope parse(String s, char separator) { + int i = 0; + int n = s.length(); + AttributeScope scope = new AttributeScope(); + while ( i0 ) { + // everything after the '=' is the init value + attr.initValue = decl.substring(equalsIndex+1,decl.length()); + rightEdgeOfDeclarator = equalsIndex-1; + } + // walk backwards looking for start of an ID + for (int i=rightEdgeOfDeclarator; i>=0; i--) { + // if we haven't found the end yet, keep going + if ( !inID && Character.isLetterOrDigit(decl.charAt(i)) ) { + inID = true; + } + else if ( inID && + !(Character.isLetterOrDigit(decl.charAt(i))|| + decl.charAt(i)=='_') ) { + start = i+1; + break; + } + } + if ( start<0 && inID ) { + start = 0; + } + if ( start<0 ) { + ErrorManager.error(ErrorManager.MSG_CANNOT_FIND_ATTRIBUTE_NAME_IN_DECL,decl); + } + // walk forwards looking for end of an ID + int stop=-1; + for (int i=start; i<=rightEdgeOfDeclarator; i++) { + // if we haven't found the end yet, keep going + if ( !(Character.isLetterOrDigit(decl.charAt(i))|| + decl.charAt(i)=='_') ) + { + stop = i; + break; + } + if ( i==rightEdgeOfDeclarator ) { + stop = i+1; + } + } + + // the name is the last ID + attr.name = decl.substring(start,stop); + + // the type is the decl minus the ID (could be empty) + attr.type = decl.substring(0,start); + if ( stop<=rightEdgeOfDeclarator ) { + attr.type += decl.substring(stop,rightEdgeOfDeclarator+1); + } + attr.type = attr.type.trim(); + if ( attr.type.length()==0 ) { + attr.type = null; + } + + attr.decl = decl; + return attr; + } + + /** Given an argument list like + * + * x, (*a).foo(21,33), 3.2+1, '\n', + * "a,oo\nick", {bl, "fdkj"eck}, ["cat\n,", x, 43] + * + * convert to a list of attributes. Allow nested square brackets etc... + * Set separatorChar to ';' or ',' or whatever you want. + */ + public static List splitArgumentList(String s, int separatorChar) { + List args = new ArrayList(); + _splitArgumentList(s, 0, -1, separatorChar, args); + return args; + } + + + public static int _splitArgumentList(String actionText, + int start, + int targetChar, + int separatorChar, + List args) + { + if ( actionText==null ) { + return -1; + } + actionText = actionText.replaceAll("//.*\n", ""); + int n = actionText.length(); + //System.out.println("actionText@"+start+"->"+(char)targetChar+"="+actionText.substring(start,n)); + int p = start; + int last = p; + while ( p',p+1)>=p ) { + // do we see a matching '>' ahead? if so, hope it's a generic + // and not less followed by expr with greater than + p = _splitArgumentList(actionText,p+1,'>',separatorChar,args); + } + else { + p++; // treat as normal char + } + break; + case '[' : + p = _splitArgumentList(actionText,p+1,']',separatorChar,args); + break; + default : + if ( c==separatorChar && targetChar==-1 ) { + String arg = actionText.substring(last, p); + //System.out.println("arg="+arg); + args.add(arg.trim()); + last = p+1; + } + p++; + break; + } + } + if ( targetChar==-1 && p<=n ) { + String arg = actionText.substring(last, p).trim(); + //System.out.println("arg="+arg); + if ( arg.length()>0 ) { + args.add(arg.trim()); + } + } + p++; + return p; + } + +} diff --git a/tool/src/org/antlr/v4/tool/Attribute.java b/tool/src/org/antlr/v4/tool/Attribute.java new file mode 100644 index 000000000..51884c326 --- /dev/null +++ b/tool/src/org/antlr/v4/tool/Attribute.java @@ -0,0 +1,32 @@ +package org.antlr.v4.tool; + +/** Track the names of attributes define in arg lists, return values, + * scope blocks etc... + */ +public class Attribute { + /** The entire declaration such as "String foo;" */ + public String decl; + + /** The type; might be empty such as for Python which has no static typing */ + public String type; + + /** The name of the attribute "foo" */ + public String name; + + /** The optional attribute intialization expression */ + public String initValue; + + public Attribute() {;} + + public Attribute(String name, String decl) { + this.name = name; + this.decl = decl; + } + + public String toString() { + if ( initValue!=null ) { + return type+" "+name+"="+initValue; + } + return type+" "+name; + } +} \ No newline at end of file diff --git a/tool/src/org/antlr/v4/tool/AttributeScope.java b/tool/src/org/antlr/v4/tool/AttributeScope.java new file mode 100644 index 000000000..fa110a138 --- /dev/null +++ b/tool/src/org/antlr/v4/tool/AttributeScope.java @@ -0,0 +1,39 @@ +package org.antlr.v4.tool; + +import java.util.LinkedHashMap; + +/** Track the attributes within a scope. A named scoped has just its list + * of attributes. Each rule has potentially 3 scopes: return values, + * parameters, and an implicitly-named scope (i.e., a scope defined in a rule). + * Implicitly-defined scopes are named after the rule; rules and scopes then + * must live in the same name space--no collisions allowed. + */ +public class AttributeScope { + /** The scope name */ + private String name; + + public static enum Type { + ARG, RET, TOKEN, PREDEFINED_RULE, PREDEFINED_LEXER_RULE, + GLOBAL_SCOPE, // scope symbols { ...} + RULE_SCOPE; // scope { int i; int j; } + } + + /** The list of Attribute objects */ + + public LinkedHashMap attributes = + new LinkedHashMap(); + + public String getName() { +// if ( isParameterScope ) { +// return name+"_parameter"; +// } +// else if ( isReturnScope ) { +// return name+"_return"; +// } + return name; + } + + public String toString() { + return getName()+":"+attributes; + } +}