Exemple #1
0
        protected override void ExtractInfo()
        {
            // Extract keyword
            Keyword = Element.Name.LocalName;

            // Check syntax
            IEnumerable <XNode> textNodes = Element.Nodes()
                                            .Where(n => n.NodeType == XmlNodeType.Text);

            if (textNodes.Any())
            {
                string        text     = Element.Value.Trim().Ellipses(25);
                string        fmt      = Resources.SyntaxExceptionXmlUnexpectedText;
                XNode         textNode = textNodes.ElementAt(0);
                ISourceEntity src      = new XmlSourceEntity(textNode);
                throw LayoutScriptException.Create <SyntaxException>(null, src, fmt, text, Keyword);
            }

            // Extract parameters
            foreach (XAttribute attr in Element.Attributes())
            {
                SetParameter(attr.Name.LocalName, attr.Value);
            }

            // Parse nested statements
            foreach (XElement elem in Element.Elements())
            {
                AddNestedStatement(XmlStatement.Parse(elem));
            }
        }
Exemple #2
0
        private void InterpretStatement(Statement stmt)
        {
            StatementType   type = stmt.StatementType;
            InterpretAction interpret;
            string          msg;

            switch (type)
            {
            case StatementType.Directive:
                // Get action based on directive name.
                if (!directiveActionMap.TryGetValue(stmt.Keyword, out interpret))
                {
                    msg = "Unknown directive '{0}'.";
                    throw LayoutScriptException.Create <LayoutScriptException>(layout, stmt, msg, stmt.Keyword);
                }
                break;

            case StatementType.None:
                // Invalid state. Should never happen if the statement was parsed correctly...
                msg = "Invalid statement.";
                throw LayoutScriptException.Create <LayoutScriptException>(layout, stmt, msg);

            default:
                // Get action based on statement type
                if (!statementTypeActionMap.TryGetValue(type, out interpret))
                {
                    // Should never happen...
                    msg = string.Format("Bug! No action exists for statement type '{0}'!", type);
                    throw new InvalidOperationException(msg);
                }
                break;
            }

            interpret(stmt);
        }
Exemple #3
0
        private bool GetParameter(Statement stmt, string paramName, bool isRequired, out string value)
        {
            bool hasParam = stmt.Parameters.TryGetValue(paramName, out value);

            if (!hasParam && isRequired)
            {
                string msg = "Missing required parameter '{0}'";
                throw LayoutScriptException.Create <SyntaxException>(layout, stmt, msg, paramName);
            }

            return(hasParam);
        }
Exemple #4
0
        private void EnsureParameters(Statement stmt, params string[] paramNames)
        {
            List <string> unknownParams = stmt.Parameters
                                          .Select(x => x.Key)
                                          .Where(x => !paramNames.Contains(x))
                                          .ToList();

            if (unknownParams.Any())
            {
                string msg = "Unknown parameter '{0}'.";
                throw LayoutScriptException.Create <SyntaxException>(layout, stmt, msg, unknownParams[0]);
            }
        }
Exemple #5
0
        private void InterpretRootStatement(Statement stmt)
        {
            // Validate root element name
            if (stmt.Keyword != Keywords.XmlDocumentRoot)
            {
                string msg = Resources.SyntaxExceptionXmlInvalidRootElement;
                throw LayoutScriptException.Create <SyntaxException>(layout, stmt, msg, Keywords.XmlDocumentRoot);
            }

            // Interpret nested statements
            foreach (Statement childStmt in stmt.NestedStatements)
            {
                InterpretStatement(childStmt);
            }
        }
Exemple #6
0
        private void InterpretTypedef(Statement stmt)
        {
            EnsureParameters(stmt, Parameters.Comment, Parameters.Kind, Parameters.Name);

            GetRequiredParameter(stmt, Parameters.Kind, out string baseTypeName);
            GetRequiredParameter(stmt, Parameters.Name, out string newTypeName);

            if (!SymbolTable.IsIdentifierValid(newTypeName))
            {
                string msg = "Invalid identifier '{0}'. " +
                             "Identifiers must consist of only letters, numbers, and underscores. " +
                             "Identifiers cannot begin with a digit nor can they be identical to a reserved word.";
                throw LayoutScriptException.Create <LayoutScriptException>(layout, stmt, msg, newTypeName);
            }

            if (TryLookupType(newTypeName, out TypeInfo dummyType))
            {
                string msg = "Type '{0}' already exists.";
                throw LayoutScriptException.Create <LayoutScriptException>(layout, stmt, msg, newTypeName);
            }

            bool     isStruct = baseTypeName == Keywords.DataTypes.Struct;
            bool     isUnion  = baseTypeName == Keywords.DataTypes.Union;
            TypeInfo baseType;

            if (isStruct || isUnion)
            {
                baseType = CreateStructureType(stmt, isUnion);
            }
            else
            {
                bool exists = TryLookupType(baseTypeName, out baseType);
                if (!exists)
                {
                    string msg = "Unknown type '{0}'.";
                    throw LayoutScriptException.Create <LayoutScriptException>(layout, stmt, msg, baseTypeName);
                }
            }

            userDefinedTypes[newTypeName] = baseType;
        }
Exemple #7
0
        private void InterpretLocal(Statement stmt)
        {
            EnsureParameters(stmt, Parameters.Comment, Parameters.Name, Parameters.Value);

            GetRequiredParameter(stmt, Parameters.Name, out string varName);
            GetRequiredParameter(stmt, Parameters.Value, out string valueStr);

            if (CurrentCodeBlock.Symbol.Lookup(varName) != null)
            {
                string msg = "A variable with identifier '{0}' already exists in the current scope.";
                throw LayoutScriptException.Create <LayoutScriptException>(layout, stmt, msg, varName);
            }

            try {
                double value = EvaluateExpression(valueStr);
                CurrentCodeBlock.Locals[varName] = value;
            } catch (SyntaxErrorException e) {
                string msg = "'{0}' is not a valid expression.";
                throw LayoutScriptException.Create <LayoutScriptException>(layout, e, stmt, msg, valueStr);
            }
        }
Exemple #8
0
        private void InterpretInclude(Statement stmt)
        {
            EnsureParameters(stmt, Parameters.Path);

            GetRequiredParameter(stmt, Parameters.Path, out string path);

            // Path is relative to the current layout script's path.
            // If the current script was not loaded from a file, the path is
            // relative to the current program's directory.
            string fullPath;

            if (layout.SourcePath == null)
            {
                fullPath = Directory.GetCurrentDirectory() + "/" + path;
            }
            else
            {
                fullPath = Path.GetDirectoryName(layout.SourcePath) + "/" + path;
            }
            fullPath = Path.GetFullPath(fullPath);

            if (!File.Exists(fullPath))
            {
                string fmt = "File not found - {0}";
                throw LayoutScriptException.Create <LayoutScriptException>(layout, stmt, fmt, path);
            }

            LayoutScript incl = LayoutScript.Load(fullPath);

            if (includedLayouts.Contains(incl))
            {
                string msg = "Include cycle detected!";
                throw LayoutScriptException.Create <LayoutScriptException>(layout, stmt, msg);
            }

            includedLayouts.Add(incl);
            InterpretRootStatement(incl.RootStatement);
        }
Exemple #9
0
        private string EvaluateOperator(Operator op, string varName)
        {
            bool isSpecialVar = SpecialVariables.AllSpecialVariables.Contains(varName);
            bool isLocalVar   = TryLookupLocal(varName, out double localVarVal);

            // Handle special variables
            if (isSpecialVar)
            {
                if (op != Operator.ValueOf)
                {
                    Log(LogLevel.Warning, "Operator {0} cannot be used on special variable '{1}'.", op, varName);
                    return("");
                }

                switch (varName)
                {
                case SpecialVariables.Filesize:
                    return(file.Length + "");

                case SpecialVariables.GlobalOffset:
                    return(GlobalOffset + "");

                case SpecialVariables.Offset:
                    return(CurrentCodeBlock.Offset + "");
                }
            }

            // Handle local variables
            if (isLocalVar)
            {
                if (op != Operator.ValueOf)
                {
                    Log(LogLevel.Warning, "Operator {0} cannot be used on local variable '{1}'.", op, varName);
                    return("");
                }

                return(localVarVal + "");
            }

            bool isVar             = CurrentCodeBlock.Symbol.TryLookup(varName, out SymbolTable sym);
            bool isUserDefinedType = userDefinedTypes.TryGetValue(varName, out TypeInfo usrType);
            bool isBuiltinType     = BuiltInPrimitives.TryGetValue(varName, out TypeInfo builtinType);

            if (!(isVar || isUserDefinedType || isBuiltinType))
            {
                // TODO: get statement. Perhaps throw a different exception and have Caller of ResolveVariables catch and handle it
                string msg = "Unknown variable or typename '{0}'";
                throw LayoutScriptException.Create <LayoutScriptException>(layout, null, msg, varName);
            }

            string val = "";

            switch (op)
            {
            case Operator.GlobalOffsetOf:
                if (CurrentCodeBlock.IsProcessingTypedef)
                {
                    string msg = "GlobalOffsetOf operator not valid within type definitions.";
                    throw LayoutScriptException.Create <LayoutScriptException>(layout, null, msg, varName);
                }

                if (isVar)
                {
                    val = sym.GlobalDataAddress.ToString();
                }
                else
                {
                    string msg = "GlobalOffsetOf operator not valid for types.";
                    throw LayoutScriptException.Create <LayoutScriptException>(layout, null, msg, varName);
                }
                break;

            case Operator.OffsetOf:
                if (CurrentCodeBlock.IsProcessingTypedef)
                {
                    string msg = "OffsetOf operator not valid within type definitions.";
                    throw LayoutScriptException.Create <LayoutScriptException>(layout, null, msg, varName);
                }

                if (isVar)
                {
                    val = sym.LocalDataAddress.ToString();
                }
                else
                {
                    string msg = "OffsetOf operator not valid for types.";
                    throw LayoutScriptException.Create <LayoutScriptException>(layout, null, msg, varName);
                }
                break;

            case Operator.SizeOf:
                if (isVar)
                {
                    val = sym.DataLength.ToString();
                }
                else if (isBuiltinType)
                {
                    val = builtinType.Size.ToString();
                }
                else if (isUserDefinedType)
                {
                    val = usrType.Size.ToString();
                }
                break;

            case Operator.ValueOf:
                if (CurrentCodeBlock.IsProcessingTypedef)
                {
                    string msg = "ValueOf operator not valid within type definitions.";
                    throw LayoutScriptException.Create <LayoutScriptException>(layout, null, msg, varName);
                }

                if (isVar)
                {
                    val = StringValueOf(sym);
                }
                else
                {
                    string msg = "ValueOf operator not valid for types.";
                    throw LayoutScriptException.Create <LayoutScriptException>(layout, null, msg, varName);
                }
                break;
            }

            return(val);
        }
Exemple #10
0
        private void InterpretFileObjectDefinition(Statement stmt)
        {
            EnsureParameters(stmt, Parameters.Comment, Parameters.Count, Parameters.Name);

            bool hasCount = GetParameter(stmt, Parameters.Count, out string countStr);
            bool hasName  = GetParameter(stmt, Parameters.Name, out string objName);

            string typeName             = stmt.Keyword;
            bool   isAnonymousStructure = (typeName == Keywords.DataTypes.Struct || typeName == Keywords.DataTypes.Union);

            TypeInfo type = default(TypeInfo);

            if (!isAnonymousStructure && !TryLookupType(typeName, out type))
            {
                string msg = "Unknown type '{0}'.";
                throw LayoutScriptException.Create <LayoutScriptException>(layout, stmt, msg, typeName);
            }

            // Evaluate 'count' expression
            int count = 1;

            if (hasCount)
            {
                try
                {
                    count = (int)EvaluateExpression(countStr);
                }
                catch (SyntaxErrorException e)
                {
                    string msg = "'{0}' is not a valid expression.";
                    throw LayoutScriptException.Create <LayoutScriptException>(layout, e, stmt, msg, countStr);
                }

                if (count <= 0)
                {
                    string msg = "Parameter '{0}' must be a positive integer.";
                    throw LayoutScriptException.Create <LayoutScriptException>(layout, stmt, msg, Parameters.Count);
                }
            }

            // Validate name and create object symbol
            SymbolTable sym = SymbolTable.CreateRootSymbolTable();

            if (hasName)
            {
                if (!SymbolTable.IsIdentifierValid(objName))
                {
                    string msg = "Invalid identifier '{0}'. " +
                                 "Identifiers must consist of only letters, numbers, and underscores. " +
                                 "Identifiers cannot begin with a digit nor can they be identical to a reserved word.";
                    throw LayoutScriptException.Create <LayoutScriptException>(layout, stmt, msg, objName);
                }
                if (CurrentCodeBlock.Symbol.Lookup(objName) != null || TryLookupLocal(objName, out double dummyLocalValue))
                {
                    string msg = "A variable with identifier '{0}' already exists in the current scope.";
                    throw LayoutScriptException.Create <LayoutScriptException>(layout, stmt, msg, objName);
                }

                if (hasCount)
                {
                    sym = CurrentCodeBlock.Symbol.Insert(objName, count);
                }
                else
                {
                    sym = CurrentCodeBlock.Symbol.Insert(objName);
                }
            }

            // Set symbol properties
            sym.GlobalDataAddress = GlobalOffset;
            sym.LocalDataAddress  = CurrentCodeBlock.Offset;
            if (isAnonymousStructure || type.IsStruct || type.IsUnion)
            {
                sym.DataType = typeof(Structure);
            }
            else
            {
                sym.DataType = type.NativeType;
            }

            int         totalDataLength = 0;
            SymbolTable elemSym         = sym;

            for (int i = 0; i < count; i++)
            {
                if (hasCount && hasName)
                {
                    elemSym = sym[i];
                }
                elemSym.GlobalDataAddress = GlobalOffset;

                if (isAnonymousStructure || type.IsStruct || type.IsUnion)
                {
                    if (hasName)
                    {
                        scopeStack.Push(new CodeBlock(elemSym));
                    }
                    else
                    {
                        scopeStack.Push(new CodeBlock(SymbolTable.CreateNamelessSymbolTable(CurrentCodeBlock.Symbol)));
                    }
                    CurrentCodeBlock.IsUnion = (stmt.Keyword == Keywords.DataTypes.Union || (type != null && type.IsUnion));

                    IEnumerable <Statement> members = (isAnonymousStructure)
                        ? stmt.NestedStatements
                        : type.Members;
                    if (!members.Any())
                    {
                        string msg = "Empty structures are not allowed.";
                        throw LayoutScriptException.Create <SyntaxException>(layout, stmt, msg);
                    }

                    foreach (Statement member in members)
                    {
                        InterpretStatement(member);
                    }

                    CodeBlock oldScope = scopeStack.Pop();
                    int       numBytes = oldScope.MaxOffset;
                    if (!CurrentCodeBlock.IsUnion)
                    {
                        CurrentCodeBlock.Offset += numBytes;
                    }
                    else
                    {
                        CurrentCodeBlock.MaxOffset = numBytes;
                    }

                    elemSym.DataType   = sym.DataType;
                    elemSym.DataLength = numBytes;
                    totalDataLength   += numBytes;
                }
                else
                {
                    int numBytes  = type.Size;
                    int newOffset = CurrentCodeBlock.Offset + numBytes;
                    if (newOffset > file.Length)
                    {
                        string msg = "Object definition runs past the end of the file.";
                        throw LayoutScriptException.Create <LayoutScriptException>(layout, stmt, msg);
                    }

                    if (!CurrentCodeBlock.IsUnion)
                    {
                        CurrentCodeBlock.Offset = newOffset;
                    }
                    else
                    {
                        CurrentCodeBlock.MaxOffset = numBytes;
                    }

                    elemSym.DataType   = type.NativeType;
                    elemSym.DataLength = numBytes;
                    totalDataLength   += numBytes;
                }
            }
            sym.DataLength = totalDataLength;
        }