engine/source/preprocessorlib/pp_expr.c
/**
 * Constructs an abstract syntax tree from the rest of the remaining line of
 * the parser.  The returned pointer should be freed with pp_expr_destroy()
 * when it's no longer needed.
 *
 * @param parser the parser to get the token stream from
 * @param paren true if parsing a parenthetical expression, false otherwise
 * @return the tree constructed from the input, or NULL on error
 */
Constructs an abstract syntax tree from the rest of the remaining line of
the parser.  The returned pointer should be freed with pp_expr_destroy()
when it's no longer needed.

@param parser the parser to get the token stream from
@param paren true if parsing a parenthetical expression, false otherwise
@return the tree constructed from the input, or NULL on error
Constructs an abstract syntax tree from the rest of the remaining line of the parser . The returned pointer should be freed with pp_expr_destroy () when it ' s no longer needed . @param parser the parser to get the token stream from @param paren true if parsing a parenthetical expression false otherwise @return the tree constructed from the input or NULL on error
pp_expr *pp_expr_parse(pp_parser *parser, bool paren)
{
    pp_expr *root = malloc(sizeof(pp_expr));
    pp_expr *current = root;
    pp_expr *previous = NULL;
    pp_expr *leftleaf = NULL;
    nodedata *currentdata = NULL;
    pp_token *token;
    memset(root, 0, sizeof(pp_expr));
    do
    {
        int type;
        token = pp_parser_emit_token(parser);
        type = tokentype(token->theType);
        if(type == MULTI)
        {
            if(!leftleaf)
            {
                type = UNARY;
            }
            else
            {
                pp_expr *bottomnode = leftleaf;
                while(bottomnode && bottomnode->left)
                {
                    bottomnode = bottomnode->left;
                }
                type = (bottomnode->info->type == LEAF) ? BINARY : UNARY;
            }
        }
        currentdata = malloc(sizeof(nodedata));
        memcpy(&currentdata->theToken, token, sizeof(pp_token));
        currentdata->type = type;
        if(token->theType == PP_TOKEN_EOF || token->theType == PP_TOKEN_RPAREN)
        {
            if (token->theType == PP_TOKEN_RPAREN && (!paren || !leftleaf))
            {
                if(paren)
                {
                    pp_error(parser, "no expression between '(' and ')'");
                }
                else
                {
                    pp_error(parser, "')' without matching '('");
                }
                goto error;
            }
            else if (token->theType == PP_TOKEN_EOF && (paren || !leftleaf))
            {
                if(paren)
                {
                    pp_error(parser, "expected ')' before end of conditional expression");
                }
                else
                {
                    pp_error(parser, "#if with no expression");
                }
                goto error;
            }
            pp_expr_init(current, currentdata, leftleaf, NULL);
            if(previous)
            {
                previous->right = current;
            }
            currentdata = NULL;
            break;
        }
        else if(token->theType == PP_TOKEN_WHITESPACE ||
                token->theType == PP_TOKEN_NEWLINE) 
        {
            free(currentdata);
            currentdata = NULL;
        }
        else if(type == LEAF || type == UNARY)
        {
            pp_expr *treedata;
            pp_expr *bottomnode = leftleaf;
            pp_expr *subtree = NULL;
            if(leftleaf)
                while(bottomnode->left)
                {
                    bottomnode = bottomnode->left;
                }
            if(leftleaf && bottomnode->info->type != UNARY)
            {
                pp_error(parser, "expected an operator, got '%s'", token->theSource);
                goto error;
            }
            if(token->theType == PP_TOKEN_LPAREN)
            {
                subtree = pp_expr_parse(parser, true);
                if(subtree == NULL)
                {
                    goto error;
                }
            }
            else if(token->theType == PP_TOKEN_DEFINED)
            {
                int lparen = 0;
                pp_parser_lex_token(parser, true);
                if(parser->token.theType == PP_TOKEN_LPAREN)
                {
                    lparen = 1;
                    pp_parser_lex_token(parser, true);
                }
                if(parser->token.theType != PP_TOKEN_IDENTIFIER)
                {
                    pp_error(parser, "bad 'defined' syntax");
                    goto error;
                }
                currentdata->theToken.theType = PP_TOKEN_INTCONSTANT;
                strcpy(currentdata->theToken.theSource,
                       pp_parser_is_defined(parser, parser->token.theSource) ? "1" : "0");
                if(lparen)
                {
                    pp_parser_lex_token(parser, true);
                    if(parser->token.theType != PP_TOKEN_RPAREN)
                    {
                        pp_error(parser, "bad 'defined' syntax");
                        goto error;
                    }
                }
            }
            treedata = malloc(sizeof(pp_expr));
            pp_expr_init(treedata, currentdata, subtree, NULL);
            currentdata = NULL;
            if(leftleaf)
            {
                bottomnode->left = treedata;
            }
            else
            {
                leftleaf = treedata;
            }
        }
        else if(type == BINARY)
        {
            if(!leftleaf)
            {
                pp_error(parser, "expected an operand, got '%s'", token->theSource);
                goto error;
            }
            pp_expr_init(current, currentdata, leftleaf, NULL);
            leftleaf = NULL;
            currentdata = NULL;
            if(previous)
            {
                previous->right = current;
            }
            previous = current;
            current = malloc(sizeof(pp_expr));
#if LEXTREE_DEBUG
            printf("%s %s\n", previous->left->info->theToken.theSource, token->theSource);
#endif
        }
        else
        {
            pp_error(parser, "'%s' is not a valid token in an #if/#elif condition\n",
                     token->theSource);
            goto error;
        }
    }
    while(1);
    return root;
error:
    if(root->info)
    {
        pp_expr_destroy(root);
    }
    if(leftleaf)
    {
        pp_expr_destroy(leftleaf);
    }
    if(current != root)
    {
        free(current);
    }
    if(currentdata)
    {
        free(currentdata);
    }
    return NULL;
}
pp_expr * pp_expr_parse ( pp_parser * parser , bool paren ) { pp_expr * root = malloc ( sizeof ( pp_expr ) ) ; pp_expr * current = root ; pp_expr * previous = NULL ; pp_expr * leftleaf = NULL ; nodedata * currentdata = NULL ; pp_token * token ; memset ( root , 0 , sizeof ( pp_expr ) ) ; do { int type ; token = pp_parser_emit_token ( parser ) ; type = tokentype ( token -> theType ) ; if ( type == MULTI ) { if ( ! leftleaf ) { type = UNARY ; } else { pp_expr * bottomnode = leftleaf ; while ( bottomnode && bottomnode -> left ) { bottomnode = bottomnode -> left ; } type = ( bottomnode -> info -> type == LEAF ) ? BINARY : UNARY ; } } currentdata = malloc ( sizeof ( nodedata ) ) ; memcpy ( & currentdata -> theToken , token , sizeof ( pp_token ) ) ; currentdata -> type = type ; if ( token -> theType == PP_TOKEN_EOF || token -> theType == PP_TOKEN_RPAREN ) { if ( token -> theType == PP_TOKEN_RPAREN && ( ! paren || ! leftleaf ) ) { if ( paren ) { pp_error ( parser , " " ) ; } else { pp_error ( parser , " " ) ; } goto error ; } else if ( token -> theType == PP_TOKEN_EOF && ( paren || ! leftleaf ) ) { if ( paren ) { pp_error ( parser , " " ) ; } else { pp_error ( parser , " " ) ; } goto error ; } pp_expr_init ( current , currentdata , leftleaf , NULL ) ; if ( previous ) { previous -> right = current ; } currentdata = NULL ; break ; } else if ( token -> theType == PP_TOKEN_WHITESPACE || token -> theType == PP_TOKEN_NEWLINE ) { free ( currentdata ) ; currentdata = NULL ; } else if ( type == LEAF || type == UNARY ) { pp_expr * treedata ; pp_expr * bottomnode = leftleaf ; pp_expr * subtree = NULL ; if ( leftleaf ) while ( bottomnode -> left ) { bottomnode = bottomnode -> left ; } if ( leftleaf && bottomnode -> info -> type != UNARY ) { pp_error ( parser , " " , token -> theSource ) ; goto error ; } if ( token -> theType == PP_TOKEN_LPAREN ) { subtree = pp_expr_parse ( parser , true ) ; if ( subtree == NULL ) { goto error ; } } else if ( token -> theType == PP_TOKEN_DEFINED ) { int lparen = 0 ; pp_parser_lex_token ( parser , true ) ; if ( parser -> token . theType == PP_TOKEN_LPAREN ) { lparen = 1 ; pp_parser_lex_token ( parser , true ) ; } if ( parser -> token . theType != PP_TOKEN_IDENTIFIER ) { pp_error ( parser , " " ) ; goto error ; } currentdata -> theToken . theType = PP_TOKEN_INTCONSTANT ; strcpy ( currentdata -> theToken . theSource , pp_parser_is_defined ( parser , parser -> token . theSource ) ? " " : " " ) ; if ( lparen ) { pp_parser_lex_token ( parser , true ) ; if ( parser -> token . theType != PP_TOKEN_RPAREN ) { pp_error ( parser , " " ) ; goto error ; } } } treedata = malloc ( sizeof ( pp_expr ) ) ; pp_expr_init ( treedata , currentdata , subtree , NULL ) ; currentdata = NULL ; if ( leftleaf ) { bottomnode -> left = treedata ; } else { leftleaf = treedata ; } } else if ( type == BINARY ) { if ( ! leftleaf ) { pp_error ( parser , " " , token -> theSource ) ; goto error ; } pp_expr_init ( current , currentdata , leftleaf , NULL ) ; leftleaf = NULL ; currentdata = NULL ; if ( previous ) { previous -> right = current ; } previous = current ; current = malloc ( sizeof ( pp_expr ) ) ; #if LEXTREE_DEBUG printf ( " \n " , previous -> left -> info -> theToken . theSource , token -> theSource ) ; #endif } else { pp_error ( parser , " \n " , token -> theSource ) ; goto error ; } } while ( 1 ) ; return root ; error : if ( root -> info ) { pp_expr_destroy ( root ) ; } if ( leftleaf ) { pp_expr_destroy ( leftleaf ) ; } if ( current != root ) { free ( current ) ; } if ( currentdata ) { free ( currentdata ) ; } return NULL ; }
Constructs an abstract syntax tree from the rest of the remaining line of
 the parser.
Constructs an abstract syntax tree from the rest of the remaining line of the parser .
// determine whether a MULTI operator is being used as unary or binary // skip over whitespace // find the bottom of the left tree (there can be any number of unary operators stacked there) // insert at the bottom of the left tree