
cb.parser.Parser Maven / Gradle / Ivy
/**
* Copyright (c) 2001 Markus Dahm
* Copyright (C) 2015-2018 BITPlan GmbH http://www.bitplan.com
*
* This source is part of
* https://github.com/BITPlan/CrazyBeans
* and the license as outlined there applies
*/
package cb.parser;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.Stack;
import cb.petal.Design;
import cb.petal.Petal;
import cb.petal.PetalFile;
import cb.petal.PetalNode;
import cb.petal.PetalNodeList;
import cb.petal.PetalObject;
import cb.petal.StringLiteral;
import cb.petal.Value;
/**
* parser
*
* @author wf
*
*/
public class Parser {
private Lexer lexer;
private PetalNode current_parent = null;
private Stack parent_stack = new Stack();
private void saveParent(PetalNode new_parent) {
parent_stack.push(current_parent);
current_parent = new_parent;
}
private void restoreParent() {
current_parent = (PetalNode) parent_stack.pop();
}
private static ObjectFactory factory = ObjectFactory.getInstance();
public Parser(Reader r) {
lexer = new Lexer(r);
}
private List ignored_nodes = new ArrayList();
/**
* If the parser finds such a node while building the petal tree, the node
* will be ignored and not added to the tree. E.g,
* setIgnoredNodes(Diagram.class) will abandon all diagrams of the model.
*/
public void setIgnoredNodes(java.lang.Class[] nodes) {
ignored_nodes = new ArrayList(Arrays.asList(nodes));
}
public java.lang.Class[] getIgnoredNodes() {
java.lang.Class[] nodes = new java.lang.Class[ignored_nodes.size()];
ignored_nodes.toArray(nodes);
return nodes;
}
private boolean ignored(PetalNode obj) {
for (Iterator i = ignored_nodes.iterator(); i.hasNext();) {
java.lang.Class clazz = (java.lang.Class) i.next();
if (clazz.isInstance(obj)) {
return true;
}
}
return false;
}
private Token match(int kind, String match) {
Token t = lexer.getToken();
if (t.kind != kind)
throw new RuntimeException("Mismatch: Expected " + kind + " but got "
+ t.kind + " at line " + t.line);
if ((match != null) && !match.equals(t.image))
throw new RuntimeException("Mismatch: Expected " + match + " but got "
+ t.image + " at line " + t.line);
return t;
}
private Token match(int kind) {
return match(kind, null);
}
private ArrayList list = new ArrayList(); // Reused list to collect docs
/**
* (...)* wildcard
*
* @return images
*/
private ArrayList matchAll(int kind) {
list.clear();
Token t = lexer.getToken();
while (t.kind == kind) {
list.add(t.image);
t = lexer.getToken();
}
lexer.ungetToken(t);
return list;
}
/**
* [...] optional
*
* @return image
*/
private Token matchAny(int kind) {
Token t = lexer.getToken();
if (t.kind == kind)
return t;
else {
lexer.ungetToken(t);
return null;
}
}
public static PetalFile parse(String file_name) {
return parse(new File(file_name));
}
public static PetalFile parse(java.net.URL url) {
try {
return parse(url.openStream());
} catch (IOException e) {
throw new RuntimeException(e.toString());
}
}
public static PetalFile parse(File file) {
try {
PetalFile tree = parse(new FileReader(file));
String name = file.getName();
int index = name.lastIndexOf('.');
if (index > 0)
name = name.substring(0, index);
tree.setModelName(name);
return tree;
} catch (IOException e) {
throw new RuntimeException(e.toString());
}
}
public static PetalFile parse(Reader stream) {
return new Parser(stream).parse();
}
public static PetalFile parse(InputStream stream) {
return parse(new InputStreamReader(stream));
}
/**
* Top level construct are always petal and design objects
*/
public PetalFile parse() {
PetalObject petal, design;
PetalFile file = new PetalFile();
current_parent = file;
petal = parseObject();
design = parseObject();
file.setPetal((Petal) petal);
file.setDesign((Design) design);
return file;
}
/*
* Example: (object ClassView "Class" "Use Case View::Student" @76 location
* (160, 176))
*/
public PetalObject parseObject() {
match(Lexer.LPAREN);
match(Lexer.IDENT, "object");
Token t1 = match(Lexer.IDENT);
ArrayList docs = matchAll(Lexer.STRING);
Token t3 = matchAny(Lexer.TAG);
PetalNode parent = ignored(current_parent) ? null : current_parent;
PetalObject obj = factory.createObject(parent, t1.image, docs,
t3 == null ? null : t3.image);
saveParent(obj);
/*
* List of properties
*/
Token t4 = matchAny(Lexer.IDENT);
while (t4 != null) {
PetalNode prop = parseValue(false);
if (prop != null)
obj.addProperty(t4.image, prop);
t4 = matchAny(Lexer.IDENT);
}
match(Lexer.RPAREN);
restoreParent();
if (!ignored(obj)) {
obj.init();
return obj;
} else
return null;
}
public PetalNode parseValue(boolean rparen_ok) {
Token t = lexer.getToken();
switch (t.kind) {
case Lexer.STRING:
return factory.createString(t.image, false);
case Lexer.MULTI_STRING:
return factory.createString(t.image, true);
case Lexer.INTEGER:
return factory.createInteger(t.image);
case Lexer.FLOAT:
return factory.createFloat(t.image);
case Lexer.BOOLEAN:
return factory.createBoolean(t.image);
case Lexer.TAG:
return factory.createTag(t.image);
case Lexer.LPAREN:
Token t2 = lexer.getToken();
switch (t2.kind) {
case Lexer.IDENT:
lexer.ungetToken(t2);
lexer.ungetToken(t);
if (t2.image.equals("object")) {
return parseObject();
} else if (t2.image.equals("list")) {
return parseList();
} else if (t2.image.equals("value")) {
return parseValueObject();
} else
throw new RuntimeException("Unexpected " + t2.image + " after (");
case Lexer.INTEGER:
match(Lexer.COMMA);
Token t3 = match(Lexer.INTEGER);
match(Lexer.RPAREN);
return factory.createLocation(t2.image, t3.image);
case Lexer.STRING:
Token t4 = match(Lexer.INTEGER);
match(Lexer.RPAREN);
return factory.createTuple(t2.image, t4.image);
default:
throw new RuntimeException("Unexpected " + t2.image + "after (");
}
default:
if ((t.kind == Lexer.RPAREN) && rparen_ok)
return null;
else
throw new RuntimeException("Unexpected " + t.image);
}
}
/*
* Example: (list unit_reference_list (object Module_Diagram "Main" quid
* "35CB163B03CF"))
*
*/
public PetalNodeList parseList() {
match(Lexer.LPAREN);
match(Lexer.IDENT, "list");
Token t = matchAny(Lexer.IDENT);
PetalNodeList list = factory.createList(t == null ? null : t.image);
PetalNode obj;
while ((obj = parseValue(true)) != null) // null == RPAREN
list.add(obj);
return list;
}
public Value parseValueObject() {
match(Lexer.LPAREN);
match(Lexer.IDENT, "value");
Token t = match(Lexer.IDENT);
Token t2 = lexer.getToken();
StringLiteral str;
switch (t2.kind) {
case Lexer.STRING:
str = factory.createString(t2.image, false);
break;
case Lexer.MULTI_STRING:
str = factory.createString(t2.image, true);
break;
default:
throw new RuntimeException("Unexpected " + t2.image + " in (value ...)");
}
match(Lexer.RPAREN);
return factory.createValue(t.image, str);
}
public static void main(String[] args) throws Exception {
FileReader r = new FileReader(args[0]);
Parser parser = new Parser(r);
parser.parse();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy