Index: trunk/src/VBox/Storage/testcase/VDScript.cpp
===================================================================
--- trunk/src/VBox/Storage/testcase/VDScript.cpp	(revision 44811)
+++ trunk/src/VBox/Storage/testcase/VDScript.cpp	(revision 44840)
@@ -36,4 +36,9 @@
  * code. Could be used as a scripting language for the VBox debugger for example or in the scm
  * tool to automatically rewrite C code using the AST VDSCript generates...
+ *
+ * The syntax of VDSCript is derived from the C syntax. The syntax of C in BNF was taken
+ * from: http://www.csci.csusb.edu/dick/samples/c.syntax.html
+ * and: http://slps.github.com/zoo/c/iso-9899-tc3.html
+ * and: http://www.open-std.org/jtc1/sc22/WG14/www/docs/n1256.pdf
  */
 #define LOGGROUP LOGGROUP_DEFAULT
@@ -42,4 +47,5 @@
 #include <iprt/mem.h>
 #include <iprt/ctype.h>
+#include <iprt/stream.h>
 
 #include <VBox/log.h>
@@ -47,19 +53,4 @@
 #include "VDScript.h"
 #include "VDScriptAst.h"
-
-/**
- * Position information.
- */
-typedef struct VDSRCPOS
-{
-    /** Line in the source. */
-    unsigned       iLine;
-    /** Current start character .*/
-    unsigned       iChStart;
-    /** Current end character. */
-    unsigned       iChEnd;
-} VDSRCPOS;
-/** Pointer to a source position. */
-typedef struct VDSRCPOS *PVDSRCPOS;
 
 /**
@@ -102,4 +93,6 @@
     VDSCRIPTTOKENKEYWORD_WHILE,
     VDSCRIPTTOKENKEYWORD_BREAK,
+    VDSCRIPTTOKENKEYWORD_FALSE,
+    VDSCRIPTTOKENKEYWORD_TRUE,
     VDSCRIPTTOKENKEYWORD_ELSE,
     VDSCRIPTTOKENKEYWORD_CASE,
@@ -135,11 +128,5 @@
         struct
         {
-            /** Flag whether the number is negative. */
-            bool fNegative;
-            union
-            {
-                uint64_t u64;
-                int64_t  i64;
-            };
+            uint64_t u64;
         } NumConst;
         /** String constant */
@@ -297,5 +284,6 @@
     {"<",   1},
     {">",   1},
-    {"!",   1}
+    {"!",   1},
+    {"~",   1}
 };
 
@@ -339,4 +327,6 @@
     {"while",    5, VDSCRIPTTOKENKEYWORD_WHILE},
     {"break",    5, VDSCRIPTTOKENKEYWORD_BREAK},
+    {"false",    5, VDSCRIPTTOKENKEYWORD_FALSE},
+    {"true",     4, VDSCRIPTTOKENKEYWORD_TRUE},
     {"else",     4, VDSCRIPTTOKENKEYWORD_ELSE},
     {"case",     4, VDSCRIPTTOKENKEYWORD_CASE},
@@ -348,4 +338,6 @@
 static int vdScriptParseCompoundStatement(PVDSCRIPTCTXINT pThis, PVDSCRIPTASTSTMT *ppAstNodeCompound);
 static int vdScriptParseStatement(PVDSCRIPTCTXINT pThis, PVDSCRIPTASTSTMT *ppAstNodeStmt);
+static int vdScriptParseExpression(PVDSCRIPTCTXINT pThis, PVDSCRIPTASTEXPR *ppAstNodeExpr);
+static int vdScriptParseAssignmentExpression(PVDSCRIPTCTXINT pThis, PVDSCRIPTASTEXPR *ppAstNodeExpr);
 
 /**
@@ -458,4 +450,9 @@
             vdScriptTokenizerSkipCh(pTokenizer);
     }
+
+    if (!vdScriptTokenizerIsEos(pTokenizer))
+        vdScriptTokenizerSkipCh(pTokenizer);
+    if (!vdScriptTokenizerIsEos(pTokenizer))
+        vdScriptTokenizerSkipCh(pTokenizer);
 }
 
@@ -469,9 +466,8 @@
 DECLINLINE(void) vdScriptTokenizerSkipWhitespace(PVDTOKENIZER pTokenizer)
 {
-    while (true)
-    {
-        while (  !vdScriptTokenizerIsEos(pTokenizer)
-               && (   vdScriptTokenizerGetCh(pTokenizer) == ' '
-                   || vdScriptTokenizerGetCh(pTokenizer) == '\t'))
+    while (!vdScriptTokenizerIsEos(pTokenizer))
+    {
+        while (   vdScriptTokenizerGetCh(pTokenizer) == ' '
+               || vdScriptTokenizerGetCh(pTokenizer) == '\t')
             vdScriptTokenizerSkipCh(pTokenizer);
 
@@ -481,5 +477,9 @@
             if (   vdScriptTokenizerGetCh(pTokenizer) == '/'
                 && vdScriptTokenizerPeekCh(pTokenizer) == '*')
+            {
+                vdScriptTokenizerSkipCh(pTokenizer);
+                vdScriptTokenizerSkipCh(pTokenizer);
                 vdScriptTokenizerSkipComment(pTokenizer);
+            }
             else
                 break; /* Skipped everything, next is some real content. */
@@ -545,12 +545,17 @@
 {
     unsigned uBase = 10;
-    size_t cchNumber = 0;
+    char *pszNext = NULL;
 
     Assert(RT_C_IS_DIGIT(vdScriptTokenizerGetCh(pTokenizer)));
 
-    if (vdScriptTokenizerGetCh(pTokenizer) == '0')
-    {
-        /* Maybe octal or hex representation. */
-    }
+    /* Let RTStrToUInt64Ex() do all the work, looks C compliant :). */
+    pToken->enmClass = VDTOKENCLASS_NUMCONST;
+    int rc = RTStrToUInt64Ex(pTokenizer->pszInput, &pszNext, 0, &pToken->Class.NumConst.u64);
+    Assert(RT_SUCCESS(rc) || rc == VWRN_TRAILING_CHARS || rc == VWRN_TRAILING_SPACES);
+    /** @todo: Handle number to big, throw a warning */
+
+    unsigned cchNumber = pszNext - pTokenizer->pszInput;
+    for (unsigned i = 0; i < cchNumber; i++)
+        vdScriptTokenizerSkipCh(pTokenizer);
 }
 
@@ -846,4 +851,42 @@
 
 /**
+ * Check whether the next token in the input stream is a keyword and matches the given
+ * keyword.
+ *
+ * @returns true if the token matched.
+ *          false otherwise.
+ * @param   pTokenizer    The tokenizer state.
+ * @param   pszOp         The operation to check against.
+ */
+static bool vdScriptTokenizerIsOperatorEqual(PVDTOKENIZER pTokenizer, const char *pszOp)
+{
+    PCVDSCRIPTTOKEN pToken = vdScriptTokenizerGetToken(pTokenizer);
+
+    if (   pToken->enmClass == VDTOKENCLASS_OPERATORS
+        && !RTStrCmp(pToken->Class.Operator.aszOp, pszOp))
+        return true;
+
+    return false;
+}
+
+/**
+ * Check whether the next token in the input stream is an operator and matches the given
+ * keyword and skips it.
+ *
+ * @returns true if the token matched and was skipped.
+ *          false otherwise.
+ * @param   pTokenizer    The tokenizer state.
+ * @param   pszOp         The operation to check against.
+ */
+static bool vdScriptTokenizerSkipIfIsOperatorEqual(PVDTOKENIZER pTokenizer, const char *pszOp)
+{
+    bool fEqual = vdScriptTokenizerIsOperatorEqual(pTokenizer, pszOp);
+    if (fEqual)
+        vdScriptTokenizerConsume(pTokenizer);
+
+    return fEqual;
+}
+
+/**
  * Record an error while parsing.
  *
@@ -854,4 +897,5 @@
     NOREF(pThis);
     NOREF(pszFmt);
+    RTPrintf(pszFmt);
     return rc;
 }
@@ -885,4 +929,5 @@
 
             *ppAstNodeIde = pAstNodeIde;
+            vdScriptTokenizerConsume(pThis->pTokenizer);
         }
         else
@@ -895,26 +940,1023 @@
 
 /**
- * Parse a conditional expression.
+ * Parse a primary expression.
+ *
+ * @returns VBox status code.
+ * @param   pThis                The  script context.
+ * @param   ppAstNodeExpr        Where to store the primary expression on success.
+ */
+static int vdScriptParsePrimaryExpression(PVDSCRIPTCTXINT pThis, PVDSCRIPTASTEXPR *ppAstNodeExpr)
+{
+    int rc = VINF_SUCCESS;
+
+    if (vdScriptTokenizerSkipIfIsPunctuatorEqual(pThis->pTokenizer, '('))
+    {
+        rc = vdScriptParseExpression(pThis, ppAstNodeExpr);
+        if (RT_SUCCESS(rc)
+            && !vdScriptTokenizerSkipIfIsPunctuatorEqual(pThis->pTokenizer, ')'))
+            rc = vdScriptParserError(pThis, VERR_INVALID_PARAMETER, RT_SRC_POS, "Parser: Expected \")\", got ...\n");
+    }
+    else
+    {
+        PVDSCRIPTASTEXPR pExpr = (PVDSCRIPTASTEXPR)vdScriptAstNodeAlloc(VDSCRIPTASTCLASS_EXPRESSION);
+        if (pExpr)
+        {
+            if (vdScriptTokenizerGetTokenClass(pThis->pTokenizer) == VDTOKENCLASS_IDENTIFIER)
+            {
+                PVDSCRIPTASTIDE pIde = NULL;
+                rc = vdScriptParseIde(pThis, &pIde);
+                if (RT_SUCCESS(rc))
+                {
+                    pExpr->enmType = VDSCRIPTEXPRTYPE_PRIMARY_IDENTIFIER;
+                    pExpr->pIde = pIde;
+                }
+            }
+            else if (vdScriptTokenizerGetTokenClass(pThis->pTokenizer) == VDTOKENCLASS_NUMCONST)
+            {
+                PCVDSCRIPTTOKEN pToken = vdScriptTokenizerGetToken(pThis->pTokenizer);
+                pExpr->enmType = VDSCRIPTEXPRTYPE_PRIMARY_NUMCONST;
+                pExpr->u64 = pToken->Class.NumConst.u64;
+                vdScriptTokenizerConsume(pThis->pTokenizer);
+            }
+            else if (vdScriptTokenizerGetTokenClass(pThis->pTokenizer) == VDTOKENCLASS_STRINGCONST)
+            {
+                PCVDSCRIPTTOKEN pToken = vdScriptTokenizerGetToken(pThis->pTokenizer);
+                pExpr->enmType = VDSCRIPTEXPRTYPE_PRIMARY_STRINGCONST;
+                pExpr->pszStr = RTStrDup(pToken->Class.StringConst.pszString);
+                vdScriptTokenizerConsume(pThis->pTokenizer);
+
+                if (!pExpr->pszStr)
+                    rc = vdScriptParserError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Parser: Out of memory allocating string\n");
+            }
+            else
+                rc = vdScriptParserError(pThis, VERR_INVALID_PARAMETER, RT_SRC_POS, "Parser: Expected \"(\" | identifier | constant | string, got ...\n");
+
+            if (RT_FAILURE(rc))
+                vdScriptAstNodeFree(&pExpr->Core);
+            else
+                *ppAstNodeExpr = pExpr;
+        }
+        else
+            rc = vdScriptParserError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Parser: Out of memory allocating expression AST node\n");
+    }
+
+    return rc;
+}
+
+/**
+ * Parse an argument list for a function call.
+ *
+ * @returns VBox status code.
+ * @param   pThis                The script context.
+ * @param   pFnCall              The function call AST node.
+ */
+static int vdScriptParseFnCallArgumentList(PVDSCRIPTCTXINT pThis, PVDSCRIPTASTEXPR pFnCall)
+{
+    int rc = VINF_SUCCESS;
+    PVDSCRIPTASTEXPR pExpr = NULL;
+
+    rc = vdScriptParseAssignmentExpression(pThis, &pExpr);
+    if (RT_SUCCESS(rc))
+    {
+        RTListAppend(&pFnCall->FnCall.ListArgs, &pExpr->Core.ListNode);
+        while (vdScriptTokenizerSkipIfIsPunctuatorEqual(pThis->pTokenizer, ','))
+        {
+            rc = vdScriptParseAssignmentExpression(pThis, &pExpr);
+            if (RT_SUCCESS(rc))
+                RTListAppend(&pFnCall->FnCall.ListArgs, &pExpr->Core.ListNode);
+            else
+                break;
+        }
+        if (   RT_SUCCESS(rc)
+            && !vdScriptTokenizerSkipIfIsPunctuatorEqual(pThis->pTokenizer, ')'))
+            rc = vdScriptParserError(pThis, VERR_INVALID_PARAMETER, RT_SRC_POS, "Parser: Expected \")\", got ...\n");
+    }
+
+    return rc;
+}
+
+/**
+ * Parse a postfix expression.
  *
  * @returns VBox status code.
  * @param   pThis                The script context.
  * @param   ppAstNodeExpr        Where to store the expression AST node on success.
- */
-static int vdScriptParseCondExpression(PVDSCRIPTCTXINT pThis, PVDSCRIPTASTEXPR *ppAstNodeExpr)
-{
-    int rc = VERR_NOT_IMPLEMENTED;
-    return rc;
-}
-
-/**
- * Parse an expression.
+ *
+ * @note Syntax:
+ *      postfix-expression:
+ *          primary-expression
+ *          postfix-expression ( argument-expression )
+ *          postfix-expression ++
+ *          postfix-expression --
+ */
+static int vdScriptParsePostfixExpression(PVDSCRIPTCTXINT pThis, PVDSCRIPTASTEXPR *ppAstNodeExpr)
+{
+    int rc = VINF_SUCCESS;
+    PVDSCRIPTASTEXPR pExpr = NULL;
+
+    rc = vdScriptParsePrimaryExpression(pThis, &pExpr);
+    if (RT_SUCCESS(rc))
+    {
+        while (true)
+        {
+            PVDSCRIPTASTEXPR pExprNew = NULL;
+
+            if (vdScriptTokenizerSkipIfIsOperatorEqual(pThis->pTokenizer, "++"))
+            {
+                pExprNew = (PVDSCRIPTASTEXPR)vdScriptAstNodeAlloc(VDSCRIPTASTCLASS_EXPRESSION);
+                if (pExprNew)
+                {
+                    pExprNew->enmType = VDSCRIPTEXPRTYPE_POSTFIX_INCREMENT;
+                    pExprNew->pExpr = pExpr;
+                    pExpr = pExprNew;
+                }
+                else
+                    rc = vdScriptParserError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Parser: Out of memory allocating expression AST node\n");
+            }
+            else if (vdScriptTokenizerSkipIfIsOperatorEqual(pThis->pTokenizer, "--"))
+            {
+                pExprNew = (PVDSCRIPTASTEXPR)vdScriptAstNodeAlloc(VDSCRIPTASTCLASS_EXPRESSION);
+                if (pExprNew)
+                {
+                    pExprNew->enmType = VDSCRIPTEXPRTYPE_POSTFIX_DECREMENT;
+                    pExprNew->pExpr = pExpr;
+                    pExpr = pExprNew;
+                }
+                else
+                    rc = vdScriptParserError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Parser: Out of memory allocating expression AST node\n");
+            }
+            else if (vdScriptTokenizerSkipIfIsPunctuatorEqual(pThis->pTokenizer, '('))
+            {
+                pExprNew = (PVDSCRIPTASTEXPR)vdScriptAstNodeAlloc(VDSCRIPTASTCLASS_EXPRESSION);
+                if (pExprNew)
+                {
+                    pExprNew->enmType = VDSCRIPTEXPRTYPE_POSTFIX_FNCALL;
+                    RTListInit(&pExprNew->FnCall.ListArgs);
+                    if (!vdScriptTokenizerSkipIfIsPunctuatorEqual(pThis->pTokenizer, ')'))
+                        rc = vdScriptParseFnCallArgumentList(pThis, pExprNew);
+                    pExprNew->FnCall.pFnIde = pExpr;
+                    pExpr = pExprNew;
+                }
+                else
+                    rc = vdScriptParserError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Parser: Out of memory allocating expression AST node\n");
+            }
+            else
+                break;
+
+            if (RT_FAILURE(rc))
+                break;
+        }
+
+        if (RT_SUCCESS(rc))
+            *ppAstNodeExpr = pExpr;
+        else
+            vdScriptAstNodeFree(&pExpr->Core);
+    }
+    return rc;
+}
+
+/**
+ * Parse an unary expression.
  *
  * @returns VBox status code.
  * @param   pThis                The script context.
  * @param   ppAstNodeExpr        Where to store the expression AST node on success.
+ *
+ * @note Syntax:
+ *      unary-expression:
+ *          postfix-expression
+ *          ++ unary-expression
+ *          -- unary-expression
+ *          + unary-expression
+ *          - unary-expression
+ *          ~ unary-expression
+ *          ! unary-expression
+ */
+static int vdScriptParseUnaryExpression(PVDSCRIPTCTXINT pThis, PVDSCRIPTASTEXPR *ppAstNodeExpr)
+{
+    int rc = VINF_SUCCESS;
+    PVDSCRIPTASTEXPR pExpr = NULL;
+    PVDSCRIPTASTEXPR pExprTop = NULL;
+
+    while (true)
+    {
+        PVDSCRIPTASTEXPR pExprNew = NULL;
+
+        if (vdScriptTokenizerSkipIfIsOperatorEqual(pThis->pTokenizer, "++"))
+        {
+            pExprNew = (PVDSCRIPTASTEXPR)vdScriptAstNodeAlloc(VDSCRIPTASTCLASS_EXPRESSION);
+            if (pExprNew)
+                pExprNew->enmType = VDSCRIPTEXPRTYPE_UNARY_INCREMENT;
+            else
+                rc = vdScriptParserError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Parser: Out of memory allocating expression AST node\n");
+        }
+        else if (vdScriptTokenizerSkipIfIsOperatorEqual(pThis->pTokenizer, "--"))
+        {
+            pExprNew = (PVDSCRIPTASTEXPR)vdScriptAstNodeAlloc(VDSCRIPTASTCLASS_EXPRESSION);
+            if (pExprNew)
+                pExprNew->enmType = VDSCRIPTEXPRTYPE_UNARY_DECREMENT;
+            else
+                rc = vdScriptParserError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Parser: Out of memory allocating expression AST node\n");
+        }
+        else if (vdScriptTokenizerSkipIfIsOperatorEqual(pThis->pTokenizer, "+"))
+        {
+            pExprNew = (PVDSCRIPTASTEXPR)vdScriptAstNodeAlloc(VDSCRIPTASTCLASS_EXPRESSION);
+            if (pExprNew)
+                pExprNew->enmType = VDSCRIPTEXPRTYPE_UNARY_POSSIGN;
+            else
+                rc = vdScriptParserError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Parser: Out of memory allocating expression AST node\n");
+        }
+        else if (vdScriptTokenizerSkipIfIsOperatorEqual(pThis->pTokenizer, "-"))
+        {
+            pExprNew = (PVDSCRIPTASTEXPR)vdScriptAstNodeAlloc(VDSCRIPTASTCLASS_EXPRESSION);
+            if (pExprNew)
+                pExprNew->enmType = VDSCRIPTEXPRTYPE_UNARY_NEGSIGN;
+            else
+                rc = vdScriptParserError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Parser: Out of memory allocating expression AST node\n");
+        }
+        else if (vdScriptTokenizerSkipIfIsOperatorEqual(pThis->pTokenizer, "~"))
+        {
+            pExprNew = (PVDSCRIPTASTEXPR)vdScriptAstNodeAlloc(VDSCRIPTASTCLASS_EXPRESSION);
+            if (pExprNew)
+                pExprNew->enmType = VDSCRIPTEXPRTYPE_UNARY_INVERT;
+            else
+                rc = vdScriptParserError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Parser: Out of memory allocating expression AST node\n");
+        }
+        else if (vdScriptTokenizerSkipIfIsOperatorEqual(pThis->pTokenizer, "!"))
+        {
+            pExprNew = (PVDSCRIPTASTEXPR)vdScriptAstNodeAlloc(VDSCRIPTASTCLASS_EXPRESSION);
+            if (pExprNew)
+                pExprNew->enmType = VDSCRIPTEXPRTYPE_UNARY_NEGATE;
+            else
+                rc = vdScriptParserError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Parser: Out of memory allocating expression AST node\n");
+        }
+        else
+        {
+            /* Must be a postfix expression. */
+            rc = vdScriptParsePostfixExpression(pThis, &pExprNew);
+        }
+
+        if (RT_SUCCESS(rc))
+        {
+            if (!pExprTop)
+            {
+                pExprTop = pExprNew;
+                pExpr = pExprNew;
+            }
+            else
+            {
+                pExpr->pExpr = pExprNew;
+                pExpr = pExprNew;
+            }
+        }
+        else
+            break;
+    }
+
+    if (RT_SUCCESS(rc))
+        *ppAstNodeExpr = pExprTop;
+    else if (pExprTop)
+        vdScriptAstNodeFree(&pExprTop->Core);
+
+    return rc;
+}
+
+/**
+ * Parse a multiplicative expression.
+ *
+ * @returns VBox status code.
+ * @param   pThis                The script context.
+ * @param   ppAstNodeExpr        Where to store the expression AST node on success.
+ *
+ * @note Syntax:
+ *      multiplicative-expression:
+ *          unary-expression
+ *          multiplicative-expression * unary-expression
+ *          multiplicative-expression / unary-expression
+ *          multiplicative-expression % unary-expression
+ */
+static int vdScriptParseMultiplicativeExpression(PVDSCRIPTCTXINT pThis, PVDSCRIPTASTEXPR *ppAstNodeExpr)
+{
+    int rc = VINF_SUCCESS;
+    PVDSCRIPTASTEXPR pExpr = NULL;
+
+    rc = vdScriptParseUnaryExpression(pThis, &pExpr);
+    if (RT_SUCCESS(rc))
+    {
+        PVDSCRIPTASTEXPR pExprNew = NULL;
+        while (RT_SUCCESS(rc))
+        {
+            if (vdScriptTokenizerSkipIfIsOperatorEqual(pThis->pTokenizer, "*"))
+            {
+                pExprNew = (PVDSCRIPTASTEXPR)vdScriptAstNodeAlloc(VDSCRIPTASTCLASS_EXPRESSION);
+                if (pExprNew)
+                    pExprNew->enmType = VDSCRIPTEXPRTYPE_MULTIPLICATION;
+                else
+                    rc = vdScriptParserError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Parser: Out of memory allocating expression AST node\n");
+            }
+            else if (vdScriptTokenizerSkipIfIsOperatorEqual(pThis->pTokenizer, "/"))
+            {
+                pExprNew = (PVDSCRIPTASTEXPR)vdScriptAstNodeAlloc(VDSCRIPTASTCLASS_EXPRESSION);
+                if (pExprNew)
+                    pExprNew->enmType = VDSCRIPTEXPRTYPE_DIVISION;
+                else
+                    rc = vdScriptParserError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Parser: Out of memory allocating expression AST node\n");
+            }
+            else if (vdScriptTokenizerSkipIfIsOperatorEqual(pThis->pTokenizer, "%"))
+            {
+                pExprNew = (PVDSCRIPTASTEXPR)vdScriptAstNodeAlloc(VDSCRIPTASTCLASS_EXPRESSION);
+                if (pExprNew)
+                    pExprNew->enmType = VDSCRIPTEXPRTYPE_MODULUS;
+                else
+                    rc = vdScriptParserError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Parser: Out of memory allocating expression AST node\n");
+            }
+            else
+                break;
+
+            pExprNew->BinaryOp.pLeftExpr = pExpr;
+            pExpr = pExprNew;
+            rc = vdScriptParseUnaryExpression(pThis, &pExprNew);
+            if (RT_SUCCESS(rc))
+                pExpr->BinaryOp.pRightExpr = pExprNew;
+        }
+
+        if (RT_SUCCESS(rc))
+            *ppAstNodeExpr = pExpr;
+        else
+            vdScriptAstNodeFree(&pExpr->Core);
+    }
+    return rc;
+}
+
+/**
+ * Parse a additive expression.
+ *
+ * @returns VBox status code.
+ * @param   pThis                The script context.
+ * @param   ppAstNodeExpr        Where to store the expression AST node on success.
+ *
+ * @note Syntax:
+ *      additive-expression:
+ *          multiplicative-expression
+ *          additive-expression + multiplicative-expression
+ *          additive-expression - multiplicative-expression
+ */
+static int vdScriptParseAdditiveExpression(PVDSCRIPTCTXINT pThis, PVDSCRIPTASTEXPR *ppAstNodeExpr)
+{
+    int rc = VINF_SUCCESS;
+    PVDSCRIPTASTEXPR pExpr = NULL;
+
+    rc = vdScriptParseMultiplicativeExpression(pThis, &pExpr);
+    if (RT_SUCCESS(rc))
+    {
+        PVDSCRIPTASTEXPR pExprNew = NULL;
+        while (RT_SUCCESS(rc))
+        {
+            if (vdScriptTokenizerSkipIfIsOperatorEqual(pThis->pTokenizer, "+"))
+            {
+                pExprNew = (PVDSCRIPTASTEXPR)vdScriptAstNodeAlloc(VDSCRIPTASTCLASS_EXPRESSION);
+                if (pExprNew)
+                    pExprNew->enmType = VDSCRIPTEXPRTYPE_ADDITION;
+                else
+                    rc = vdScriptParserError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Parser: Out of memory allocating expression AST node\n");
+            }
+            else if (vdScriptTokenizerSkipIfIsOperatorEqual(pThis->pTokenizer, "-"))
+            {
+                pExprNew = (PVDSCRIPTASTEXPR)vdScriptAstNodeAlloc(VDSCRIPTASTCLASS_EXPRESSION);
+                if (pExprNew)
+                    pExprNew->enmType = VDSCRIPTEXPRTYPE_SUBTRACTION;
+                else
+                    rc = vdScriptParserError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Parser: Out of memory allocating expression AST node\n");
+            }
+            else
+                break;
+
+            pExprNew->BinaryOp.pLeftExpr = pExpr;
+            pExpr = pExprNew;
+            rc = vdScriptParseMultiplicativeExpression(pThis, &pExprNew);
+            if (RT_SUCCESS(rc))
+                pExpr->BinaryOp.pRightExpr = pExprNew;
+        }
+
+        if (RT_SUCCESS(rc))
+            *ppAstNodeExpr = pExpr;
+        else
+            vdScriptAstNodeFree(&pExpr->Core);
+    }
+    return rc;
+}
+
+/**
+ * Parse a shift expression.
+ *
+ * @returns VBox status code.
+ * @param   pThis                The script context.
+ * @param   ppAstNodeExpr        Where to store the expression AST node on success.
+ *
+ * @note Syntax:
+ *      shift-expression:
+ *          additive-expression
+ *          shift-expression << additive-expression
+ *          shift-expression >> additive-expression
+ */
+static int vdScriptParseShiftExpression(PVDSCRIPTCTXINT pThis, PVDSCRIPTASTEXPR *ppAstNodeExpr)
+{
+    int rc = VINF_SUCCESS;
+    PVDSCRIPTASTEXPR pExpr = NULL;
+
+    rc = vdScriptParseAdditiveExpression(pThis, &pExpr);
+    if (RT_SUCCESS(rc))
+    {
+        PVDSCRIPTASTEXPR pExprNew = NULL;
+        while (RT_SUCCESS(rc))
+        {
+            if (vdScriptTokenizerSkipIfIsOperatorEqual(pThis->pTokenizer, "<<"))
+            {
+                pExprNew = (PVDSCRIPTASTEXPR)vdScriptAstNodeAlloc(VDSCRIPTASTCLASS_EXPRESSION);
+                if (pExprNew)
+                    pExprNew->enmType = VDSCRIPTEXPRTYPE_LSL;
+                else
+                    rc = vdScriptParserError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Parser: Out of memory allocating expression AST node\n");
+            }
+            else if (vdScriptTokenizerSkipIfIsOperatorEqual(pThis->pTokenizer, ">>"))
+            {
+                pExprNew = (PVDSCRIPTASTEXPR)vdScriptAstNodeAlloc(VDSCRIPTASTCLASS_EXPRESSION);
+                if (pExprNew)
+                    pExprNew->enmType = VDSCRIPTEXPRTYPE_LSR;
+                else
+                    rc = vdScriptParserError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Parser: Out of memory allocating expression AST node\n");
+            }
+            else
+                break;
+
+            pExprNew->BinaryOp.pLeftExpr = pExpr;
+            pExpr = pExprNew;
+            rc = vdScriptParseAdditiveExpression(pThis, &pExprNew);
+            if (RT_SUCCESS(rc))
+                pExpr->BinaryOp.pRightExpr = pExprNew;
+        }
+
+        if (RT_SUCCESS(rc))
+            *ppAstNodeExpr = pExpr;
+        else
+            vdScriptAstNodeFree(&pExpr->Core);
+    }
+    return rc;
+}
+
+/**
+ * Parse a relational expression.
+ *
+ * @returns VBox status code.
+ * @param   pThis                The script context.
+ * @param   ppAstNodeExpr        Where to store the expression AST node on success.
+ *
+ * @note Syntax:
+ *      relational-expression:
+ *          shift-expression
+ *          relational-expression < shift-expression
+ *          relational-expression > shift-expression
+ *          relational-expression >= shift-expression
+ *          relational-expression <= shift-expression
+ */
+static int vdScriptParseRelationalExpression(PVDSCRIPTCTXINT pThis, PVDSCRIPTASTEXPR *ppAstNodeExpr)
+{
+    int rc = VINF_SUCCESS;
+    PVDSCRIPTASTEXPR pExpr = NULL;
+
+    rc = vdScriptParseShiftExpression(pThis, &pExpr);
+    if (RT_SUCCESS(rc))
+    {
+        PVDSCRIPTASTEXPR pExprNew = NULL;
+        while (RT_SUCCESS(rc))
+        {
+            if (vdScriptTokenizerSkipIfIsOperatorEqual(pThis->pTokenizer, "<"))
+            {
+                pExprNew = (PVDSCRIPTASTEXPR)vdScriptAstNodeAlloc(VDSCRIPTASTCLASS_EXPRESSION);
+                if (pExprNew)
+                    pExprNew->enmType = VDSCRIPTEXPRTYPE_LOWER;
+                else
+                    rc = vdScriptParserError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Parser: Out of memory allocating expression AST node\n");
+            }
+            else if (vdScriptTokenizerSkipIfIsOperatorEqual(pThis->pTokenizer, ">"))
+            {
+                pExprNew = (PVDSCRIPTASTEXPR)vdScriptAstNodeAlloc(VDSCRIPTASTCLASS_EXPRESSION);
+                if (pExprNew)
+                    pExprNew->enmType = VDSCRIPTEXPRTYPE_HIGHER;
+                else
+                    rc = vdScriptParserError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Parser: Out of memory allocating expression AST node\n");
+            }
+            else if (vdScriptTokenizerSkipIfIsOperatorEqual(pThis->pTokenizer, ">="))
+            {
+                pExprNew = (PVDSCRIPTASTEXPR)vdScriptAstNodeAlloc(VDSCRIPTASTCLASS_EXPRESSION);
+                if (pExprNew)
+                    pExprNew->enmType = VDSCRIPTEXPRTYPE_HIGHEREQUAL;
+                else
+                    rc = vdScriptParserError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Parser: Out of memory allocating expression AST node\n");
+            }
+            else if (vdScriptTokenizerSkipIfIsOperatorEqual(pThis->pTokenizer, "<="))
+            {
+                pExprNew = (PVDSCRIPTASTEXPR)vdScriptAstNodeAlloc(VDSCRIPTASTCLASS_EXPRESSION);
+                if (pExprNew)
+                    pExprNew->enmType = VDSCRIPTEXPRTYPE_LOWEREQUAL;
+                else
+                    rc = vdScriptParserError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Parser: Out of memory allocating expression AST node\n");
+            }
+            else
+                break;
+
+            pExprNew->BinaryOp.pLeftExpr = pExpr;
+            pExpr = pExprNew;
+            rc = vdScriptParseShiftExpression(pThis, &pExprNew);
+            if (RT_SUCCESS(rc))
+                pExpr->BinaryOp.pRightExpr = pExprNew;
+        }
+
+        if (RT_SUCCESS(rc))
+            *ppAstNodeExpr = pExpr;
+        else
+            vdScriptAstNodeFree(&pExpr->Core);
+    }
+    return rc;
+}
+
+/**
+ * Parse a equality expression.
+ *
+ * @returns VBox status code.
+ * @param   pThis                The script context.
+ * @param   ppAstNodeExpr        Where to store the expression AST node on success.
+ *
+ * @note Syntax:
+ *      equality-expression:
+ *          relational-expression
+ *          equality-expression == relational-expression
+ *          equality-expression != relational-expression
+ */
+static int vdScriptParseEqualityExpression(PVDSCRIPTCTXINT pThis, PVDSCRIPTASTEXPR *ppAstNodeExpr)
+{
+    int rc = VINF_SUCCESS;
+    PVDSCRIPTASTEXPR pExpr = NULL;
+
+    rc = vdScriptParseRelationalExpression(pThis, &pExpr);
+    if (RT_SUCCESS(rc))
+    {
+        PVDSCRIPTASTEXPR pExprNew = NULL;
+        while (RT_SUCCESS(rc))
+        {
+            if (vdScriptTokenizerSkipIfIsOperatorEqual(pThis->pTokenizer, "=="))
+            {
+                pExprNew = (PVDSCRIPTASTEXPR)vdScriptAstNodeAlloc(VDSCRIPTASTCLASS_EXPRESSION);
+                if (pExprNew)
+                    pExprNew->enmType = VDSCRIPTEXPRTYPE_EQUAL;
+                else
+                    rc = vdScriptParserError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Parser: Out of memory allocating expression AST node\n");
+            }
+            else if (vdScriptTokenizerSkipIfIsOperatorEqual(pThis->pTokenizer, "!="))
+            {
+                pExprNew = (PVDSCRIPTASTEXPR)vdScriptAstNodeAlloc(VDSCRIPTASTCLASS_EXPRESSION);
+                if (pExprNew)
+                    pExprNew->enmType = VDSCRIPTEXPRTYPE_NOTEQUAL;
+                else
+                    rc = vdScriptParserError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Parser: Out of memory allocating expression AST node\n");
+            }
+            else
+                break;
+
+            pExprNew->BinaryOp.pLeftExpr = pExpr;
+            pExpr = pExprNew;
+            rc = vdScriptParseRelationalExpression(pThis, &pExprNew);
+            if (RT_SUCCESS(rc))
+                pExpr->BinaryOp.pRightExpr = pExprNew;
+        }
+
+        if (RT_SUCCESS(rc))
+            *ppAstNodeExpr = pExpr;
+        else
+            vdScriptAstNodeFree(&pExpr->Core);
+    }
+    return rc;
+}
+
+/**
+ * Parse a bitwise and expression.
+ *
+ * @returns VBox status code.
+ * @param   pThis                The script context.
+ * @param   ppAstNodeExpr        Where to store the expression AST node on success.
+ *
+ * @note Syntax:
+ *      and-expression:
+ *          equality-expression
+ *          and-expression & equality-expression
+ */
+static int vdScriptParseBitwiseAndExpression(PVDSCRIPTCTXINT pThis, PVDSCRIPTASTEXPR *ppAstNodeExpr)
+{
+    int rc = VINF_SUCCESS;
+    PVDSCRIPTASTEXPR pExpr = NULL;
+
+    rc = vdScriptParseEqualityExpression(pThis, &pExpr);
+    if (RT_SUCCESS(rc))
+    {
+        PVDSCRIPTASTEXPR pExprNew = NULL;
+        while (   RT_SUCCESS(rc)
+               && vdScriptTokenizerSkipIfIsOperatorEqual(pThis->pTokenizer, "&"))
+        {
+            pExprNew = (PVDSCRIPTASTEXPR)vdScriptAstNodeAlloc(VDSCRIPTASTCLASS_EXPRESSION);
+            if (pExprNew)
+            {
+                pExprNew->enmType = VDSCRIPTEXPRTYPE_EQUAL;
+                pExprNew->BinaryOp.pLeftExpr = pExpr;
+                pExpr = pExprNew;
+                rc = vdScriptParseEqualityExpression(pThis, &pExprNew);
+                if (RT_SUCCESS(rc))
+                    pExpr->BinaryOp.pRightExpr = pExprNew;
+            }
+            else
+                rc = vdScriptParserError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Parser: Out of memory allocating expression AST node\n");
+        }
+
+        if (RT_SUCCESS(rc))
+            *ppAstNodeExpr = pExpr;
+        else
+            vdScriptAstNodeFree(&pExpr->Core);
+    }
+    return rc;
+}
+
+/**
+ * Parse a bitwise xor expression.
+ *
+ * @returns VBox status code.
+ * @param   pThis                The script context.
+ * @param   ppAstNodeExpr        Where to store the expression AST node on success.
+ *
+ * @note Syntax:
+ *      xor-expression:
+ *          and-expression
+ *          xor-expression ^ equality-expression
+ */
+static int vdScriptParseBitwiseXorExpression(PVDSCRIPTCTXINT pThis, PVDSCRIPTASTEXPR *ppAstNodeExpr)
+{
+    int rc = VINF_SUCCESS;
+    PVDSCRIPTASTEXPR pExpr = NULL;
+
+    rc = vdScriptParseBitwiseAndExpression(pThis, &pExpr);
+    if (RT_SUCCESS(rc))
+    {
+        PVDSCRIPTASTEXPR pExprNew = NULL;
+        while (   RT_SUCCESS(rc)
+               && vdScriptTokenizerSkipIfIsOperatorEqual(pThis->pTokenizer, "^"))
+        {
+            pExprNew = (PVDSCRIPTASTEXPR)vdScriptAstNodeAlloc(VDSCRIPTASTCLASS_EXPRESSION);
+            if (pExprNew)
+            {
+                pExprNew->enmType = VDSCRIPTEXPRTYPE_BITWISE_XOR;
+                pExprNew->BinaryOp.pLeftExpr = pExpr;
+                pExpr = pExprNew;
+                rc = vdScriptParseBitwiseAndExpression(pThis, &pExprNew);
+                if (RT_SUCCESS(rc))
+                    pExpr->BinaryOp.pRightExpr = pExprNew;
+            }
+            else
+                rc = vdScriptParserError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Parser: Out of memory allocating expression AST node\n");
+        }
+
+        if (RT_SUCCESS(rc))
+            *ppAstNodeExpr = pExpr;
+        else
+            vdScriptAstNodeFree(&pExpr->Core);
+    }
+    return rc;
+}
+
+/**
+ * Parse a bitwise or expression.
+ *
+ * @returns VBox status code.
+ * @param   pThis                The script context.
+ * @param   ppAstNodeExpr        Where to store the expression AST node on success.
+ *
+ * @note Syntax:
+ *      or-expression:
+ *          xor-expression
+ *          or-expression | xor-expression
+ */
+static int vdScriptParseBitwiseOrExpression(PVDSCRIPTCTXINT pThis, PVDSCRIPTASTEXPR *ppAstNodeExpr)
+{
+    int rc = VINF_SUCCESS;
+    PVDSCRIPTASTEXPR pExpr = NULL;
+
+    rc = vdScriptParseBitwiseXorExpression(pThis, &pExpr);
+    if (RT_SUCCESS(rc))
+    {
+        PVDSCRIPTASTEXPR pExprNew = NULL;
+        while (   RT_SUCCESS(rc)
+               && vdScriptTokenizerSkipIfIsOperatorEqual(pThis->pTokenizer, "|"))
+        {
+            pExprNew = (PVDSCRIPTASTEXPR)vdScriptAstNodeAlloc(VDSCRIPTASTCLASS_EXPRESSION);
+            if (pExprNew)
+            {
+                pExprNew->enmType = VDSCRIPTEXPRTYPE_BITWISE_OR;
+                pExprNew->BinaryOp.pLeftExpr = pExpr;
+                pExpr = pExprNew;
+                rc = vdScriptParseBitwiseXorExpression(pThis, &pExprNew);
+                if (RT_SUCCESS(rc))
+                    pExpr->BinaryOp.pRightExpr = pExprNew;
+            }
+            else
+                rc = vdScriptParserError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Parser: Out of memory allocating expression AST node\n");
+        }
+
+        if (RT_SUCCESS(rc))
+            *ppAstNodeExpr = pExpr;
+        else
+            vdScriptAstNodeFree(&pExpr->Core);
+    }
+    return rc;
+}
+
+/**
+ * Parse a logical and expression.
+ *
+ * @returns VBox status code.
+ * @param   pThis                The script context.
+ * @param   ppAstNodeExpr        Where to store the expression AST node on success.
+ *
+ * @note Syntax:
+ *      logical-and-expression:
+ *          or-expression
+ *          logical-and-expression | or-expression
+ */
+static int vdScriptParseLogicalAndExpression(PVDSCRIPTCTXINT pThis, PVDSCRIPTASTEXPR *ppAstNodeExpr)
+{
+    int rc = VINF_SUCCESS;
+    PVDSCRIPTASTEXPR pExpr = NULL;
+
+    rc = vdScriptParseBitwiseOrExpression(pThis, &pExpr);
+    if (RT_SUCCESS(rc))
+    {
+        PVDSCRIPTASTEXPR pExprNew = NULL;
+        while (   RT_SUCCESS(rc)
+               && vdScriptTokenizerSkipIfIsOperatorEqual(pThis->pTokenizer, "&&"))
+        {
+            pExprNew = (PVDSCRIPTASTEXPR)vdScriptAstNodeAlloc(VDSCRIPTASTCLASS_EXPRESSION);
+            if (pExprNew)
+            {
+                pExprNew->enmType = VDSCRIPTEXPRTYPE_LOGICAL_AND;
+                pExprNew->BinaryOp.pLeftExpr = pExpr;
+                pExpr = pExprNew;
+                rc = vdScriptParseBitwiseOrExpression(pThis, &pExprNew);
+                if (RT_SUCCESS(rc))
+                    pExpr->BinaryOp.pRightExpr = pExprNew;
+            }
+            else
+                rc = vdScriptParserError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Parser: Out of memory allocating expression AST node\n");
+        }
+
+        if (RT_SUCCESS(rc))
+            *ppAstNodeExpr = pExpr;
+        else
+            vdScriptAstNodeFree(&pExpr->Core);
+    }
+    return rc;
+}
+
+/**
+ * Parse a logical or expression.
+ *
+ * @returns VBox status code.
+ * @param   pThis                The script context.
+ * @param   ppAstNodeExpr        Where to store the expression AST node on success.
+ *
+ * @note Syntax:
+ *      logical-or-expression:
+ *          logical-and-expression
+ *          logical-or-expression | logical-and-expression
+ */
+static int vdScriptParseLogicalOrExpression(PVDSCRIPTCTXINT pThis, PVDSCRIPTASTEXPR *ppAstNodeExpr)
+{
+    int rc = VINF_SUCCESS;
+    PVDSCRIPTASTEXPR pExpr = NULL;
+
+    rc = vdScriptParseLogicalAndExpression(pThis, &pExpr);
+    if (RT_SUCCESS(rc))
+    {
+        PVDSCRIPTASTEXPR pExprNew = NULL;
+        while (   RT_SUCCESS(rc)
+               && vdScriptTokenizerSkipIfIsOperatorEqual(pThis->pTokenizer, "||"))
+        {
+            pExprNew = (PVDSCRIPTASTEXPR)vdScriptAstNodeAlloc(VDSCRIPTASTCLASS_EXPRESSION);
+            if (pExprNew)
+            {
+                pExprNew->enmType = VDSCRIPTEXPRTYPE_LOGICAL_OR;
+                pExprNew->BinaryOp.pLeftExpr = pExpr;
+                pExpr = pExprNew;
+                rc = vdScriptParseLogicalAndExpression(pThis, &pExprNew);
+                if (RT_SUCCESS(rc))
+                    pExpr->BinaryOp.pRightExpr = pExprNew;
+            }
+            else
+                rc = vdScriptParserError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Parser: Out of memory allocating expression AST node\n");
+        }
+
+        if (RT_SUCCESS(rc))
+            *ppAstNodeExpr = pExpr;
+        else
+            vdScriptAstNodeFree(&pExpr->Core);
+    }
+    return rc;
+}
+
+/**
+ * Parse a conditional expression.
+ *
+ * @returns VBox status code.
+ * @param   pThis                The script context.
+ * @param   ppAstNodeExpr        Where to store the expression AST node on success.
+ *
+ * @note: VDScript doesn't support logical-or-expression ? expression : conditional-expression
+ *        so a conditional expression is equal to a logical-or-expression.
+ */
+static int vdScriptParseCondExpression(PVDSCRIPTCTXINT pThis, PVDSCRIPTASTEXPR *ppAstNodeExpr)
+{
+    return vdScriptParseLogicalOrExpression(pThis, ppAstNodeExpr);
+}
+
+/**
+ * Parse an assignment expression.
+ *
+ * @returns VBox status code.
+ * @param   pThis                The script context.
+ * @param   ppAstNodeExpr        Where to store the expression AST node on success.
+ *
+ * @note Syntax:
+ *      assignment-expression:
+ *          conditional-expression
+ *          unary-expression assignment-operator assignment-expression
+ */
+static int vdScriptParseAssignmentExpression(PVDSCRIPTCTXINT pThis, PVDSCRIPTASTEXPR *ppAstNodeExpr)
+{
+    int rc = VINF_SUCCESS;
+    PVDSCRIPTASTEXPR pExpr;
+
+    rc = vdScriptParseLogicalOrExpression(pThis, &pExpr);
+    if (RT_SUCCESS(rc))
+    {
+        PVDSCRIPTASTEXPR pExprNew = NULL;
+        while (RT_SUCCESS(rc))
+        {
+            if (vdScriptTokenizerSkipIfIsOperatorEqual(pThis->pTokenizer, "="))
+            {
+                pExprNew = (PVDSCRIPTASTEXPR)vdScriptAstNodeAlloc(VDSCRIPTASTCLASS_EXPRESSION);
+                if (pExprNew)
+                    pExprNew->enmType = VDSCRIPTEXPRTYPE_ASSIGN;
+                else
+                    rc = vdScriptParserError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Parser: Out of memory allocating expression AST node\n");
+            }
+            else if (vdScriptTokenizerSkipIfIsOperatorEqual(pThis->pTokenizer, "*="))
+            {
+                pExprNew = (PVDSCRIPTASTEXPR)vdScriptAstNodeAlloc(VDSCRIPTASTCLASS_EXPRESSION);
+                if (pExprNew)
+                    pExprNew->enmType = VDSCRIPTEXPRTYPE_ASSIGN_MULT;
+                else
+                    rc = vdScriptParserError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Parser: Out of memory allocating expression AST node\n");
+            }
+            else if (vdScriptTokenizerSkipIfIsOperatorEqual(pThis->pTokenizer, "/="))
+            {
+                pExprNew = (PVDSCRIPTASTEXPR)vdScriptAstNodeAlloc(VDSCRIPTASTCLASS_EXPRESSION);
+                if (pExprNew)
+                    pExprNew->enmType = VDSCRIPTEXPRTYPE_ASSIGN_DIV;
+                else
+                    rc = vdScriptParserError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Parser: Out of memory allocating expression AST node\n");
+            }
+            else if (vdScriptTokenizerSkipIfIsOperatorEqual(pThis->pTokenizer, "%="))
+            {
+                pExprNew = (PVDSCRIPTASTEXPR)vdScriptAstNodeAlloc(VDSCRIPTASTCLASS_EXPRESSION);
+                if (pExprNew)
+                    pExprNew->enmType = VDSCRIPTEXPRTYPE_ASSIGN_MOD;
+                else
+                    rc = vdScriptParserError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Parser: Out of memory allocating expression AST node\n");
+            }
+            else if (vdScriptTokenizerSkipIfIsOperatorEqual(pThis->pTokenizer, "+="))
+            {
+                pExprNew = (PVDSCRIPTASTEXPR)vdScriptAstNodeAlloc(VDSCRIPTASTCLASS_EXPRESSION);
+                if (pExprNew)
+                    pExprNew->enmType = VDSCRIPTEXPRTYPE_ASSIGN_ADD;
+                else
+                    rc = vdScriptParserError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Parser: Out of memory allocating expression AST node\n");
+            }
+            else if (vdScriptTokenizerSkipIfIsOperatorEqual(pThis->pTokenizer, "-="))
+            {
+                pExprNew = (PVDSCRIPTASTEXPR)vdScriptAstNodeAlloc(VDSCRIPTASTCLASS_EXPRESSION);
+                if (pExprNew)
+                    pExprNew->enmType = VDSCRIPTEXPRTYPE_ASSIGN_SUB;
+                else
+                    rc = vdScriptParserError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Parser: Out of memory allocating expression AST node\n");
+            }
+            else if (vdScriptTokenizerSkipIfIsOperatorEqual(pThis->pTokenizer, "<<="))
+            {
+                pExprNew = (PVDSCRIPTASTEXPR)vdScriptAstNodeAlloc(VDSCRIPTASTCLASS_EXPRESSION);
+                if (pExprNew)
+                    pExprNew->enmType = VDSCRIPTEXPRTYPE_ASSIGN_LSL;
+                else
+                    rc = vdScriptParserError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Parser: Out of memory allocating expression AST node\n");
+            }
+            else if (vdScriptTokenizerSkipIfIsOperatorEqual(pThis->pTokenizer, ">>="))
+            {
+                pExprNew = (PVDSCRIPTASTEXPR)vdScriptAstNodeAlloc(VDSCRIPTASTCLASS_EXPRESSION);
+                if (pExprNew)
+                    pExprNew->enmType = VDSCRIPTEXPRTYPE_ASSIGN_LSR;
+                else
+                    rc = vdScriptParserError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Parser: Out of memory allocating expression AST node\n");
+            }
+            else if (vdScriptTokenizerSkipIfIsOperatorEqual(pThis->pTokenizer, "&="))
+            {
+                pExprNew = (PVDSCRIPTASTEXPR)vdScriptAstNodeAlloc(VDSCRIPTASTCLASS_EXPRESSION);
+                if (pExprNew)
+                    pExprNew->enmType = VDSCRIPTEXPRTYPE_ASSIGN_AND;
+                else
+                    rc = vdScriptParserError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Parser: Out of memory allocating expression AST node\n");
+            }
+            else if (vdScriptTokenizerSkipIfIsOperatorEqual(pThis->pTokenizer, "^="))
+            {
+                pExprNew = (PVDSCRIPTASTEXPR)vdScriptAstNodeAlloc(VDSCRIPTASTCLASS_EXPRESSION);
+                if (pExprNew)
+                    pExprNew->enmType = VDSCRIPTEXPRTYPE_ASSIGN_XOR;
+                else
+                    rc = vdScriptParserError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Parser: Out of memory allocating expression AST node\n");
+            }
+            else if (vdScriptTokenizerSkipIfIsOperatorEqual(pThis->pTokenizer, "|="))
+            {
+                pExprNew = (PVDSCRIPTASTEXPR)vdScriptAstNodeAlloc(VDSCRIPTASTCLASS_EXPRESSION);
+                if (pExprNew)
+                    pExprNew->enmType = VDSCRIPTEXPRTYPE_ASSIGN_OR;
+                else
+                    rc = vdScriptParserError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Parser: Out of memory allocating expression AST node\n");
+            }
+            else
+                break;
+
+            pExprNew->BinaryOp.pLeftExpr = pExpr;
+            pExpr = pExprNew;
+            rc = vdScriptParseLogicalOrExpression(pThis, &pExprNew);
+            if (RT_SUCCESS(rc))
+                pExpr->BinaryOp.pRightExpr = pExprNew;
+        }
+
+        if (RT_SUCCESS(rc))
+            *ppAstNodeExpr = pExpr;
+        else
+            vdScriptAstNodeFree(&pExpr->Core);
+    }
+    return rc;
+}
+
+/**
+ * Parse an expression.
+ *
+ * @returns VBox status code.
+ * @param   pThis                The script context.
+ * @param   ppAstNodeExpr        Where to store the expression AST node on success.
+ *
+ * @note Syntax:
+ *      expression:
+ *          assignment-expression
+ *          expression , assignment-expression
  */
 static int vdScriptParseExpression(PVDSCRIPTCTXINT pThis, PVDSCRIPTASTEXPR *ppAstNodeExpr)
 {
-    int rc = VERR_NOT_IMPLEMENTED;
+    int rc = VINF_SUCCESS;
+    PVDSCRIPTASTEXPR pAssignExpr = NULL;
+
+    rc = vdScriptParseAssignmentExpression(pThis, &pAssignExpr);
+    if (   RT_SUCCESS(rc)
+        && vdScriptTokenizerSkipIfIsPunctuatorEqual(pThis->pTokenizer, ','))
+    {
+        PVDSCRIPTASTEXPR pListAssignExpr = (PVDSCRIPTASTEXPR)vdScriptAstNodeAlloc(VDSCRIPTASTCLASS_EXPRESSION);
+        if (pListAssignExpr)
+        {
+            pListAssignExpr->enmType = VDSCRIPTEXPRTYPE_ASSIGNMENT_LIST;
+            RTListInit(&pListAssignExpr->ListExpr);
+            RTListAppend(&pListAssignExpr->ListExpr, &pAssignExpr->Core.ListNode);
+            do
+            {
+                rc = vdScriptParseAssignmentExpression(pThis, &pAssignExpr);
+                if (RT_SUCCESS(rc))
+                    RTListAppend(&pListAssignExpr->ListExpr, &pAssignExpr->Core.ListNode);
+            } while (   RT_SUCCESS(rc)
+                     && vdScriptTokenizerSkipIfIsPunctuatorEqual(pThis->pTokenizer, ','));
+
+            if (RT_FAILURE(rc))
+                vdScriptAstNodeFree(&pListAssignExpr->Core);
+            else
+                *ppAstNodeExpr = pListAssignExpr;
+        }
+        else
+            rc = vdScriptParserError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Parser: Out of memory allocating expression AST node\n");
+    }
+    else if (RT_SUCCESS(rc))
+        *ppAstNodeExpr = pAssignExpr;
+
     return rc;
 }
@@ -1202,5 +2244,5 @@
                     if (RT_SUCCESS(rc))
                         pAstNodeStmt->pStmt = pAstNodeStmtDef;
-                } 
+                }
                 else
                     rc = vdScriptParserError(pThis, VERR_INVALID_PARAMETER, RT_SRC_POS, "Parser: Expected \":\", got ...\n");
@@ -1270,8 +2312,11 @@
             {
                 pAstNodeStmt->enmStmtType = VDSCRIPTSTMTTYPE_RETURN;
-                rc = vdScriptParseExpression(pThis, &pAstNodeStmt->pExpr);
-                if (   RT_SUCCESS(rc)
-                    && !vdScriptTokenizerSkipIfIsPunctuatorEqual(pThis->pTokenizer, ';'))
-                    rc = vdScriptParserError(pThis, VERR_INVALID_PARAMETER, RT_SRC_POS, "Parser: Expected \";\", got ...\n");
+                if (!vdScriptTokenizerSkipIfIsPunctuatorEqual(pThis->pTokenizer, ';'))
+                {
+                    rc = vdScriptParseExpression(pThis, &pAstNodeStmt->pExpr);
+                    if (   RT_SUCCESS(rc)
+                        && !vdScriptTokenizerSkipIfIsPunctuatorEqual(pThis->pTokenizer, ';'))
+                        rc = vdScriptParserError(pThis, VERR_INVALID_PARAMETER, RT_SRC_POS, "Parser: Expected \";\", got ...\n");
+                }
             }
             else
Index: trunk/src/VBox/Storage/testcase/VDScriptAst.cpp
===================================================================
--- trunk/src/VBox/Storage/testcase/VDScriptAst.cpp	(revision 44811)
+++ trunk/src/VBox/Storage/testcase/VDScriptAst.cpp	(revision 44840)
@@ -48,4 +48,6 @@
         case VDSCRIPTASTCLASS_STATEMENT:
             break;
+        case VDSCRIPTASTCLASS_EXPRESSION:
+            break;
         case VDSCRIPTASTCLASS_INVALID:
         default:
@@ -73,4 +75,7 @@
         case VDSCRIPTASTCLASS_STATEMENT:
             cbAlloc = sizeof(VDSCRIPTASTSTMT);
+            break;
+        case VDSCRIPTASTCLASS_EXPRESSION:
+            cbAlloc = sizeof(VDSCRIPTASTEXPR);
             break;
         case VDSCRIPTASTCLASS_IDENTIFIER:
Index: trunk/src/VBox/Storage/testcase/VDScriptAst.h
===================================================================
--- trunk/src/VBox/Storage/testcase/VDScriptAst.h	(revision 44811)
+++ trunk/src/VBox/Storage/testcase/VDScriptAst.h	(revision 44840)
@@ -19,4 +19,19 @@
 
 #include <iprt/list.h>
+
+/**
+ * Position information.
+ */
+typedef struct VDSRCPOS
+{
+    /** Line in the source. */
+    unsigned       iLine;
+    /** Current start character .*/
+    unsigned       iChStart;
+    /** Current end character. */
+    unsigned       iChEnd;
+} VDSRCPOS;
+/** Pointer to a source position. */
+typedef struct VDSRCPOS *PVDSRCPOS;
 
 /**
@@ -55,4 +70,6 @@
     /** List which might be used. */
     RTLISTNODE       ListNode;
+    /** Position in the source file of this node. */
+    VDSRCPOS         Pos;
 } VDSCRIPTASTCORE;
 /** Pointer to an AST core structure. */
@@ -61,4 +78,6 @@
 /** Pointer to an statement node - forward declaration. */
 typedef struct VDSCRIPTASTSTMT *PVDSCRIPTASTSTMT;
+/** Pointer to an expression node - forward declaration. */
+typedef struct VDSCRIPTASTEXPR *PVDSCRIPTASTEXPR;
 
 /**
@@ -90,4 +109,103 @@
 
 /**
+ * Expression types.
+ */
+typedef enum VDSCRIPTEXPRTYPE
+{
+    /** Invalid. */
+    VDSCRIPTEXPRTYPE_INVALID = 0,
+    /** Numerical constant. */
+    VDSCRIPTEXPRTYPE_PRIMARY_NUMCONST,
+    /** String constant. */
+    VDSCRIPTEXPRTYPE_PRIMARY_STRINGCONST,
+    /** Identifier. */
+    VDSCRIPTEXPRTYPE_PRIMARY_IDENTIFIER,
+    /** List of assignment expressions. */
+    VDSCRIPTEXPRTYPE_ASSIGNMENT_LIST,
+    /** Assignment expression. */
+    VDSCRIPTEXPRTYPE_ASSIGNMENT,
+    /** Postfix increment expression. */
+    VDSCRIPTEXPRTYPE_POSTFIX_INCREMENT,
+    /** Postfix decrement expression. */
+    VDSCRIPTEXPRTYPE_POSTFIX_DECREMENT,
+    /** Postfix function call expression. */
+    VDSCRIPTEXPRTYPE_POSTFIX_FNCALL,
+    /** Unary increment expression. */
+    VDSCRIPTEXPRTYPE_UNARY_INCREMENT,
+    /** Unary decrement expression. */
+    VDSCRIPTEXPRTYPE_UNARY_DECREMENT,
+    /** Unary positive sign expression. */
+    VDSCRIPTEXPRTYPE_UNARY_POSSIGN,
+    /** Unary negtive sign expression. */
+    VDSCRIPTEXPRTYPE_UNARY_NEGSIGN,
+    /** Unary invert expression. */
+    VDSCRIPTEXPRTYPE_UNARY_INVERT,
+    /** Unary negate expression. */
+    VDSCRIPTEXPRTYPE_UNARY_NEGATE,
+    /** Multiplicative expression. */
+    VDSCRIPTEXPRTYPE_MULTIPLICATION,
+    /** Division expression. */
+    VDSCRIPTEXPRTYPE_DIVISION,
+    /** Modulus expression. */
+    VDSCRIPTEXPRTYPE_MODULUS,
+    /** Addition expression. */
+    VDSCRIPTEXPRTYPE_ADDITION,
+    /** Subtraction expression. */
+    VDSCRIPTEXPRTYPE_SUBTRACTION,
+    /** Logical shift right. */
+    VDSCRIPTEXPRTYPE_LSR,
+    /** Logical shift left. */
+    VDSCRIPTEXPRTYPE_LSL,
+    /** Lower than expression */
+    VDSCRIPTEXPRTYPE_LOWER,
+    /** Higher than expression */
+    VDSCRIPTEXPRTYPE_HIGHER,
+    /** Lower or equal than expression */
+    VDSCRIPTEXPRTYPE_LOWEREQUAL,
+    /** Higher or equal than expression */
+    VDSCRIPTEXPRTYPE_HIGHEREQUAL,
+    /** Equals expression */
+    VDSCRIPTEXPRTYPE_EQUAL,
+    /** Not equal expression */
+    VDSCRIPTEXPRTYPE_NOTEQUAL,
+    /** Bitwise and expression */
+    VDSCRIPTEXPRTYPE_BITWISE_AND,
+    /** Bitwise xor expression */
+    VDSCRIPTEXPRTYPE_BITWISE_XOR,
+    /** Bitwise or expression */
+    VDSCRIPTEXPRTYPE_BITWISE_OR,
+    /** Logical and expression */
+    VDSCRIPTEXPRTYPE_LOGICAL_AND,
+    /** Logical or expression */
+    VDSCRIPTEXPRTYPE_LOGICAL_OR,
+    /** Assign expression */
+    VDSCRIPTEXPRTYPE_ASSIGN,
+    /** Multiplicative assign expression */
+    VDSCRIPTEXPRTYPE_ASSIGN_MULT,
+    /** Division assign expression */
+    VDSCRIPTEXPRTYPE_ASSIGN_DIV,
+    /** Modulus assign expression */
+    VDSCRIPTEXPRTYPE_ASSIGN_MOD,
+    /** Additive assign expression */
+    VDSCRIPTEXPRTYPE_ASSIGN_ADD,
+    /** Subtractive assign expression */
+    VDSCRIPTEXPRTYPE_ASSIGN_SUB,
+    /** Bitwise left shift assign expression */
+    VDSCRIPTEXPRTYPE_ASSIGN_LSL,
+    /** Bitwise right shift assign expression */
+    VDSCRIPTEXPRTYPE_ASSIGN_LSR,
+    /** Bitwise and assign expression */
+    VDSCRIPTEXPRTYPE_ASSIGN_AND,
+    /** Bitwise xor assign expression */
+    VDSCRIPTEXPRTYPE_ASSIGN_XOR,
+    /** Bitwise or assign expression */
+    VDSCRIPTEXPRTYPE_ASSIGN_OR,
+    /** 32bit hack. */
+    VDSCRIPTEXPRTYPE_32BIT_HACK = 0x7fffffff
+} VDSCRIPTEXPRTYPE;
+/** Pointer to an expression type. */
+typedef VDSCRIPTEXPRTYPE *PVDSCRIPTEXPRTYPE;
+
+/**
  * AST expression node.
  */
@@ -96,9 +214,37 @@
     /** Core structure. */
     VDSCRIPTASTCORE    Core;
-    /** @todo */
-    unsigned           uDummy;
+    /** Expression type. */
+    VDSCRIPTEXPRTYPE   enmType;
+    /** Expression type dependent data. */
+    union
+    {
+        /** Numerical constant. */
+        uint64_t          u64;
+        /** Primary identifier. */
+        PVDSCRIPTASTIDE   pIde;
+        /** String literal */
+        const char       *pszStr;
+        /** List of expressions - VDSCRIPTASTEXPR. */
+        RTLISTANCHOR      ListExpr;
+        /** Pointer to another expression. */
+        PVDSCRIPTASTEXPR  pExpr;
+        /** Function call expression. */
+        struct
+        {
+            /** Other postfix expression used as the identifier for the function. */
+            PVDSCRIPTASTEXPR pFnIde;
+            /** Argument list if existing. */
+            RTLISTANCHOR     ListArgs;
+        } FnCall;
+        /** Binary operation. */
+        struct
+        {
+            /** Left operator. */
+            PVDSCRIPTASTEXPR pLeftExpr;
+            /** Right operator. */
+            PVDSCRIPTASTEXPR pRightExpr;
+        } BinaryOp;
+    };
 } VDSCRIPTASTEXPR;
-/** Pointer to an expression node. */
-typedef VDSCRIPTASTEXPR *PVDSCRIPTASTEXPR;
 
 /**
