#include #include #include #include "../global/macros.h" #include "../tokenizer/tokenizer.h" #include "parser.h" #define PDEBUG /********************************** * Global variables. **********************************/ char stream[] = "identifier(arg1, arg2, ...) => do: \n\twhile:\n\t;\n;\ntest = 1+2+3+!x\nmoo => 1*(5/6)"; SwSymbol prev_symbol = 0; SwToken *token = NULL; SwTokenBuffer *buffer = NULL; SwOperator *operators[70]; /********************************** * Deal with tokens. **********************************/ int get_symbol(void) { advance(); if(token) /* store the prev symbol. */ prev_symbol = token->symbol; return next_token(buffer) != NULL ? 1 : 0; } int accept(SwSymbol sy) { advance(); if(token->symbol == sy) { get_symbol(); advance(); return 1; } return 0; } /* Try to accept an operator. */ int accept_xfix(SwOperatorType type) { advance(); SwOperator *op = operators[token->symbol]; if(op != NULL && op->where == type) { expect(token->symbol); return 1; } return 0; } void expect(SwSymbol sy) { PDEBUG printf("\tExpecting token [%d]\n", sy); if(accept(sy)) { PDEBUG printf("\t\tFound token [%d]\n", sy); return; } PARSE_ERROR("Unexpected token found.\n"); } void advance(void) { token = current_token(buffer); } /********************************** * Symbols. **********************************/ void clear_operators(void) { int i = 0; //if(!(operators = (SwOperator **)malloc(sizeof(SwOperator *) * 70))) // FATAL_ERROR("Could not allocate space for operators."); for(; i < 70; i++) { operators[i] = NULL; } } void add_operator(SwSymbol sy, SwOperatorType type, int bind_left, int bind_right) { SwOperator *o; int tk = sy; PDEBUG printf("Adding operator [%d]\n", tk); if(operators[tk] == NULL) { if(!(o = (SwOperator *)malloc(sizeof(SwOperator)))) FATAL_ERROR("Could not allocate operator for symbol table."); o->symbol = sy; o->where = type; o->bind_left = bind_left; o->bind_right = bind_right; operators[tk] = o; } return; } /********************************** * Parsing functions! **********************************/ /* Parse function arguments. Deals with function definitions and function calls in slightly different ways. */ void function_args(int def) { PDEBUG printf("\tParsing function arguments... \n"); int more_args_allowed = 1; do { /* Named argument. */ if(accept(SW_TOKEN_IDENTIFIER)) ; /* Simple argument with default value. */ else if(accept(SW_TOKEN_IDENT_DEF)) { expect(SW_TOKEN_SET); def ? term() : expression(); /* function arguments can be specified to be accepted as procedures. This type of argument is extremely useful when you don't want it to be evaluated before being passed in. */ } else if(accept(SW_TOKEN_IDENT_DEF_PROC)) { expect(SW_TOKEN_PROCEDURE); def ? term() : expression(); /* The more args symbol '...' must be at the end of the list. */ } else if(accept(SW_TOKEN_MORE_ARGS)) { if(!def) PARSE_ERROR("Unexpected '...' found. This symbol is only \ allowed in function definitions."); more_args_allowed = 0; } } while(more_args_allowed && accept(SW_TOKEN_COMMA)); expect(SW_TOKEN_PAREN_CLOSE); /* Check for function calls returning functions (which are then being called). */ if(!def) { if(accept(SW_TOKEN_PAREN_OPEN)) function_args(0); } } /* Lambda funciton, call-only, not allowed to set a variable to the actual lambda function itself. */ void lambda(void) { PDEBUG printf("Parsing lambda expression... \n"); expect(SW_TOKEN_PAREN_OPEN); function_args(1); expect(SW_TOKEN_PROCEDURE); /* lambdas are define-only */ procedure(); } /* Parse a procedure */ void procedure(void) { PDEBUG printf("\tParsing procedure... \n"); if(accept(SW_TOKEN_PROCEDURE)) /* procedure in a procedure */ procedure(); else if(accept(SW_TOKEN_SET)) /* possible typo by programmer */ PARSE_ERROR("Expected '=>' or after '=>' but found '='."); else statement(); } /* Parse a dictionary */ void dictionary(void) { PDEBUG printf("Parsing dictionary definition... \n"); do { expect(SW_TOKEN_STRING_LITERAL); expect(SW_TOKEN_COLON); term(); } while(accept(SW_TOKEN_COMMA)); expect(SW_TOKEN_BRACE_CLOSE); } /* Parse a list */ void list(void) { PDEBUG printf("Parsing list definition... \n"); do { term(); /* a range in a list */ if(accept(SW_TOKEN_TO)) { /* [term to term] */ term(); break; } } while(accept(SW_TOKEN_COMMA)); expect(SW_TOKEN_BRACKET_CLOSE); } /* Index or slice on a list/dict/string. */ void index_or_slice(int allow_multi) { PDEBUG printf("\tFound index or slice \n"); term(); if(accept(SW_TOKEN_COLON)) { /* array slice, [x:y] */ PDEBUG printf("\t\tIt was a slice.\n"); term(); } expect(SW_TOKEN_BRACKET_CLOSE); if(accept(SW_TOKEN_BRACKET_OPEN)) { /* another list index, recurse */ if(!allow_multi) PARSE_ERROR("Unexpected index accesor or slice found on non multi\ -dimension list."); index_or_slice(allow_multi); } } /* The core types are allowed to be accessed directly as functions, eg: "moo"() 123() 12.34() */ void try_type_as_function(void) { if(accept(SW_TOKEN_PAREN_OPEN)) { PDEBUG printf("Found function call on literal, parsing arguments...\n"); function_args(0); } } void factor(void) { /* debugging */ advance(); char *val = token->value; printf("value: %s\n", val); /* deal with unary +/- */ if(accept(SW_TOKEN_ADD) || accept(SW_TOKEN_SUBTRACT)) { advance(); PDEBUG printf("\tFound unary +/-\n"); token->symbol = token->symbol == SW_TOKEN_ADD ? SW_TOKEN_POSITIVE : \ SW_TOKEN_NEGATIVE; factor(); /* identifiers */ } else if(accept(SW_TOKEN_IDENTIFIER)) { PDEBUG printf("\tFound identifier [%s] \n", val); if(accept(SW_TOKEN_PAREN_OPEN)) { /* function call */ function_args(0); if(accept(SW_TOKEN_COLON)) { /* macro call */ block(); } } else if(accept(SW_TOKEN_BRACKET_OPEN)) /* array index/slice */ index_or_slice(1); /* integer literals */ } else if(accept(SW_TOKEN_INTEGER)) { PDEBUG printf("\tFound integer literal [%s] \n", val); try_type_as_function(); /* floating-point literals */ } else if(accept(SW_TOKEN_FLOAT)) { PDEBUG printf("\tFOund floating-point literal [%s] \n", val); try_type_as_function(); /* string literals */ } else if(accept(SW_TOKEN_STRING_LITERAL)) { PDEBUG printf("\tFound string literal [\"%s\"] \n", val); try_type_as_function(); if(accept(SW_TOKEN_BRACKET_OPEN)) { /* allow direct access/slices on string literals. */ index_or_slice(0); } /* booleans */ } else if(accept(SW_TOKEN_BOOL_TRUE) || accept(SW_TOKEN_BOOL_FALSE)) { PDEBUG printf("\tFound boolean literal [true/false]\n"); try_type_as_function(); } else if(accept(SW_TOKEN_NULL)) { PDEBUG printf("\tFound null literal \n"); try_type_as_function(); /* sub expression */ } else if(accept(SW_TOKEN_PAREN_OPEN)) { expression(); expect(SW_TOKEN_PAREN_CLOSE); } else if(accept(SW_TOKEN_BRACE_OPEN)) { dictionary(); } else if(accept(SW_TOKEN_BRACKET_OPEN)) { list(); } } void term(void) { factor(); } void rest_of_expression(void) { while(accept_xfix(SW_INFIX)) { while(accept_xfix(SW_PREFIX)) /* eg: you can have: !!x */ ; term(); } statement(); } void expression(void) { PDEBUG printf("Parsing expression... \n"); if(accept(SW_TOKEN_LAMBDA)) { lambda(); } term(); PDEBUG printf("Parsing rest of expression...\n"); rest_of_expression(); } void block(void) { PDEBUG printf(" \n"); statement(); expect(SW_TOKEN_SEMICOLON); PDEBUG printf("\n"); statement(); } /* Deal with implicit returns in functions/procedures. We will only do this if the previous symbol was a => */ void check_implicit_return(void) { if(prev_symbol == SW_TOKEN_PROCEDURE) expression(); } void statement(void) { advance(); printf("statement\n"); PDEBUG printf("\tFound token [%d], value [%s]\n", token->symbol, token->value); if(accept(SW_TOKEN_IDENTIFIER) || accept(SW_TOKEN_LAMBDA)) { if(accept(SW_TOKEN_PAREN_OPEN)) { /* func call */ function_args(0); if(accept(SW_TOKEN_PROCEDURE)) /* func def */ PARSE_ERROR("Unexpected function definition."); else if(accept(SW_TOKEN_COLON)) /* macro call */ block(); } else if(accept(SW_TOKEN_BRACKET_OPEN)) expression(); else if(accept(SW_TOKEN_COLON)) /* macro call, no args */ block(); else if(accept(SW_TOKEN_SET)) goto identifier_set; else if(accept(SW_TOKEN_PROCEDURE)) goto procedure_set; } else if(accept(SW_TOKEN_FUNC_DEF)) { PDEBUG printf("\t\tStatement is function definition \n"); expect(SW_TOKEN_PAREN_OPEN); function_args(1); expect(SW_TOKEN_PROCEDURE); procedure(); } else if(accept(SW_TOKEN_IDENT_DEF)) { expect(SW_TOKEN_SET); identifier_set: PDEBUG printf("\t\tStatement is identifier definition \n"); expression(); /* Found a =>, send it off to the procedure function */ } else if(accept(SW_TOKEN_IDENT_DEF_PROC)) { expect(SW_TOKEN_PROCEDURE); procedure_set: PDEBUG printf("\t\tStatement is procedure definition \n"); procedure(); /* Found a lambda */ } else if(accept(SW_TOKEN_LAMBDA)) { lambda(); /* Likely in an implicitly returning procedure, statement can't handle that. What we want is a way to make it explicit. */ } else { check_implicit_return(); } } int main() { printf("\n\nTesting Swerve parser...\n"); printf("---------------\n"); printf("buffer to parse: \n%s\n\n", stream); clear_operators(); add_operator(SW_TOKEN_NOT, SW_PREFIX, 1, 10); add_operator(SW_TOKEN_POSITIVE, SW_PREFIX, 1, 10); add_operator(SW_TOKEN_NEGATIVE, SW_PREFIX, 1, 10); add_operator(SW_TOKEN_ADD, SW_INFIX, 4, 4); add_operator(SW_TOKEN_SUBTRACT, SW_INFIX, 4, 4); add_operator(SW_TOKEN_DIVIDE, SW_INFIX, 5, 5); add_operator(SW_TOKEN_MODULO, SW_INFIX, 5, 5); add_operator(SW_TOKEN_MULTIPLY, SW_INFIX, 6, 6); add_operator(SW_TOKEN_EXPONENT, SW_INFIX, 6, 7); add_operator(SW_TOKEN_BIT_OR, SW_INFIX, 3, 3); add_operator(SW_TOKEN_BIT_XOR, SW_INFIX, 3, 3); add_operator(SW_TOKEN_BIT_AND, SW_INFIX, 3, 3); add_operator(SW_TOKEN_BIT_LSHIFT, SW_INFIX, 5, 4); add_operator(SW_TOKEN_BIT_RSHIFT, SW_INFIX, 4, 5); add_operator(SW_TOKEN_BIT_COMPLEMENT, SW_INFIX, 3, 3); add_operator(SW_TOKEN_IS, SW_INFIX, 2, 2); add_operator(SW_TOKEN_IN, SW_INFIX, 2, 2); add_operator(SW_TOKEN_TO, SW_INFIX, 5, 5); add_operator(SW_TOKEN_EQUALS, SW_INFIX, 2, 2); add_operator(SW_TOKEN_NOT_EQUALS, SW_INFIX, 2, 2); add_operator(SW_TOKEN_LOGICAL_AND, SW_INFIX, 1, 1); add_operator(SW_TOKEN_LOGICAL_OR, SW_INFIX, 0, 0); add_operator(SW_TOKEN_LOGICAL_XOR, SW_INFIX, 0, 0); add_operator(SW_TOKEN_LT, SW_INFIX, 4, 4); add_operator(SW_TOKEN_GT, SW_INFIX, 4, 4); add_operator(SW_TOKEN_LT_EQUAL, SW_INFIX, 4, 4); add_operator(SW_TOKEN_GT_EQUAL, SW_INFIX, 4, 4); //add_operator(SW_TOKEN_RANGE, SW_INFIX, 9, 9); buffer = init_tokenizer(stream); PDEBUG printf("\n"); get_symbol(); statement(); PDEBUG printf("\n"); disable_tokenizer(buffer); return 0; }