/**
* <copyright>
*
* Copyright (c) 2002-2007 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM - Initial API and implementation
*
* </copyright>
*
* $Id: RoseParser.java,v 1.6 2008/12/22 14:26:15 emerks Exp $
*/
package com.sap.emf.importer.moin.rose.parser;
import java.util.List;
import java.util.Stack;
/**
* A parser for Rose files.
* This parser uses the following contex-free grammar:
* <pre>
* E -> ( O ) | ( L ) | ( V ) | S' ;expression
* S' -> S | "|" S' ;sequence of strings
* S" -> EPS | S' S" ;sequence of strings inside list
* O -> object S P' ;object
* V -> value S S' ;value
* P' -> EPS | P P' ;sequence of pairs
* P -> K E ;pair
* L -> list S O' | list S S" ;list
* O' -> EPS | ( O ) O' ;sequence of objects
* </pre>
* Here are the terminals:
* <pre>
* K is a key token (always one word)
* S is a string token (can have multiple words)
* object is an object token
* list is a list token
* "|" is a vertical bar token
* EPS is an empty string token
* </pre>
*/
public class RoseParser
{
protected RoseLexer lexer;
protected RoseNode versionTree;
protected RoseNode modelTree;
protected String baseId = "";
protected Stack<Integer> idStack = new Stack<Integer>();
protected boolean isTreeOnly = false;
protected boolean isAllowed = true;
protected boolean isRoot = true;
protected boolean isListMapping = true;
protected boolean noLogicalPresentation = false;
protected boolean mapProperties = true; // map properties even when isTreeOnly == true
public RoseParser(RoseLexer lexer)
{
this(lexer, false, false);
}
public RoseParser(RoseLexer lexer, boolean isTreeOnly)
{
this(lexer, isTreeOnly, false);
}
public RoseParser(RoseLexer lexer, boolean isTreeOnly, boolean noPresentation)
{
this.lexer = lexer;
this.isTreeOnly = isTreeOnly;
this.noLogicalPresentation = noPresentation;
}
public RoseNode getVersionTree()
{
return versionTree;
}
public RoseNode getModelTree()
{
return modelTree;
}
public void parse()
{
baseId = null;
idStack.push(0);
versionTree = parseExpr("");
idStack.push(0);
baseId = null;
modelTree = parseExpr("");
}
public void traverseTree(List<Integer> path)
{
RoseNode node = modelTree;
if (node == null)
{
return;
}
for (int i = 0; i < path.size(); i++)
{
if (node.getRoseNodeType() == RoseNode.STRING)
{
return;
}
List<RoseNode> nodes = node.getNodes();
Integer integ = path.get(i);
int j = integ;
if (j < 1 || j > nodes.size())
break;
node = nodes.get(j - 1);
}
String id = node.getId();
String atId = node.getAtId();
if (id == null)
{
id = "";
}
if (atId == null)
{
atId = "";
}
String t1 = "";
if (node.getRoseNodeType() == RoseNode.STRING)
{
t1 = "(STRING)";
}
else if (node.getRoseNodeType() == RoseNode.LIST)
{
t1 = "(LIST)";
}
else if (node.getRoseNodeType() == RoseNode.OBJECT)
{
t1 = "(OBJECT)";
}
else if (node.getRoseNodeType() == RoseNode.STRING_SEQ)
{
t1 = "(STRING_SEQ)";
}
else if (node.getRoseNodeType() == RoseNode.VALUE)
{
t1 = "(VALUE)";
}
System.out.println(t1 + "\t" + node.getKey() + " --- " + node.getValue() + " - " + id + " - " + atId);
List<RoseNode> nodes = node.getNodes();
int count = 1;
for (int i = 0; i < nodes.size(); i++)
{
RoseNode n = nodes.get(i);
String t = "";
if (n.getRoseNodeType() == RoseNode.STRING)
{
t = "(STRING)";
}
else if (n.getRoseNodeType() == RoseNode.LIST)
{
t = "(LIST)";
}
else if (n.getRoseNodeType() == RoseNode.OBJECT)
{
t = "(OBJECT)";
}
else if (n.getRoseNodeType() == RoseNode.STRING_SEQ)
{
t = "(STRING_SEQ)";
}
else if (n.getRoseNodeType() == RoseNode.VALUE)
{
t = "(VALUE)";
}
System.out.println(count + " " + t + "\t" + n.getKey() + " --- " + n.getValue());
count++;
}
}
private RoseNode parseObject(String key)
{
Integer topInt = idStack.pop();
int top = topInt;
idStack.push(++top);
idStack.push(0);
if (baseId == null)
{
baseId = "id";
}
else
{
baseId += ".";
baseId += topInt.toString();
}
RoseToken tok = lexer.getNext();
if (tok.getType() != RoseToken.OBJECT)
{
System.out.println(" Parsing error in parseObject - expecting object token");
return null;
}
tok = lexer.getNext();
if (tok.getType() != RoseToken.STRING)
{
System.out.println(" Parsing error in parseObject - expecting string");
return null;
}
String label = tok.getValue();
RoseNode root = null;
if (isTreeOnly)
{
if (key.equals("root_usecase_package") || key.equals("root_subsystem") || !mapProperties && key.equals("properties")
&& label.equals("Properties"))
{
isListMapping = false;
}
else if (key.equals("root_category") || key.equals("process_structure") && label.equals("Processes"))
{
isListMapping = true;
}
}
root = new RoseNode(key, label, RoseNode.OBJECT);
root.setId(baseId);
while (true)
{
tok = lexer.peekNext();
if (tok.getType() == RoseToken.RIGHT_PAREN)
break;
else
tok = lexer.getNext();
if (tok.getType() != RoseToken.KEY)
{
System.out.println(" Parsing error in parseObject - expecting key " + tok.lineNum);
return null;
}
String pairKey = tok.getValue();
RoseNode node = parseExpr(pairKey);
if (isTreeOnly)
{
if (node != null)
{
root.addNode(node);
}
}
else
{
if (node == null)
{
return null;
}
root.addNode(node);
}
}
idStack.pop();
if (baseId.lastIndexOf('.') > 0)
{
baseId = baseId.substring(0, baseId.lastIndexOf('.'));
}
return root;
}
private RoseNode parseValue(String key)
{
Integer topInt = idStack.pop();
int top = topInt;
// top++;
idStack.push(++top);
idStack.push(0);
if (baseId == null)
{
baseId = "id";
}
else
{
baseId += ".";
baseId += topInt.toString();
}
RoseToken tok = lexer.getNext();
if (tok.getType() != RoseToken.VALUE)
{
System.out.println(" Parsing error in parseValue - expecting value token");
return null;
}
tok = lexer.getNext();
if (tok.getType() != RoseToken.STRING)
{
System.out.println(" Parsing error in parseValue - expecting string");
return null;
}
String label = tok.getValue();
RoseNode root = null;
root = new RoseNode(key, label, RoseNode.VALUE);
root.setId(baseId);
RoseNode node = parseS_prime("");
if (isTreeOnly)
{
if (node != null)
{
root.addNode(node);
}
}
else
{
if (node == null)
{
return null;
}
root.addNode(node);
}
idStack.pop();
if (baseId.lastIndexOf('.') > 0)
{
baseId = baseId.substring(0, baseId.lastIndexOf('.'));
}
return root;
}
private RoseNode parseExpr(String key)
{
RoseToken tok = lexer.peekNext();
if (tok.getType() == RoseToken.LEFT_PAREN)
{
tok = lexer.getNext();
RoseNode root;
tok = lexer.peekNext();
if (tok.getType() == RoseToken.OBJECT)
{
root = parseObject(key);
if (!isTreeOnly)
{
if (root == null)
return null;
}
}
else if (tok.getType() == RoseToken.VALUE)
{
root = parseValue(key);
if (!isTreeOnly)
{
if (root == null)
{
return null;
}
}
}
else if (tok.getType() == RoseToken.LIST)
{
root = parseList(key);
if (!isTreeOnly)
{
if (root == null)
return null;
}
}
else
{
System.out.println(" Parsing error in parseExpr - expecting object or list");
return null;
}
tok = lexer.getNext();
if (tok.getType() != RoseToken.RIGHT_PAREN)
{
System.out.println(" Parsing error in parseExpr - expecting right parenthesis");
return null;
}
return root;
}
else
{
return parseS_prime(key);
}
}
private RoseNode parseS_prime(String key)
{
RoseToken tok = lexer.peekNext();
if (tok.getType() == RoseToken.STRING)
{
tok = lexer.getNext();
RoseNode root = null;
root = new RoseNode(key, tok.getValue(), RoseNode.STRING);
return root;
}
else if (tok.getType() == RoseToken.VERTICAL_BAR)
{
RoseNode root = null;
root = new RoseNode(key, "", RoseNode.STRING_SEQ);
while (true)
{
tok = lexer.peekNext();
if (tok.getType() == RoseToken.VERTICAL_BAR)
{
tok = lexer.getNext();
}
else
{
break;
}
tok = lexer.getNext();
if (tok.getType() != RoseToken.STRING)
{
System.out.println(" Parsing error in parseS_prime - expecting string");
return null;
}
RoseNode node = null;
node = new RoseNode("", tok.getValue(), RoseNode.STRING);
if (root != null)
{
root.addNode(node);
}
}
return root;
}
else
{
lexer.printNeighbors();
System.out.println(" Parsing error in parseS_prime - expecting string or | " + tok.lineNum);
return null;
}
}
private RoseNode parseList(String key)
{
boolean wasAllowed = isAllowed;
if (noLogicalPresentation)
{
if (key.equals("logical_presentations"))
{
isAllowed = false;
}
else
{
isAllowed = true;
}
}
else
{
isAllowed = true;
}
if (!isListMapping)
{
isAllowed = false;
}
RoseNode root = null;
RoseToken tok;
tok = lexer.getNext();
if (tok.getType() != RoseToken.LIST)
{
System.out.println(" Parsing error in parseList - expecting list token");
return null;
}
tok = lexer.getNext();
if (tok.getType() != RoseToken.STRING)
{
System.out.println(" Parsing error in parseList - expecting string");
return null;
}
String label = tok.getValue();
tok = lexer.peekNext();
if (tok.getType() == RoseToken.LEFT_PAREN)
{
if (!isTreeOnly || isAllowed)
{
root = new RoseNode(key, label, RoseNode.LIST);
}
while (true)
{
tok = lexer.getNext();
if (tok.getType() != RoseToken.LEFT_PAREN)
{
System.out.println(" Parsing error in parseList - expecting left parenthesis");
return null;
}
RoseNode node = parseObject("");
if (isTreeOnly)
{
if (root != null && node != null)
{
root.addNode(node);
}
}
else if (root != null)
{
if (node == null)
{
return null;
}
root.addNode(node);
}
tok = lexer.getNext();
if (tok.getType() != RoseToken.RIGHT_PAREN)
{
System.out.println(" Parsing error in parseList - expecting right parenthesis");
return null;
}
tok = lexer.peekNext();
if (tok.getType() == RoseToken.RIGHT_PAREN)
{
break;
}
}
}
else if (tok.getType() == RoseToken.RIGHT_PAREN)
{
if (!isTreeOnly || isAllowed)
{
root = new RoseNode(key, label, RoseNode.LIST);
}
}
else if (tok.getType() == RoseToken.STRING || tok.getType() == RoseToken.VERTICAL_BAR)
{
if (!isTreeOnly || isAllowed)
{
root = new RoseNode(key, label, RoseNode.LIST);
}
while (true)
{
tok = lexer.peekNext();
if (tok.getType() != RoseToken.STRING && tok.getType() != RoseToken.VERTICAL_BAR)
{
System.out.println(" Parsing error in parseList - expecting string or |");
return null;
}
RoseNode node = null;
node = parseS_prime("");
if (root != null)
{
root.addNode(node);
}
tok = lexer.peekNext();
if (tok.getType() == RoseToken.RIGHT_PAREN)
{
break;
}
}
}
else
{
lexer.getNext();
System.out.println(" Parsing error in parseList - expecting left/right parenthesis or string or | " + tok.lineNum);
}
isAllowed = wasAllowed;
return root;
}
}