📄 slparse.c
字号:
/* Copyright (c) 1998, 1999, 2001, 2002, 2003 John E. Davis * This file is part of the S-Lang library. * * You may distribute under the terms of either the GNU General Public * License or the Perl Artistic License. */#include "slinclud.h"#include "slang.h"#include "_slang.h"static SLang_Load_Type *LLT;int _SLang_Compile_Line_Num_Info;static void free_token (_SLang_Token_Type *t){ register unsigned int nrefs = t->num_refs; if (nrefs == 0) return; if (nrefs == 1) { if (t->free_sval_flag) { if (t->type == BSTRING_TOKEN) SLbstring_free (t->v.b_val); else _SLfree_hashed_string (t->v.s_val, strlen (t->v.s_val), t->hash); t->v.s_val = NULL; } } t->num_refs = nrefs - 1;}static void init_token (_SLang_Token_Type *t){ memset ((char *) t, 0, sizeof (_SLang_Token_Type));#if _SLANG_HAS_DEBUG_CODE t->line_number = -1;#endif}/* Allow room for one push back of a token. This is necessary for * multiple assignment. */static unsigned int Use_Next_Token;static _SLang_Token_Type Next_Token;#if _SLANG_HAS_DEBUG_CODEstatic int Last_Line_Number = -1;#endifstatic int unget_token (_SLang_Token_Type *ctok){ if (SLang_Error) return -1; if (Use_Next_Token != 0) { _SLparse_error ("unget_token failed", ctok, 0); return -1; } Use_Next_Token++; Next_Token = *ctok; init_token (ctok); return 0;}static int get_token (_SLang_Token_Type *ctok){ if (ctok->num_refs) free_token (ctok); if (Use_Next_Token) { Use_Next_Token--; *ctok = Next_Token; return ctok->type; } return _SLget_token (ctok);}static int compile_token (_SLang_Token_Type *t){#if _SLANG_HAS_DEBUG_CODE if (_SLang_Compile_Line_Num_Info && (t->line_number != Last_Line_Number) && (t->line_number != -1)) { _SLang_Token_Type tok; tok.type = LINE_NUM_TOKEN; tok.v.long_val = Last_Line_Number = t->line_number; (*_SLcompile_ptr) (&tok); }#endif (*_SLcompile_ptr) (t); return 0;}typedef struct{#define USE_PARANOID_MAGIC 0#if USE_PARANOID_MAGIC unsigned long magic;#endif _SLang_Token_Type *stack; unsigned int len; unsigned int size;}Token_List_Type;#define MAX_TOKEN_LISTS 16static Token_List_Type Token_List_Stack [MAX_TOKEN_LISTS];static unsigned int Token_List_Stack_Depth = 0;static Token_List_Type *Token_List = NULL;static void init_token_list (Token_List_Type *t){ t->size = 0; t->len = 0; t->stack = NULL;#if USE_PARANOID_MAGIC t->magic = 0xABCDEF12;#endif}static void free_token_list (Token_List_Type *t){ _SLang_Token_Type *s; if (t == NULL) return;#if USE_PARANOID_MAGIC if (t->magic != 0xABCDEF12) { SLang_doerror ("Magic error."); return; }#endif s = t->stack; if (s != NULL) { _SLang_Token_Type *smax = s + t->len; while (s != smax) { if (s->num_refs) free_token (s); s++; } SLfree ((char *) t->stack); } memset ((char *) t, 0, sizeof (Token_List_Type));}static Token_List_Type *push_token_list (void){ if (Token_List_Stack_Depth == MAX_TOKEN_LISTS) { _SLparse_error ("Token list stack size exceeded", NULL, 0); return NULL; } Token_List = Token_List_Stack + Token_List_Stack_Depth; Token_List_Stack_Depth++; init_token_list (Token_List); return Token_List;}static int pop_token_list (int do_free){ if (Token_List_Stack_Depth == 0) { if (SLang_Error == 0) _SLparse_error ("Token list stack underflow", NULL, 0); return -1; } Token_List_Stack_Depth--; if (do_free) free_token_list (Token_List); if (Token_List_Stack_Depth != 0) Token_List = Token_List_Stack + (Token_List_Stack_Depth - 1); else Token_List = NULL; return 0;}static int check_token_list_space (Token_List_Type *t, unsigned int delta_size){ _SLang_Token_Type *st; unsigned int len;#if USE_PARANOID_MAGIC if (t->magic != 0xABCDEF12) { SLang_doerror ("Magic error."); return -1; }#endif len = t->len + delta_size; if (len <= t->size) return 0; if (delta_size < 4) { delta_size = 4; len = t->len + delta_size; } st = (_SLang_Token_Type *) SLrealloc((char *) t->stack, len * sizeof(_SLang_Token_Type)); if (st == NULL) { _SLparse_error ("Malloc error", NULL, 0); return -1; } memset ((char *) (st + t->len), 0, delta_size); t->stack = st; t->size = len; return 0;}static int append_token (_SLang_Token_Type *t){ if (-1 == check_token_list_space (Token_List, 1)) return -1; Token_List->stack [Token_List->len] = *t; Token_List->len += 1; t->num_refs = 0; /* stealing it */ return 0;}static int append_token_of_type (unsigned char t){ _SLang_Token_Type *tok; if (-1 == check_token_list_space (Token_List, 1)) return -1; /* The memset when the list was created ensures that the other fields * are properly initialized. */ tok = Token_List->stack + Token_List->len; init_token (tok); tok->type = t; Token_List->len += 1; return 0;}static _SLang_Token_Type *get_last_token (void){ unsigned int len; if ((Token_List == NULL) || (0 == (len = Token_List->len))) return NULL; len--; return Token_List->stack + len;}/* This function does NOT free the list. */static int compile_token_list_with_fun (int dir, Token_List_Type *list, int (*f)(_SLang_Token_Type *)){ _SLang_Token_Type *t0, *t1; if (list == NULL) return -1; if (f == NULL) f = compile_token; t0 = list->stack; t1 = t0 + list->len; if (dir < 0) { /* backwards */ while ((SLang_Error == 0) && (t1 > t0)) { t1--; (*f) (t1); } return 0; } /* forward */ while ((SLang_Error == 0) && (t0 < t1)) { (*f) (t0); t0++; } return 0;}static int compile_token_list (void){ if (Token_List == NULL) return -1; compile_token_list_with_fun (1, Token_List, NULL); pop_token_list (1); return 0;}/* Take all elements in the list from pos2 to the end and exchange them * with the elements at pos1, e.g., * ...ABCDEabc ==> ...abcABCDE * where pos1 denotes A and pos2 denotes a. */static int token_list_element_exchange (unsigned int pos1, unsigned int pos2){ _SLang_Token_Type *s, *s1, *s2; unsigned int len, nloops; if (Token_List == NULL) return -1; s = Token_List->stack; len = Token_List->len; if ((s == NULL) || (len == 0) || (pos2 >= len)) return -1; /* This may not be the most efficient algorithm but the number to swap * is most-likely going to be small, e.g, 3 * The algorithm is to rotate the list. The particular rotation * direction was chosen to make insert_token fast. * It works like: * @ ABCabcde --> BCabcdeA --> CabcdeAB --> abcdefAB * which is optimal for Abcdef sequence produced by function calls. * * Profiling indicates that nloops is almost always 1, whereas the inner * loop can loop many times (e.g., 9 times). */ s2 = s + (len - 1); s1 = s + pos1; nloops = pos2 - pos1; while (nloops) { _SLang_Token_Type save; s = s1; save = *s; while (s < s2) { *s = *(s + 1); s++; } *s = save; nloops--; } return 0;}#if 0static int insert_token (_SLang_Token_Type *t, unsigned int pos){ if (-1 == append_token (t)) return -1; return token_list_element_exchange (pos, Token_List->len - 1);}#endifstatic void compile_token_of_type (unsigned char t){ _SLang_Token_Type tok;#if _SLANG_HAS_DEBUG_CODE tok.line_number = -1;#endif tok.type = t; compile_token(&tok);}static void statement (_SLang_Token_Type *);static void compound_statement (_SLang_Token_Type *);static void expression_with_parenthesis (_SLang_Token_Type *);static void handle_semicolon (_SLang_Token_Type *);static void statement_list (_SLang_Token_Type *);static void variable_list (_SLang_Token_Type *, unsigned char);static void struct_declaration (_SLang_Token_Type *);static void define_function_args (_SLang_Token_Type *);static void typedef_definition (_SLang_Token_Type *);static void function_args_expression (_SLang_Token_Type *, int);static void expression (_SLang_Token_Type *);static void expression_with_commas (_SLang_Token_Type *, int);static void simple_expression (_SLang_Token_Type *);static void unary_expression (_SLang_Token_Type *);static void postfix_expression (_SLang_Token_Type *);static int check_for_lvalue (unsigned char, _SLang_Token_Type *);/* static void primary_expression (_SLang_Token_Type *); */static void block (_SLang_Token_Type *);static void inline_array_expression (_SLang_Token_Type *);static void array_index_expression (_SLang_Token_Type *);static void do_multiple_assignment (_SLang_Token_Type *);static void try_multiple_assignment (_SLang_Token_Type *);#if 0static void not_implemented (char *what){ char err [256]; sprintf (err, "Expression not implemented: %s", what); _SLparse_error (err, NULL, 0);}#endifstatic void rpn_parse_line (_SLang_Token_Type *tok){ do { /* multiple RPN tokens possible when the file looks like: * . <end of line> * . <end of line> */ if (tok->type != RPN_TOKEN) compile_token (tok); free_token (tok); } while (EOF_TOKEN != _SLget_rpn_token (tok));}static int get_identifier_token (_SLang_Token_Type *tok){ if (IDENT_TOKEN == get_token (tok)) return IDENT_TOKEN; _SLparse_error ("Expecting identifier", tok, 0); return tok->type;}static void define_function (_SLang_Token_Type *ctok, unsigned char type){ _SLang_Token_Type fname; switch (type) { case STATIC_TOKEN: type = DEFINE_STATIC_TOKEN; break; case PUBLIC_TOKEN: type = DEFINE_PUBLIC_TOKEN; break; case PRIVATE_TOKEN: type = DEFINE_PRIVATE_TOKEN; } init_token (&fname); if (IDENT_TOKEN != get_identifier_token (&fname)) { free_token (&fname); return; } compile_token_of_type(OPAREN_TOKEN); get_token (ctok); define_function_args (ctok); compile_token_of_type(FARG_TOKEN); if (ctok->type == OBRACE_TOKEN) compound_statement(ctok); else if (ctok->type != SEMICOLON_TOKEN) { _SLparse_error("Expecting {", ctok, 0); free_token (&fname); return; } fname.type = type; compile_token (&fname); free_token (&fname);}/* statement: * compound-statement * if ( expression ) statement * if ( expression ) statement else statement * !if ( expression ) statement * loop ( expression ) statement * _for ( expression ) statement * foreach ( expression ) statement * foreach (expression ) using (expression-list) statement * while ( expression ) statement * do statement while (expression) ; * for ( expressionopt ; expressionopt ; expressionopt ) statement * ERROR_BLOCK statement * EXIT_BLOCK statement * USER_BLOCK0 statement * USER_BLOCK1 statement * USER_BLOCK2 statement * USER_BLOCK3 statement * USER_BLOCK4 statement * forever statement * break ; * continue ; * return expressionopt ; * variable variable-list ; * struct struct-decl ; * define identifier function-args ; * define identifier function-args compound-statement * switch ( expression ) statement * rpn-line * at-line * push ( expression ) * ( expression ) = expression ; * expression ; * expression : *//* Note: This function does not return with a new token. It is up to the * calling routine to handle that. */static void statement (_SLang_Token_Type *ctok){ unsigned char type; if (SLang_Error) return; LLT->parse_level += 1; switch (ctok->type) { case OBRACE_TOKEN: compound_statement (ctok); break; case IF_TOKEN: case IFNOT_TOKEN: type = ctok->type; get_token (ctok); expression_with_parenthesis (ctok); block (ctok); if (ELSE_TOKEN != get_token (ctok)) { compile_token_of_type (type); unget_token (ctok); break; } get_token (ctok); block (ctok); if (type == IF_TOKEN) type = ELSE_TOKEN; else type = NOTELSE_TOKEN; compile_token_of_type (type); break; /* case IFNOT_TOKEN: */ case LOOP_TOKEN: case _FOR_TOKEN: type = ctok->type; get_token (ctok); expression_with_parenthesis (ctok); block (ctok); compile_token_of_type (type); break; case FOREACH_TOKEN: get_token (ctok); expression_with_parenthesis (ctok); if (NULL == push_token_list ()) break; append_token_of_type (ARG_TOKEN); if (ctok->type == USING_TOKEN) { if (OPAREN_TOKEN != get_token (ctok)) { _SLparse_error ("Expected 'using ('", ctok, 0); break; } get_token (ctok); function_args_expression (ctok, 0); } append_token_of_type (EARG_TOKEN); compile_token_list (); block (ctok); compile_token_of_type (FOREACH_TOKEN); break; case WHILE_TOKEN: get_token (ctok); compile_token_of_type (OBRACE_TOKEN); expression_with_parenthesis (ctok); compile_token_of_type (CBRACE_TOKEN); block (ctok); compile_token_of_type (WHILE_TOKEN); break; case DO_TOKEN: get_token (ctok); block (ctok); if (WHILE_TOKEN != get_token (ctok)) { _SLparse_error("Expecting while", ctok, 0); break; } get_token (ctok); compile_token_of_type (OBRACE_TOKEN); expression_with_parenthesis (ctok); compile_token_of_type (CBRACE_TOKEN); compile_token_of_type (DOWHILE_TOKEN); handle_semicolon (ctok); break; case FOR_TOKEN: /* Look for (exp_opt ; exp_opt ; exp_opt ) */ if (OPAREN_TOKEN != get_token (ctok)) { _SLparse_error("Expecting (.", ctok, 0); break; } if (NULL == push_token_list ()) break; append_token_of_type (OBRACE_TOKEN); if (SEMICOLON_TOKEN != get_token (ctok)) { expression (ctok); if (ctok->type != SEMICOLON_TOKEN) { _SLparse_error("Expecting ;", ctok, 0); break; } } append_token_of_type (CBRACE_TOKEN); append_token_of_type (OBRACE_TOKEN); if (SEMICOLON_TOKEN != get_token (ctok)) { expression (ctok); if (ctok->type != SEMICOLON_TOKEN) { _SLparse_error("Expecting ;", ctok, 0); break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -