/* * xtc - The eXTensible Compiler * Copyright (C) 2009-2011 New York University * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * version 2.1 as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, * USA. */ package xtc.lang.cpp; import xtc.tree.Node; import xtc.tree.GNode; import xtc.tree.Location; import xtc.util.Pair; import xtc.util.Runtime; import xtc.lang.cpp.Syntax.Kind; import xtc.lang.cpp.Syntax.LanguageTag; import xtc.lang.cpp.Syntax.ConditionalTag; import xtc.lang.cpp.Syntax.DirectiveTag; import xtc.lang.cpp.Syntax.Layout; import xtc.lang.cpp.Syntax.Language; import xtc.lang.cpp.Syntax.Text; import xtc.lang.cpp.Syntax.Directive; import xtc.lang.cpp.Syntax.Conditional; import xtc.lang.cpp.ContextManager.Context; import xtc.lang.cpp.ForkMergeParser.StateStack; import xtc.lang.cpp.ForkMergeParser.Subparser; /** * This class implements the generated CActionsBase class. * * @author Paul Gazzillo * @version $Revision: 1.13 $ */ public class CActions extends CActionsBase { /** The initial parsing context. */ CParsingContext initialParsingContext; /** The xtc runtime. */ Runtime runtime; /** Whether to display language statistics. */ boolean languageStatistics; public CActions(Runtime runtime) { this.runtime = runtime; this.initialParsingContext = new CParsingContext(runtime); languageStatistics = runtime.test("statisticsLanguage"); } public boolean hasContext() { return true; } public Actions.Context getInitialContext() { return initialParsingContext; } public Object getValue(int id, String name, Pair<Object> values) { Object value; if (values == Pair.<Object>empty()) { value = null; } else { value = GNode.createFromPair(name, values.head(), values.tail()); } if (languageStatistics) { if (name.equals("Statement") || name.equals("Declaration") || name.equals("ExternalDeclaration")) { // Get the location of the production. Location location = getProductionLocation(value); // Emit the marker. runtime.errConsole().pln(String.format("c_construct %s %s", name, location)).flush(); } } return value; } /** * Get location of a production given its value. * * @param value The value of the production. * @return The location. */ private static Location getProductionLocation(Object value) { if (value instanceof Node) { for (Object o : (Node) value) { Location location = getProductionLocation(o); if (null != location) { return location; } } return ((Node) value).getLocation(); } else { return null; } } public void BindIdentifier(Subparser subparser) { StateStack stack = subparser.s; ContextManager.Context context = subparser.getContext(); CParsingContext scope = (CParsingContext) subparser.scope; boolean typedef; Language ident; //get nodes containing the type and the declarator Object a = stack.get(3).value; Object b = stack.get(2).value; Language t; /** Assume the typedef keyword is the first token of a typedef */ while (true) { if (a instanceof Node && ! (a instanceof Syntax)) { Node n = (Node) a; if (n.hasName(ForkMergeParser.CHOICE_NODE_NAME)) { // When it's a conditional node, the first child is a // presence condition, the second is the first AST child. a = n.get(1); } else { a = n.get(0); } } else if (a instanceof Pair) { a = ((Pair) a).head(); } else { break; } } t = (Language) a; ident = getident(b); if (CTag.TYPEDEF == t.tag()) { typedef = true; if (languageStatistics) { if (typedef) { String location = null; //TODO pass location to this function runtime.errConsole().pln(String.format("typedef %s %s", ident, location)).flush(); } } } else { typedef = false; // TODO statistics collect bind var name } scope.bind(ident.getTokenText(), typedef, context); } public void BindIdentifierInList(Subparser subparser) { StateStack stack = subparser.s; ContextManager.Context context = subparser.getContext(); CParsingContext scope = (CParsingContext) subparser.scope; boolean typedef; Language ident; //get nodes containing the type and the declarator Object a = stack.get(5).value; Object b = stack.get(2).value; Language t; while (true) { if (a instanceof Node && ! (a instanceof Syntax)) { Node n = (Node) a; if (n.hasName(ForkMergeParser.CHOICE_NODE_NAME)) { // When it's a conditional node, the first child is a // presence condition, the second is the first AST child. a = n.get(1); } else { a = n.get(0); } } else if (a instanceof Pair) { a = ((Pair) a).head(); } else { break; } } t = (Language) a; if (CTag.TYPEDEF == t.tag()) { typedef = true; // TODO statistics collect bind typedef } else { typedef = false; // TODO statistics collect bind var name } ident = getident(b); scope.bind(ident.getTokenText(), typedef, context); } public void BindVar(Subparser subparser) { StateStack stack = subparser.s; ContextManager.Context context = subparser.getContext(); CParsingContext scope = (CParsingContext) subparser.scope; Language ident; Object b = stack.get(2).value; ident = getident(b); scope.bind(ident.getTokenText(), false, context); // TODO statistics collect bind var name } public void BindEnum(Subparser subparser) { StateStack stack = subparser.s; ContextManager.Context context = subparser.getContext(); CParsingContext scope = (CParsingContext) subparser.scope; String ident; //must occur after an identifier.or.typedef.name token Object b = stack.get(2).value; ident = getident(b).getTokenText(); scope.bind(ident, false, context); // TODO statistics collect bind var name } public void EnterScope(Subparser subparser) { ContextManager.Context context = subparser.getContext(); subparser.scope = ((CParsingContext) subparser.scope).enterScope(context); } public void ExitScope(Subparser subparser) { ContextManager.Context context = subparser.getContext(); subparser.scope = ((CParsingContext) subparser.scope).exitScope(context); } public void ExitReentrantScope(Subparser subparser) { ContextManager.Context context = subparser.getContext(); subparser.scope = ((CParsingContext) subparser.scope).exitReentrantScope(context); } public void ReenterScope(Subparser subparser) { ContextManager.Context context = subparser.getContext(); subparser.scope = ((CParsingContext) subparser.scope).reenterScope(context); } public void KillReentrantScope(Subparser subparser) { ContextManager.Context context = subparser.getContext(); subparser.scope = ((CParsingContext) subparser.scope).killReentrantScope(context); } /** * Find the identifier or typedef name in a declarator. Assume * the first identifier in the subtree is the var or typedef name. * * @param o The semantic value. * @return The first identifier in the subtree or null if there is * none. */ private static Language getident(Object o) { if (o instanceof Language) { Language token = ((Language) o); if (CTag.IDENTIFIER == token.tag() || CTag.TYPEDEFname == token.tag()) { return token; } else { return null; } } else if (o instanceof Pair) { Pair<?> b = (Pair<?>) o; while (b != Pair.empty()) { Object child = b.head(); if (null != child) { Language ident = getident(child); if (null != ident) { return ident; } } b = b.tail(); } return null; } else if (o instanceof ContextManager.Context) { return null; } else { Node b = (Node) o; for (int i = 0; i < b.size(); i++) { Object child = b.get(i); if (null != child) { Language ident = getident(child); if (null != ident) { return ident; } } } return null; } } }