Changeset 1ebc1a62 in mainline
- Timestamp:
- 2010-03-29T20:30:29Z (14 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- a95310e
- Parents:
- 5da468e
- Location:
- uspace/app/sbi
- Files:
-
- 31 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/app/sbi/Makefile
r5da468e r1ebc1a62 28 28 29 29 USPACE_PREFIX = ../.. 30 EXTRA_CFLAGS = -D__HELENOS__ 30 LIBS = $(LIB_PREFIX)/clui/libclui.a 31 EXTRA_CFLAGS = -D__HELENOS__ -I$(LIB_PREFIX)/clui 31 32 32 33 BINARY = sbi -
uspace/app/sbi/src/ancr.c
r5da468e r1ebc1a62 67 67 * Note that currently we expect there to be exactly one module in the 68 68 * whole program. 69 * 70 * @param prog Program being processed. 71 * @param module Module to process. 69 72 */ 70 73 void ancr_module_process(stree_program_t *prog, stree_module_t *module) … … 79 82 modm = list_node_data(node, stree_modm_t *); 80 83 assert(modm->mc == mc_csi); /* XXX */ 81 /* printf("ancr_csi_process() on '%s'\n",82 strtab_get_str(modm->u.csi->name->sid));*/83 84 ancr_csi_dfs(prog, modm->u.csi); 84 85 … … 92 93 * process all CSI nodes by calling ancr_csi_process() on them. 93 94 * (Which causes that and possibly some other nodes to be processed). 95 * 96 * @param prog Program being processed. 97 * @param csi CSI node to visit. 94 98 */ 95 99 static void ancr_csi_dfs(stree_program_t *prog, stree_csi_t *csi) … … 116 120 * Fist processes the pre-required nodes (outer CSI and base CSIs), 117 121 * then processes @a node. This is the core 'outward-and-baseward' walk. 122 * 123 * @param prog Program being processed. 124 * @param node CSI node to process. 118 125 */ 119 126 static void ancr_csi_process(stree_program_t *prog, stree_csi_t *node) … … 171 178 * We have detected a loop in CSI ancestry. Traverse it (by following the 172 179 * nodes in ws_active state and print it. 180 * 181 * @param prog Program. 182 * @param node CSI node participating in an ancestry cycle. 173 183 */ 174 184 static void ancr_csi_print_cycle(stree_program_t *prog, stree_csi_t *node) -
uspace/app/sbi/src/builtin.c
r5da468e r1ebc1a62 27 27 */ 28 28 29 /** @file Builtin symbol binding. */ 29 /** @file Builtin symbol binding. 30 * 31 * 'Builtin' symbols are implemented outside of the language itself. 32 * Here we refer to entities residing within the interpreted universe 33 * as 'internal', while anything implemented outside this universe 34 * as 'external'. This module facilitates declaration of builtin 35 * symbols and the binding of these symbols to their external 36 * implementation. 37 */ 30 38 31 39 #include <stdio.h> … … 54 62 * 55 63 * Declares symbols that will be hooked to builtin interpreter procedures. 64 * 65 * @param program Program in which to declare builtin symbols. 56 66 */ 57 67 void builtin_declare(stree_program_t *program) … … 86 96 } 87 97 88 /** Get grandfather class. */ 98 /** Get grandfather class. 99 * 100 * Grandfather class is the class from which all other classes are 101 * (directly or indirectly) derived. 102 * 103 * @param builtin Builtin context (corresponsds to program). 104 * @return Grandfather class (CSI). 105 */ 89 106 stree_csi_t *builtin_get_gf_class(builtin_t *builtin) 90 107 { … … 95 112 } 96 113 114 /** Allocate new builtin context object. 115 * 116 * @return Builtin context object. 117 */ 97 118 static builtin_t *builtin_new(void) 98 119 { … … 126 147 } 127 148 128 /** Simplifed search for a global symbol. */ 149 /** Simplifed search for a global symbol. 150 * 151 * The specified symbol must exist. 152 * 153 * @param bi Builtin context object. 154 * @param sym_name Name of symbol to find. 155 * @return Symbol. 156 */ 129 157 stree_symbol_t *builtin_find_lvl0(builtin_t *bi, const char *sym_name) 130 158 { … … 136 164 ident->sid = strtab_get_sid(sym_name); 137 165 sym = symbol_lookup_in_csi(bi->program, NULL, ident); 166 assert(sym != NULL); 138 167 139 168 return sym; 140 169 } 141 170 142 /** Simplifed search for a level 1 symbol. */ 171 /** Simplifed search for a level 1 symbol. 172 * 173 * The specified symbol must exist. 174 * 175 * @param bi Builtin context object. 176 * @param csi_name CSI in which to look for symbol. 177 * @param sym_name Name of symbol to find. 178 * @return Symbol. 179 */ 143 180 stree_symbol_t *builtin_find_lvl1(builtin_t *bi, const char *csi_name, 144 181 const char *sym_name) … … 154 191 ident->sid = strtab_get_sid(csi_name); 155 192 csi_sym = symbol_lookup_in_csi(bi->program, NULL, ident); 193 assert(csi_sym != NULL); 156 194 csi = symbol_to_csi(csi_sym); 157 195 assert(csi != NULL); … … 159 197 ident->sid = strtab_get_sid(sym_name); 160 198 mbr_sym = symbol_lookup_in_csi(bi->program, csi, ident); 199 assert(mbr_sym != NULL); 161 200 162 201 return mbr_sym; 163 202 } 164 203 204 /** Bind level 1 member function to external implementation. 205 * 206 * Binds a member function (of a global class) to external implementation. 207 * The specified CSI and member function must exist. 208 * 209 * @param bi Builtin context object. 210 * @param csi_name CSI which contains the function. 211 * @param sym_name Function name. 212 * @param bproc Pointer to C function implementation. 213 */ 165 214 void builtin_fun_bind(builtin_t *bi, const char *csi_name, 166 215 const char *sym_name, builtin_proc_t bproc) … … 177 226 } 178 227 228 /** Execute a builtin procedure. 229 * 230 * Executes a procedure that has an external implementation. 231 * 232 * @param run Runner object. 233 * @param proc Procedure that has an external implementation. 234 */ 179 235 void builtin_run_proc(run_t *run, stree_proc_t *proc) 180 236 { … … 201 257 } 202 258 203 /** Get pointer to member var of current object. */ 259 /** Get pointer to member var of current object. 260 * 261 * Returns the var node that corresponds to a member of the currently 262 * active object with the given name. This member must exist. 263 * 264 * @param run Runner object. 265 * @param mbr_name Name of member to find. 266 * @return Var node of the member. 267 */ 204 268 rdata_var_t *builtin_get_self_mbr_var(run_t *run, const char *mbr_name) 205 269 { … … 220 284 } 221 285 222 /** Declare a builtin function in @a csi. */ 286 /** Declare a builtin function in @a csi. 287 * 288 * Declare a builtin function member of CSI @a csi. Deprecated in favor 289 * of builtin_code_snippet(). 290 * 291 * @param csi CSI in which to declare function. 292 * @param name Name of member function to declare. 293 * @return Symbol of newly declared function. 294 */ 223 295 stree_symbol_t *builtin_declare_fun(stree_csi_t *csi, const char *name) 224 296 { … … 251 323 } 252 324 253 /** Add one formal parameter to function. */ 325 /** Add one formal parameter to function. 326 * 327 * Used to incrementally construct formal parameter list of a builtin 328 * function. Deprecated in favor of builtin_code_snippet(). Does not 329 * support type checking. 330 * 331 * @param fun_sym Symbol of function to add parameters to. 332 * @param name Name of parameter to add. 333 */ 254 334 void builtin_fun_add_arg(stree_symbol_t *fun_sym, const char *name) 255 335 { -
uspace/app/sbi/src/debug.h
r5da468e r1ebc1a62 33 33 //#define DEBUG_PARSE_TRACE 34 34 35 /** 36 *Uncomment this to get extra verbose messages from parser's lexing 37 * primitives. 38 */ 39 //#define DEBUG_LPARSE_TRACE 40 35 41 /** Uncomment this to get verbose debugging messagges during typing. */ 36 42 //#define DEBUG_TYPE_TRACE -
uspace/app/sbi/src/imode.c
r5da468e r1ebc1a62 27 27 */ 28 28 29 /** @file Interactive mode. */ 29 /** @file Interactive mode. 30 * 31 * In interactive mode the user types in statements. As soon as the outermost 32 * statement is complete (terminated with ';' or 'end'), the interpreter 33 * executes it. Otherwise it prompts the user until the entire statement 34 * is read in. 35 * 36 * The user interface depends on the OS. In HelenOS we use the CLUI library 37 * which gives us rich line editing capabilities. 38 */ 30 39 31 40 #include <stdio.h> 32 41 #include <stdlib.h> 33 42 #include "ancr.h" 43 #include "assert.h" 34 44 #include "builtin.h" 45 #include "intmap.h" 35 46 #include "list.h" 36 47 #include "mytypes.h" 48 #include "rdata.h" 37 49 #include "stree.h" 38 50 #include "strtab.h" … … 45 57 #include "imode.h" 46 58 59 /** Run in interactive mode. 60 * 61 * Repeatedly read in statements from the user and execute them. 62 */ 47 63 void imode_run(void) 48 64 { … … 56 72 stree_symbol_t *fun_sym; 57 73 stype_t stype; 74 stype_block_vr_t *block_vr; 75 list_node_t *bvr_n; 76 rdata_item_t *rexpr; 77 rdata_item_t *rexpr_vi; 58 78 59 79 run_t run; … … 72 92 ancr_module_process(program, program->module); 73 93 94 /* Construct typing context. */ 95 stype.program = program; 96 stype.proc_vr = stype_proc_vr_new(); 97 list_init(&stype.proc_vr->block_vr); 98 stype.current_csi = NULL; 99 proc = stree_proc_new(); 100 101 fun = stree_fun_new(); 102 fun_sym = stree_symbol_new(sc_fun); 103 fun_sym->u.fun = fun; 104 fun->name = stree_ident_new(); 105 fun->name->sid = strtab_get_sid("$imode"); 106 107 stype.proc_vr->proc = proc; 108 fun->symbol = fun_sym; 109 proc->outer_symbol = fun_sym; 110 111 /* Create block visit record. */ 112 block_vr = stype_block_vr_new(); 113 intmap_init(&block_vr->vdecls); 114 115 /* Add block visit record to the stack. */ 116 list_append(&stype.proc_vr->block_vr, block_vr); 117 118 /* Construct run context. */ 119 run.thread_ar = run_thread_ar_new(); 120 list_init(&run.thread_ar->proc_ar); 121 run_proc_ar_create(&run, NULL, proc, &proc_ar); 122 list_append(&run.thread_ar->proc_ar, proc_ar); 123 74 124 quit_im = b_false; 75 125 while (quit_im != b_true) { 126 parse.error = b_false; 127 stype.error = b_false; 128 76 129 input_new_interactive(&input); 77 130 … … 85 138 stat = parse_stat(&parse); 86 139 87 /* Construct typing context. */ 88 stype.program = program; 89 stype.proc_vr = stype_proc_vr_new(); 90 stype.current_csi = NULL; 91 proc = stree_proc_new(); 92 93 fun = stree_fun_new(); 94 fun_sym = stree_symbol_new(sc_fun); 95 fun_sym->u.fun = fun; 96 fun->name = stree_ident_new(); 97 fun->name->sid = strtab_get_sid("$imode"); 98 99 stype.proc_vr->proc = proc; 100 fun->symbol = fun_sym; 101 proc->outer_symbol = fun_sym; 102 103 /* Construct run context. */ 104 run.thread_ar = run_thread_ar_new(); 105 list_init(&run.thread_ar->proc_ar); 106 run_proc_ar_create(&run, NULL, proc, &proc_ar); 107 list_append(&run.thread_ar->proc_ar, proc_ar); 140 if (parse.error != b_false) 141 continue; 108 142 109 143 /* Type statement. */ 110 stype_stat(&stype, stat); 144 stype_stat(&stype, stat, b_true); 145 146 if (stype.error != b_false) 147 continue; 111 148 112 149 /* Run statement. */ 113 150 run_init(&run); 114 151 run.program = program; 115 run_stat(&run, stat); 152 run_stat(&run, stat, &rexpr); 153 154 if (rexpr != NULL) { 155 /* Convert expression result to value item. */ 156 run_cvt_value_item(&run, rexpr, &rexpr_vi); 157 assert(rexpr_vi->ic == ic_value); 158 159 /* Print result. */ 160 printf("Result: "); 161 rdata_value_print(rexpr_vi->u.value); 162 printf("\n"); 163 } 116 164 } 165 166 /* Remove block visit record from the stack, */ 167 bvr_n = list_last(&stype.proc_vr->block_vr); 168 assert(list_node_data(bvr_n, stype_block_vr_t *) == block_vr); 169 list_remove(&stype.proc_vr->block_vr, bvr_n); 117 170 118 171 printf("\nBye!\n"); -
uspace/app/sbi/src/input.c
r5da468e r1ebc1a62 29 29 /** @file Input module 30 30 * 31 * Reads source code from a file. 31 * Reads source code. Currently input can be read from a file (standard 32 * case), from a string literal (when parsing builtin code) or interactively 33 * from the user. 32 34 */ 33 35 … … 35 37 #include <stdlib.h> 36 38 #include "mytypes.h" 39 #include "os/os.h" 37 40 #include "strtab.h" 38 41 39 42 #include "input.h" 40 43 44 /** Size of input buffer. XXX This limits the maximum line length. */ 41 45 #define INPUT_BUFFER_SIZE 256 42 46 … … 45 49 static void input_init_string(input_t *input, const char *str); 46 50 47 /** Create new input object for reading from file. */ 51 /** Create new input object for reading from file. 52 * 53 * @param input Place to store pointer to new input object. 54 * @param fname Name of file to read from. 55 * 56 * @return EOK on success, ENOMEM when allocation fails, 57 * ENOENT when opening file fails. 58 */ 48 59 int input_new_file(input_t **input, char *fname) 49 60 { … … 55 66 } 56 67 57 /** Create new input object for reading from interactive input. */ 68 /** Create new input object for reading from interactive input. 69 * 70 * @param input Place to store pointer to new input object. 71 * @return EOK on success, ENOMEM when allocation fails. 72 */ 58 73 int input_new_interactive(input_t **input) 59 74 { … … 66 81 } 67 82 68 /** Create new input object for reading from string. */ 83 /** Create new input object for reading from string. 84 * 85 * @param input Place to store pointer to new input object. 86 * @param str String literal from which to read input. 87 * @return EOK on success, ENOMEM when allocation fails. 88 */ 69 89 int input_new_string(input_t **input, const char *str) 70 90 { … … 77 97 } 78 98 79 /** Initialize input object for reading from file. */ 99 /** Initialize input object for reading from file. 100 * 101 * @param input Input object. 102 * @param fname Name of file to read from. 103 * 104 * @return EOK on success, ENOENT when opening file fails. 105 */ 80 106 static int input_init_file(input_t *input, char *fname) 81 107 { … … 92 118 } 93 119 120 input->str = NULL; 94 121 input->line_no = 0; 95 122 input->fin = f; … … 97 124 } 98 125 99 /** Initialize input object for reading from interactive input. */ 126 /** Initialize input object for reading from interactive input. 127 * 128 * @param input Input object. 129 */ 100 130 static void input_init_interactive(input_t *input) 101 131 { … … 106 136 } 107 137 138 input->str = NULL; 108 139 input->line_no = 0; 109 140 input->fin = NULL; 110 141 } 111 142 112 /** Initialize input object for reading from string. */ 143 /** Initialize input object for reading from string. 144 * 145 * @param input Input object. 146 * @param str String literal from which to read input. 147 */ 113 148 static void input_init_string(input_t *input, const char *str) 114 149 { … … 124 159 } 125 160 126 /** Get next line of input. */ 161 /** Get next line of input. 162 * 163 * The pointer stored in @a line is owned by @a input and is valid until the 164 * next call to input_get_line(). The caller is not to free it. The returned 165 * line is terminated with '\n' if another line is coming (potentially empty). 166 * An empty line ("") signals end of input. 167 * 168 * @param input Input object. 169 * @param line Place to store pointer to next line. 170 * 171 * @return EOK on success, EIO on failure. 172 */ 127 173 int input_get_line(input_t *input, char **line) 128 174 { 129 175 const char *sp; 130 176 char *dp; 177 char *line_p; 131 178 size_t cnt; 132 179 … … 166 213 printf("... "); 167 214 168 if (fgets(input->buffer, INPUT_BUFFER_SIZE, stdin) == NULL) 169 input->buffer[0] = '\0'; 170 171 if (ferror(stdin)) 215 fflush(stdout); 216 if (os_input_line(&line_p) != EOK) 172 217 return EIO; 173 218 174 *line = input->buffer;219 *line = line_p; 175 220 } 176 221 … … 179 224 } 180 225 181 /** Get number of the last provided line of input. */ 226 /** Get number of the last provided line of input. 227 * 228 * @param input Input module. 229 * @return Line number of the last provided input line (counting 230 * from 1 up). 231 */ 182 232 int input_get_line_no(input_t *input) 183 233 { -
uspace/app/sbi/src/intmap.c
r5da468e r1ebc1a62 29 29 /** @file Integer map. 30 30 * 31 * Maps integers to pointers (void *). 31 * Maps integers to pointers (void *). Current implementation is trivial 32 * (linked list of key-value pairs). 32 33 */ 33 34 … … 40 41 #include "intmap.h" 41 42 42 /** Initialize map. */ 43 /** Initialize map. 44 * 45 * @param intmap Map to initialize. 46 */ 43 47 void intmap_init(intmap_t *intmap) 44 48 { … … 46 50 } 47 51 48 /** Set value corresponding to a key. */ 52 /** Set value corresponding to a key. 53 * 54 * If there already exists a mapping for @a key in the map, it is 55 * silently replaced. If @a value is @c NULL, the mapping for @a key 56 * is removed from the map. 57 * 58 * @param intmap Map. 59 * @param key Key (integer). 60 * @param value Value (must be a pointer) or @c NULL. 61 */ 49 62 void intmap_set(intmap_t *intmap, int key, void *value) 50 63 { … … 83 96 } 84 97 85 /** Get value corresponding to a key. */ 98 /** Get value corresponding to a key. 99 * 100 * @param intmap Map. 101 * @param key Key for which to retrieve mapping. 102 * 103 * @return Value correspoding to @a key or @c NULL if no mapping 104 * exists. 105 */ 86 106 void *intmap_get(intmap_t *intmap, int key) 87 107 { -
uspace/app/sbi/src/lex.c
r5da468e r1ebc1a62 145 145 }; 146 146 147 /** Print lclass value. */ 147 /** Print lclass value. 148 * 149 * Prints lclass (lexical element class) value in human-readable form 150 * (for debugging). 151 * 152 * @param lclass Lclass value for display. 153 */ 148 154 void lclass_print(lclass_t lclass) 149 155 { … … 184 190 } 185 191 186 /** Print lexical element. */ 192 /** Print lexical element. 193 * 194 * Prints lexical element in human-readable form (for debugging). 195 * 196 * @param lem Lexical element for display. 197 */ 187 198 void lem_print(lem_t *lem) 188 199 { … … 203 214 } 204 215 205 /** Print lem coordinates. */ 216 /** Print lem coordinates. 217 * 218 * Print the coordinates (line number, column number) of a lexical element. 219 * 220 * @param lem Lexical element for coordinate printing. 221 */ 206 222 void lem_print_coords(lem_t *lem) 207 223 { … … 209 225 } 210 226 211 /** Initialize lexer instance. */ 227 /** Initialize lexer instance. 228 * 229 * @param lex Lexer object to initialize. 230 * @param input Input to associate with lexer. 231 */ 212 232 void lex_init(lex_t *lex, struct input *input) 213 233 { … … 229 249 /** Advance to next lexical element. 230 250 * 231 * The new element be read in lazily then it is actually accessed. 251 * The new element is read in lazily then it is actually accessed. 252 * 253 * @param lex Lexer object. 232 254 */ 233 255 void lex_next(lex_t *lex) … … 243 265 * 244 266 * The returned pointer is invalidated by next call to lex_next() 267 * 268 * @param lex Lexer object. 245 269 */ 246 270 lem_t *lex_get_current(lex_t *lex) … … 250 274 } 251 275 252 /** Read in the current lexical element (unless already read in). */ 276 /** Read in the current lexical element (unless already read in). 277 * 278 * @param lex Lexer object. 279 */ 253 280 static void lex_touch(lex_t *lex) 254 281 { … … 267 294 /** Try reading next lexical element. 268 295 * 269 * @return @c b_true on success or @c b_false if it needs restarting. 296 * Attemps to read the next lexical element. In some cases (such as a comment) 297 * this function will need to give it another try and returns @c b_false 298 * in such case. 299 * 300 * @param lex Lexer object. 301 * @return @c b_true on success or @c b_false if it needs 302 * restarting. On success the lem is stored to 303 * the current lem in @a lex. 270 304 */ 271 305 static bool_t lex_read_try(lex_t *lex) … … 369 403 } 370 404 371 /** Lex a word (identifier or keyword). */ 405 /** Lex a word (identifier or keyword). 406 * 407 * Read in a word. This may later turn out to be a keyword or a regular 408 * identifier. It is stored in the current lem in @a lex. 409 * 410 * @param lex Lexer object. 411 */ 372 412 static void lex_word(lex_t *lex) 373 413 { … … 409 449 } 410 450 411 /** Lex a numeric literal. */ 451 /** Lex a numeric literal. 452 * 453 * Reads in a numeric literal and stores it in the current lem in @a lex. 454 * 455 * @param lex Lexer object. 456 */ 412 457 static void lex_number(lex_t *lex) 413 458 { … … 429 474 } 430 475 431 /** Lex a string literal. */ 476 /** Lex a string literal. 477 * 478 * Reads in a string literal and stores it in the current lem in @a lex. 479 * 480 * @param lex Lexer object. 481 */ 432 482 static void lex_string(lex_t *lex) 433 483 { … … 461 511 } 462 512 463 /** Lex a single-line comment. */ 513 /** Lex a single-line comment. 514 * 515 * This does not produce any lem. The comment is just skipped. 516 * 517 * @param lex Lexer object. 518 */ 464 519 static void lex_skip_comment(lex_t *lex) 465 520 { … … 475 530 } 476 531 477 /** Skip whitespace characters. */ 532 /** Skip whitespace characters. 533 * 534 * This does not produce any lem. The whitespace is just skipped. 535 * 536 * @param lex Lexer object. 537 */ 478 538 static void lex_skip_ws(lex_t *lex) 479 539 { … … 485 545 while (b_true) { 486 546 while (*bp == ' ' || *bp == '\t') { 487 if (*bp == '\t') 547 if (*bp == '\t') { 548 /* XXX This is too simplifed. */ 488 549 lex->col_adj += (TAB_WIDTH - 1); 550 } 489 551 ++bp; 490 552 } … … 507 569 } 508 570 509 /** Determine if character can start a word. */ 571 /** Determine if character can start a word. 572 * 573 * @param c Character. 574 * @return @c b_true if @a c can start a word, @c b_false otherwise. 575 */ 510 576 static bool_t is_wstart(char c) 511 577 { … … 514 580 } 515 581 516 /** Determine if character can continue a word. */ 582 /** Determine if character can continue a word. 583 * 584 * @param c Character. 585 * @return @c b_true if @a c can start continue word, @c b_false 586 * otherwise. 587 */ 517 588 static bool_t is_wcont(char c) 518 589 { … … 520 591 } 521 592 593 /** Determine if character is a numeric digit. 594 * 595 * @param c Character. 596 * @return @c b_true if @a c is a numeric digit, @c b_false otherwise. 597 */ 522 598 static bool_t is_digit(char c) 523 599 { … … 525 601 } 526 602 603 /** Determine numeric value of digit character. 604 * 605 * @param c Character, must be a valid decimal digit. 606 * @return Value of the digit (0-9). 607 */ 527 608 static int digit_value(char c) 528 609 { -
uspace/app/sbi/src/list.c
r5da468e r1ebc1a62 47 47 static bool_t list_node_present(list_t *list, list_node_t *node); 48 48 49 /** Initialize list. */ 49 /** Initialize list. 50 * 51 * @param list List to initialize. 52 */ 50 53 void list_init(list_t *list) 51 54 { … … 54 57 } 55 58 56 /** Append data to list. */ 59 /** Append data to list. 60 * 61 * Create a new list node and append it at the end of the list. 62 * 63 * @param list Linked list. 64 * @param data Data for the new node. 65 */ 57 66 void list_append(list_t *list, void *data) 58 67 { … … 63 72 } 64 73 65 /** Prepend data to list. */ 74 /** Prepend data to list. 75 * 76 * Create a new list node and prepend it at the beginning of the list. 77 * 78 * @param list Linked list. 79 * @param data Data for the new node. 80 */ 66 81 void list_prepend(list_t *list, void *data) 67 82 { … … 72 87 } 73 88 74 /** Remove data from list. */ 89 /** Remove data from list. 90 * 91 * Removes the given node from a list and destroys it. Any data the node might 92 * have is ignored. If asserts are on, we check wheter node is really present 93 * in the list the caller is requesting us to remove it from. 94 * 95 * @param list Linked list. 96 * @param node List node to remove. 97 */ 75 98 void list_remove(list_t *list, list_node_t *node) 76 99 { … … 82 105 } 83 106 84 /** Return first list node or NULL if list is empty. */ 107 /** Return first list node or NULL if list is empty. 108 * 109 * @param list Linked list. 110 * @return First node of the list or @c NULL if the list is empty. 111 */ 85 112 list_node_t *list_first(list_t *list) 86 113 { … … 93 120 } 94 121 95 /** Return last list node or NULL if list is empty. */ 122 /** Return last list node or NULL if list is empty. 123 * 124 * @param list Linked list. 125 * @return Last node of the list or @c NULL if the list is empty. 126 */ 96 127 list_node_t *list_last(list_t *list) 97 128 { … … 104 135 } 105 136 106 /** Return next list node or NULL if this was the last one. */ 137 /** Return next list node or NULL if this was the last one. 138 * 139 * @param list Linked list. 140 * @param node Node whose successor we are interested in. 141 * @return Following list node or @c NULL if @a node is last. 142 */ 107 143 list_node_t *list_next(list_t *list, list_node_t *node) 108 144 { … … 114 150 } 115 151 116 /** Return next list node or NULL if this was the last one. */ 152 /** Return previous list node or NULL if this was the last one. 153 * 154 * @param list Linked list. 155 * @param node Node whose predecessor we are interested in. 156 * @return Preceding list node or @c NULL if @a node is last. 157 */ 117 158 list_node_t *list_prev(list_t *list, list_node_t *node) 118 159 { … … 124 165 } 125 166 126 /** Return b_true if list is empty. */ 167 /** Return b_true if list is empty. 168 * 169 * @param list Linked list. 170 * @return @c b_true if list is empty, @c b_false otherwise. 171 */ 127 172 bool_t list_is_empty(list_t *list) 128 173 { … … 130 175 } 131 176 132 /** Change node data. */ 177 /** Change node data. 178 * 179 * Change the data associated with a node. 180 * 181 * @param node List node. 182 * @param data New data for node. 183 */ 133 184 void list_node_setdata(list_node_t *node, void *data) 134 185 { … … 136 187 } 137 188 138 /** Create new node. */ 189 /** Create new node. 190 * 191 * @param data Initial data for node. 192 * @return New list node. 193 */ 139 194 static list_node_t *list_node_new(void *data) 140 195 { … … 154 209 } 155 210 156 /** Delete node. */ 211 /** Delete node. 212 * 213 * @param node List node. Must not take part in any list. 214 */ 157 215 static void list_node_delete(list_node_t *node) 158 216 { … … 163 221 } 164 222 165 /** Insert node between two other nodes. */ 166 static void list_node_insert_between(list_node_t *n, list_node_t *a, list_node_t *b) 223 /** Insert node between two other nodes. 224 * 225 * Inserts @a n between neighboring nodes @a a and @a b. 226 * 227 * @param n Node to insert. 228 * @param a Node to precede @a n. 229 * @param b Node to follow @a n. 230 */ 231 static void list_node_insert_between(list_node_t *n, list_node_t *a, 232 list_node_t *b) 167 233 { 168 234 assert(n->prev == NULL); … … 177 243 } 178 244 179 /** Unlink node. */ 245 /** Unlink node. 246 * 247 * Unlink node from the list it is currently in. 248 * 249 * @param n Node to unlink from its current list. 250 */ 180 251 static void list_node_unlink(list_node_t *n) 181 252 { … … 197 268 } 198 269 199 /** Check whether @a node is in list @a list. */ 270 /** Check whether @a node is in list @a list. 271 * 272 * @param list Linked list. 273 * @param node Node. 274 * @return @c b_true if @a node is part of @a list, @c b_false otherwise. 275 */ 200 276 static bool_t list_node_present(list_t *list, list_node_t *node) 201 277 { -
uspace/app/sbi/src/main.c
r5da468e r1ebc1a62 27 27 */ 28 28 29 /** @file Main module. */ 29 /** @file Main module. 30 * 31 * Main entry point for SBI, the Sysel Bootstrap Interpreter. 32 * When run without parameters, the interpreter will enter interactive 33 * mode. 34 */ 30 35 31 36 #include <stdio.h> … … 45 50 void syntax_print(void); 46 51 52 /** Main entry point. 53 * 54 * @return Zero on success, non-zero on error. 55 */ 47 56 int main(int argc, char *argv[]) 48 57 { … … 85 94 parse_module(&parse); 86 95 96 if (parse.error) 97 return 1; 98 87 99 /* Resolve ancestry. */ 88 100 ancr_module_process(program, parse.cur_mod); … … 90 102 /* Type program. */ 91 103 stype.program = program; 104 stype.error = b_false; 92 105 stype_module(&stype, program->module); 106 107 if (stype.error) 108 return 1; 93 109 94 110 /* Run program. */ … … 99 115 } 100 116 117 /** Print command-line syntax help. */ 101 118 void syntax_print(void) 102 119 { -
uspace/app/sbi/src/os/helenos.c
r5da468e r1ebc1a62 34 34 #include <str.h> 35 35 #include <task.h> 36 #include <tinput.h> 36 37 37 38 #include "os.h" … … 40 41 * Using HelenOS-specific string API. 41 42 */ 43 44 static tinput_t *tinput = NULL; 42 45 43 46 /** Concatenate two strings. */ … … 98 101 } 99 102 103 /** Read one line of input from the user. */ 104 int os_input_line(char **ptr) 105 { 106 char *line; 107 108 if (tinput == NULL) { 109 tinput = tinput_new(); 110 if (tinput == NULL) 111 return EIO; 112 } 113 114 line = tinput_read(tinput); 115 if (line == NULL) 116 return EIO; 117 118 /* XXX Input module needs trailing newline to keep going. */ 119 *ptr = os_str_acat(line, "\n"); 120 free(line); 121 122 return EOK; 123 } 124 100 125 /** Simple command execution. */ 101 126 int os_exec(char *const cmd[]) -
uspace/app/sbi/src/os/os.h
r5da468e r1ebc1a62 34 34 char *os_str_dup(const char *str); 35 35 int os_str_get_char(const char *str, int index, int *out_char); 36 int os_input_line(char **ptr); 36 37 int os_exec(char *const cmd[]); 37 38 -
uspace/app/sbi/src/os/posix.c
r5da468e r1ebc1a62 92 92 } 93 93 94 #define OS_INPUT_BUFFER_SIZE 256 95 static char os_input_buffer[OS_INPUT_BUFFER_SIZE]; 96 97 /** Read one line of input from the user. */ 98 int os_input_line(char **ptr) 99 { 100 if (fgets(os_input_buffer, OS_INPUT_BUFFER_SIZE, stdin) == NULL) 101 os_input_buffer[0] = '\0'; 102 103 if (ferror(stdin)) { 104 *ptr = NULL; 105 return EIO; 106 } 107 108 *ptr = strdup(os_input_buffer); 109 return EOK; 110 } 111 94 112 /** Simple command execution. */ 95 113 int os_exec(char *const cmd[]) -
uspace/app/sbi/src/p_expr.c
r5da468e r1ebc1a62 31 31 #include <assert.h> 32 32 #include <stdlib.h> 33 #include "debug.h" 33 34 #include "lex.h" 34 35 #include "list.h" … … 57 58 static stree_expr_t *parse_self_ref(parse_t *parse); 58 59 59 /** Parse expression. */ 60 static stree_expr_t *parse_recovery_expr(parse_t *parse); 61 62 /** Parse expression. 63 * 64 * Input is read from the input object associated with @a parse. If any 65 * error occurs, parse->error will @c b_true when this function 66 * returns. parse->error_bailout will be @c b_true if the error has not 67 * been recovered yet. Similar holds for other parsing functions in this 68 * module. 69 * 70 * @param parse Parser object. 71 */ 60 72 stree_expr_t *parse_expr(parse_t *parse) 61 73 { 74 #ifdef DEBUG_PARSE_TRACE 75 printf("Parse expression.\n"); 76 #endif 77 if (parse_is_error(parse)) 78 return parse_recovery_expr(parse); 79 62 80 return parse_assign(parse); 63 81 } 64 82 65 /** Parse assignment expression. */ 83 /** Parse assignment expression. 84 * 85 * @param parse Parser object. 86 */ 66 87 static stree_expr_t *parse_assign(parse_t *parse) 67 88 { … … 93 114 } 94 115 95 /** Parse comparative expression. */ 116 /** Parse comparative expression. 117 * 118 * @param parse Parser object. 119 */ 96 120 static stree_expr_t *parse_comparative(parse_t *parse) 97 121 { … … 105 129 lcur_lc(parse) == lc_lt || lcur_lc(parse) == lc_gt || 106 130 lcur_lc(parse) == lc_lt_equal || lcur_lc(parse) == lc_gt_equal) { 131 132 if (parse_is_error(parse)) 133 break; 107 134 108 135 switch (lcur_lc(parse)) { … … 131 158 } 132 159 133 /** Parse additive expression. */ 160 /** Parse additive expression. 161 * 162 * @param parse Parser object. 163 */ 134 164 static stree_expr_t *parse_additive(parse_t *parse) 135 165 { … … 139 169 a = parse_prefix(parse); 140 170 while (lcur_lc(parse) == lc_plus) { 171 if (parse_is_error(parse)) 172 break; 173 141 174 lskip(parse); 142 175 b = parse_prefix(parse); … … 154 187 } 155 188 156 /** Parse prefix expression. */ 189 /** Parse prefix expression. 190 * 191 * @param parse Parser object. 192 */ 157 193 static stree_expr_t *parse_prefix(parse_t *parse) 158 194 { … … 162 198 case lc_plus: 163 199 printf("Unimplemented: Unary plus.\n"); 164 exit(1); 200 a = parse_recovery_expr(parse); 201 parse_note_error(parse); 202 break; 165 203 case lc_new: 166 204 a = parse_prefix_new(parse); … … 174 212 } 175 213 176 /** Parse @c new operator. */ 214 /** Parse @c new operator. 215 * 216 * @param parse Parser object. 217 */ 177 218 static stree_expr_t *parse_prefix_new(parse_t *parse) 178 219 { … … 198 239 } 199 240 200 /** Parse postfix expression. */ 241 /** Parse postfix expression. 242 * 243 * @param parse Parser object. 244 */ 201 245 static stree_expr_t *parse_postfix(parse_t *parse) 202 246 { … … 208 252 while (lcur_lc(parse) == lc_period || lcur_lc(parse) == lc_lparen || 209 253 lcur_lc(parse) == lc_lsbr || lcur_lc(parse) == lc_as) { 254 255 if (parse_is_error(parse)) 256 break; 210 257 211 258 switch (lcur_lc(parse)) { … … 232 279 } 233 280 234 /** Parse member access expression */ 281 /** Parse member access expression 282 * 283 * @param parse Parser object. 284 */ 235 285 static stree_expr_t *parse_pf_access(parse_t *parse, stree_expr_t *a) 236 286 { … … 252 302 } 253 303 254 /** Parse function call expression. */ 304 /** Parse function call expression. 305 * 306 * @param parse Parser object. 307 */ 255 308 static stree_expr_t *parse_pf_call(parse_t *parse, stree_expr_t *a) 256 309 { … … 268 321 269 322 if (lcur_lc(parse) != lc_rparen) { 270 while ( b_true) {323 while (!parse_is_error(parse)) { 271 324 arg = parse_expr(parse); 272 325 list_append(&call->args, arg); … … 286 339 } 287 340 288 /** Parse index expression. */ 341 /** Parse index expression. 342 * 343 * @param parse Parser object. 344 */ 289 345 static stree_expr_t *parse_pf_index(parse_t *parse, stree_expr_t *a) 290 346 { … … 302 358 303 359 if (lcur_lc(parse) != lc_rsbr) { 304 while ( b_true) {360 while (!parse_is_error(parse)) { 305 361 arg = parse_expr(parse); 306 362 list_append(&index->args, arg); … … 320 376 } 321 377 322 /** Parse @c as operator. */ 378 /** Parse @c as operator. 379 * 380 * @param parse Parser object. 381 */ 323 382 static stree_expr_t *parse_pf_as(parse_t *parse, stree_expr_t *a) 324 383 { … … 339 398 } 340 399 341 /** Parse primitive expression. */ 400 /** Parse primitive expression. 401 * 402 * @param parse Parser object. 403 */ 342 404 static stree_expr_t *parse_primitive(parse_t *parse) 343 405 { … … 362 424 default: 363 425 lunexpected_error(parse); 364 exit(1); 365 } 366 367 return expr; 368 } 369 370 /** Parse name reference. */ 426 expr = parse_recovery_expr(parse); 427 } 428 429 return expr; 430 } 431 432 /** Parse name reference. 433 * 434 * @param parse Parser object. 435 */ 371 436 static stree_expr_t *parse_nameref(parse_t *parse) 372 437 { … … 382 447 } 383 448 384 /** Parse integer literal. */ 449 /** Parse integer literal. 450 * 451 * @param parse Parser object. 452 */ 385 453 static stree_expr_t *parse_lit_int(parse_t *parse) 386 454 { … … 401 469 } 402 470 403 /** Parse reference literal (@c nil). */ 471 /** Parse reference literal (@c nil). 472 * 473 * @param parse Parser object. 474 */ 404 475 static stree_expr_t *parse_lit_ref(parse_t *parse) 405 476 { … … 417 488 } 418 489 419 /** Parse string literal. */ 490 /** Parse string literal. 491 * 492 * @param parse Parser object. 493 */ 420 494 static stree_expr_t *parse_lit_string(parse_t *parse) 421 495 { … … 436 510 } 437 511 438 /** Parse @c self keyword. */ 512 /** Parse @c self keyword. 513 * 514 * @param parse Parser object. 515 */ 439 516 static stree_expr_t *parse_self_ref(parse_t *parse) 440 517 { … … 451 528 return expr; 452 529 } 530 531 /** Construct a special recovery expression. 532 * 533 * @param parse Parser object. 534 */ 535 static stree_expr_t *parse_recovery_expr(parse_t *parse) 536 { 537 stree_literal_t *literal; 538 stree_expr_t *expr; 539 540 (void) parse; 541 542 literal = stree_literal_new(ltc_ref); 543 544 expr = stree_expr_new(ec_literal); 545 expr->u.literal = literal; 546 547 return expr; 548 } -
uspace/app/sbi/src/p_type.c
r5da468e r1ebc1a62 1 /* YI1 /* 2 2 * Copyright (c) 2010 Jiri Svoboda 3 3 * All rights reserved. … … 31 31 #include <assert.h> 32 32 #include <stdlib.h> 33 #include "debug.h" 33 34 #include "lex.h" 34 35 #include "list.h" … … 48 49 static stree_tnameref_t *parse_tnameref(parse_t *parse); 49 50 50 /** Parse type expression. */ 51 static stree_texpr_t *parse_recovery_texpr(parse_t *parse); 52 53 /** Parse type expression. 54 * 55 * Input is read from the input object associated with @a parse. If any 56 * error occurs, parse->error will @c b_true when this function 57 * returns. parse->error_bailout will be @c b_true if the error has not 58 * been recovered yet. Similar holds for other parsing functions in this 59 * module. 60 * 61 * @param parse Parser object. 62 */ 51 63 stree_texpr_t *parse_texpr(parse_t *parse) 52 64 { 65 #ifdef DEBUG_PARSE_TRACE 66 printf("Parse type expression.\n"); 67 #endif 68 if (parse_is_error(parse)) 69 return parse_recovery_texpr(parse); 70 53 71 return parse_tapply(parse); 54 72 } 55 73 56 /** Parse type application expression. */ 74 /** Parse type application expression. 75 * 76 * @param parse Parser object. 77 */ 57 78 static stree_texpr_t *parse_tapply(parse_t *parse) 58 79 { … … 62 83 a = parse_tpostfix(parse); 63 84 while (lcur_lc(parse) == lc_slash) { 85 86 if (parse_is_error(parse)) 87 break; 88 64 89 lskip(parse); 65 90 b = parse_tpostfix(parse); … … 77 102 } 78 103 79 /** Parse postfix type expression. */ 104 /** Parse postfix type expression. 105 * 106 * @param parse Parser object. 107 */ 80 108 static stree_texpr_t *parse_tpostfix(parse_t *parse) 81 109 { … … 86 114 87 115 while (lcur_lc(parse) == lc_period || lcur_lc(parse) == lc_lsbr) { 116 117 if (parse_is_error(parse)) 118 break; 88 119 89 120 switch (lcur_lc(parse)) { … … 96 127 default: 97 128 lunexpected_error(parse); 98 exit(1); 129 tmp = parse_recovery_texpr(parse); 130 break; 99 131 } 100 132 … … 105 137 } 106 138 107 /** Parse access type expression. */ 139 /** Parse access type expression. 140 * 141 * @param parse Parser object. 142 * @param a Base expression. 143 */ 108 144 static stree_texpr_t *parse_pf_taccess(parse_t *parse, stree_texpr_t *a) 109 145 { … … 125 161 } 126 162 127 /** Parse index type expression. */ 163 /** Parse index type expression. 164 * 165 * @param parse Parser object. 166 * @param a Base expression. 167 */ 128 168 static stree_texpr_t *parse_pf_tindex(parse_t *parse, stree_texpr_t *a) 129 169 { … … 142 182 if (lcur_lc(parse) != lc_rsbr && lcur_lc(parse) != lc_comma) { 143 183 while (b_true) { 184 if (parse_is_error(parse)) 185 break; 144 186 expr = parse_expr(parse); 145 187 tindex->n_args += 1; … … 154 196 tindex->n_args = 1; 155 197 while (lcur_lc(parse) == lc_comma) { 198 if (parse_is_error(parse)) 199 break; 156 200 lskip(parse); 157 201 tindex->n_args += 1; … … 167 211 } 168 212 169 /** Parse primitive type expression. */ 213 /** Parse primitive type expression. 214 * 215 * @param parse Parser object. 216 */ 170 217 static stree_texpr_t *parse_tprimitive(parse_t *parse) 171 218 { … … 185 232 default: 186 233 lunexpected_error(parse); 187 exit(1); 234 texpr = parse_recovery_texpr(parse); 235 break; 188 236 } 189 237 … … 191 239 } 192 240 193 /** Parse type literal. */ 241 /** Parse type literal. 242 * 243 * @param parse Parser object. 244 */ 194 245 static stree_tliteral_t *parse_tliteral(parse_t *parse) 195 246 { … … 217 268 } 218 269 219 /** Parse type identifier. */ 270 /** Parse type identifier. 271 * 272 * @param parse Parser object. 273 */ 220 274 static stree_tnameref_t *parse_tnameref(parse_t *parse) 221 275 { … … 227 281 return tnameref; 228 282 } 283 284 /** Construct a special type expression fore recovery. 285 * 286 * @param parse Parser object. 287 */ 288 static stree_texpr_t *parse_recovery_texpr(parse_t *parse) 289 { 290 stree_tliteral_t *tliteral; 291 stree_texpr_t *texpr; 292 293 (void) parse; 294 295 tliteral = stree_tliteral_new(tlc_int); 296 297 texpr = stree_texpr_new(tc_tliteral); 298 texpr->u.tliteral = tliteral; 299 300 return texpr; 301 } -
uspace/app/sbi/src/parse.c
r5da468e r1ebc1a62 84 84 parse->cur_mod = parse->program->module; 85 85 parse->lex = lex; 86 87 parse->error = b_false; 88 parse->error_bailout = b_false; 89 86 90 lex_next(parse->lex); 87 91 } … … 93 97 stree_modm_t *modm; 94 98 95 while (lcur_lc(parse) != lc_eof ) {99 while (lcur_lc(parse) != lc_eof && !parse_is_error(parse)) { 96 100 switch (lcur_lc(parse)) { 97 101 case lc_class: … … 155 159 156 160 /* Parse class, struct or interface members. */ 157 while (lcur_lc(parse) != lc_end ) {161 while (lcur_lc(parse) != lc_end && !parse_is_error(parse)) { 158 162 csimbr = parse_csimbr(parse, csi); 159 163 list_append(&csi->members, csimbr); … … 235 239 236 240 /* Parse formal parameters. */ 237 while ( b_true) {241 while (!parse_is_error(parse)) { 238 242 arg = parse_proc_arg(parse); 239 243 … … 264 268 265 269 /* Parse attributes. */ 266 while (lcur_lc(parse) == lc_comma ) {270 while (lcur_lc(parse) == lc_comma && !parse_is_error(parse)) { 267 271 lskip(parse); 268 272 attr = parse_symbol_attr(parse); … … 281 285 symbol_print_fqn(symbol); 282 286 printf("' has no body.\n"); 283 exit(1);287 parse_note_error(parse); 284 288 } 285 289 fun->proc->body = NULL; … … 345 349 346 350 /* Parse formal parameters. */ 347 while ( b_true) {351 while (!parse_is_error(parse)) { 348 352 arg = parse_proc_arg(parse); 349 353 if (stree_arg_has_attr(arg, aac_packed)) { … … 370 374 lmatch(parse, lc_is); 371 375 372 while (lcur_lc(parse) != lc_end ) {376 while (lcur_lc(parse) != lc_end && !parse_is_error(parse)) { 373 377 switch (lcur_lc(parse)) { 374 378 case lc_get: … … 377 381 if (prop->getter != NULL) { 378 382 printf("Error: Duplicate getter.\n"); 379 exit(1); 383 (void) parse_block(parse); /* XXX Free */ 384 lmatch(parse, lc_end); 385 parse_note_error(parse); 386 break; 380 387 } 381 388 … … 395 402 if (prop->setter != NULL) { 396 403 printf("Error: Duplicate setter.\n"); 397 exit(1); 404 (void) parse_block(parse); /* XXX Free */ 405 lmatch(parse, lc_end); 406 parse_note_error(parse); 398 407 } 399 408 … … 424 433 lem_print(lcur(parse)); 425 434 printf("'.\n"); 426 exit(1);435 parse_note_error(parse); 427 436 } 428 437 … … 447 456 448 457 /* Parse attributes. */ 449 while (lcur_lc(parse) == lc_comma ) {458 while (lcur_lc(parse) == lc_comma && !parse_is_error(parse)) { 450 459 lskip(parse); 451 460 attr = parse_arg_attr(parse); … … 468 477 lem_print(lcur(parse)); 469 478 printf("'.\n"); 470 exit(1);479 parse_note_error(parse); 471 480 } 472 481 … … 486 495 list_init(&block->stats); 487 496 488 while (terminates_block(lcur_lc(parse)) != b_true) { 497 /* Avoid peeking if there is an error condition. */ 498 if (parse_is_error(parse)) 499 return block; 500 501 while (terminates_block(lcur_lc(parse)) != b_true && 502 !parse_is_error(parse)) { 503 489 504 stat = parse_stat(parse); 490 505 list_append(&block->stats, stat); … … 508 523 stree_exps_t *exp_s; 509 524 525 #ifdef DEBUG_PARSE_TRACE 526 printf("Parse statement.\n"); 527 #endif 510 528 switch (lcur_lc(parse)) { 511 529 case lc_var: … … 590 608 stree_if_t *if_s; 591 609 610 #ifdef DEBUG_PARSE_TRACE 611 printf("Parse 'if' statement.\n"); 612 #endif 592 613 if_s = stree_if_new(); 593 614 … … 613 634 stree_while_t *while_s; 614 635 636 #ifdef DEBUG_PARSE_TRACE 637 printf("Parse 'while' statement.\n"); 638 #endif 615 639 while_s = stree_while_new(); 616 640 … … 629 653 stree_for_t *for_s; 630 654 655 #ifdef DEBUG_PARSE_TRACE 656 printf("Parse 'for' statement.\n"); 657 #endif 631 658 for_s = stree_for_new(); 632 659 … … 649 676 stree_raise_t *raise_s; 650 677 678 #ifdef DEBUG_PARSE_TRACE 679 printf("Parse 'raise' statement.\n"); 680 #endif 651 681 raise_s = stree_raise_new(); 652 682 lmatch(parse, lc_raise); … … 662 692 stree_return_t *return_s; 663 693 694 #ifdef DEBUG_PARSE_TRACE 695 printf("Parse 'return' statement.\n"); 696 #endif 664 697 return_s = stree_return_new(); 665 698 … … 677 710 stree_except_t *except_c; 678 711 712 #ifdef DEBUG_PARSE_TRACE 713 printf("Parse WEF statement.\n"); 714 #endif 679 715 wef_s = stree_wef_new(); 680 716 list_init(&wef_s->except_clauses); … … 692 728 wef_s->with_block = parse_block(parse); 693 729 694 while (lcur_lc(parse) == lc_except ) {730 while (lcur_lc(parse) == lc_except && !parse_is_error(parse)) { 695 731 except_c = parse_except(parse); 696 732 list_append(&wef_s->except_clauses, except_c); … … 716 752 stree_exps_t *exps; 717 753 754 #ifdef DEBUG_PARSE_TRACE 755 printf("Parse expression statement.\n"); 756 #endif 718 757 expr = parse_expr(parse); 719 758 lmatch(parse, lc_scolon); … … 730 769 stree_except_t *except_c; 731 770 771 #ifdef DEBUG_PARSE_TRACE 772 printf("Parse 'except' statement.\n"); 773 #endif 732 774 except_c = stree_except_new(); 733 775 … … 748 790 stree_ident_t *ident; 749 791 792 #ifdef DEBUG_PARSE_TRACE 793 printf("Parse identifier.\n"); 794 #endif 750 795 lcheck(parse, lc_ident); 751 796 ident = stree_ident_new(); … … 756 801 } 757 802 803 /** Signal a parse error, start bailing out from parser. */ 804 void parse_raise_error(parse_t *parse) 805 { 806 parse->error = b_true; 807 parse->error_bailout = b_true; 808 } 809 810 /** Note a parse error that has been immediately recovered. */ 811 void parse_note_error(parse_t *parse) 812 { 813 parse->error = b_true; 814 } 815 816 /** Check if we are currently bailing out of parser due to a parse error. */ 817 bool_t parse_is_error(parse_t *parse) 818 { 819 return parse->error_bailout; 820 } 821 822 /** Recover from parse error bailout. 823 * 824 * Still remember that there was an error, but stop bailing out. 825 */ 826 void parse_recover_error(parse_t *parse) 827 { 828 assert(parse->error == b_true); 829 assert(parse->error_bailout == b_true); 830 831 parse->error_bailout = b_false; 832 } 833 758 834 /** Return current lem. */ 759 835 lem_t *lcur(parse_t *parse) 760 836 { 837 #ifdef DEBUG_LPARSE_TRACE 838 printf("lcur()\n"); 839 #endif 761 840 return lex_get_current(parse->lex); 762 841 } … … 767 846 lem_t *lem; 768 847 848 /* 849 * This allows us to skip error checking in many places. If there is an 850 * active error, lcur_lc() returns lc_invalid without reading input. 851 * 852 * Without this measure we would have to check for error all the time 853 * or risk requiring extra input from the user (in interactive mode) 854 * before actually bailing out from the parser. 855 */ 856 if (parse_is_error(parse)) 857 return lc_invalid; 858 769 859 lem = lcur(parse); 770 860 return lem->lclass; … … 774 864 void lskip(parse_t *parse) 775 865 { 866 #ifdef DEBUG_LPARSE_TRACE 867 printf("lskip()\n"); 868 #endif 776 869 lex_next(parse->lex); 777 870 } … … 780 873 void lcheck(parse_t *parse, lclass_t lc) 781 874 { 875 #ifdef DEBUG_LPARSE_TRACE 876 printf("lcheck("); 877 lclass_print(lc); 878 printf(")\n"); 879 #endif 782 880 if (lcur(parse)->lclass != lc) { 783 881 lem_print_coords(lcur(parse)); … … 785 883 printf("', got '"); lem_print(lcur(parse)); 786 884 printf("'.\n"); 787 exit(1);885 parse_raise_error(parse); 788 886 } 789 887 } … … 792 890 void lmatch(parse_t *parse, lclass_t lc) 793 891 { 892 #ifdef DEBUG_LPARSE_TRACE 893 printf("lmatch("); 894 lclass_print(lc); 895 printf(")\n"); 896 #endif 897 /* 898 * This allows us to skip error checking in many places. If there is an 899 * active error, lmatch() does nothing (similar to parse_block(), etc. 900 * 901 * Without this measure we would have to check for error all the time 902 * or risk requiring extra input from the user (in interactive mode) 903 * before actually bailing out from the parser. 904 */ 905 if (parse_is_error(parse)) 906 return; 907 794 908 lcheck(parse, lc); 795 909 lskip(parse); … … 803 917 lem_print(lcur(parse)); 804 918 printf("'.\n"); 805 exit(1);919 parse_raise_error(parse); 806 920 } 807 921 -
uspace/app/sbi/src/parse.h
r5da468e r1ebc1a62 38 38 stree_ident_t *parse_ident(parse_t *parse); 39 39 40 void parse_raise_error(parse_t *parse); 41 void parse_note_error(parse_t *parse); 42 bool_t parse_is_error(parse_t *parse); 43 void parse_recover_error(parse_t *parse); 44 40 45 /* 41 46 * Parsing primitives -
uspace/app/sbi/src/parse_t.h
r5da468e r1ebc1a62 40 40 /** Module currently being parsed */ 41 41 struct stree_module *cur_mod; 42 43 /** @c b_true if an error occured. */ 44 bool_t error; 45 46 /** @c b_true if bailing out due to an error. */ 47 bool_t error_bailout; 42 48 } parse_t; 43 49 -
uspace/app/sbi/src/rdata.c
r5da468e r1ebc1a62 48 48 49 49 static void rdata_address_print(rdata_address_t *address); 50 static void rdata_value_print(rdata_value_t *value);51 50 static void rdata_var_print(rdata_var_t *var); 52 51 … … 450 449 } 451 450 452 staticvoid rdata_value_print(rdata_value_t *value)451 void rdata_value_print(rdata_value_t *value) 453 452 { 454 453 rdata_var_print(value->var); -
uspace/app/sbi/src/rdata.h
r5da468e r1ebc1a62 56 56 57 57 void rdata_item_print(rdata_item_t *item); 58 void rdata_value_print(rdata_value_t *value); 58 59 59 60 #endif -
uspace/app/sbi/src/run.c
r5da468e r1ebc1a62 48 48 49 49 static void run_block(run_t *run, stree_block_t *block); 50 static void run_exps(run_t *run, stree_exps_t *exps );50 static void run_exps(run_t *run, stree_exps_t *exps, rdata_item_t **res); 51 51 static void run_vdecl(run_t *run, stree_vdecl_t *vdecl); 52 52 static void run_if(run_t *run, stree_if_t *if_s); … … 196 196 while (node != NULL) { 197 197 stat = list_node_data(node, stree_stat_t *); 198 run_stat(run, stat );198 run_stat(run, stat, NULL); 199 199 200 200 if (run->thread_ar->bo_mode != bm_none) … … 214 214 } 215 215 216 /** Run statement. */ 217 void run_stat(run_t *run, stree_stat_t *stat) 216 /** Run statement. 217 * 218 * Executes a statement. If @a res is not NULL and the statement is an 219 * expression statement with a value, the value item will be stored to 220 * @a res. 221 * 222 * @param run Runner object. 223 * @param stat Statement to run. 224 * @param res Place to store exps result or NULL if not interested. 225 */ 226 void run_stat(run_t *run, stree_stat_t *stat, rdata_item_t **res) 218 227 { 219 228 #ifdef DEBUG_RUN_TRACE 220 229 printf("Executing one statement %p.\n", stat); 221 230 #endif 231 232 if (res != NULL) 233 *res = NULL; 222 234 223 235 switch (stat->sc) { 224 236 case st_exps: 225 run_exps(run, stat->u.exp_s );237 run_exps(run, stat->u.exp_s, res); 226 238 break; 227 239 case st_vdecl: … … 251 263 } 252 264 253 /** Run expression statement. */ 254 static void run_exps(run_t *run, stree_exps_t *exps) 265 /** Run expression statement. 266 * 267 * Executes an expression statement. If @a res is not NULL then the value 268 * of the expression (or NULL if it has no value) will be stored to @a res. 269 * 270 * @param run Runner object. 271 * @param exps Expression statement to run. 272 * @param res Place to store exps result or NULL if not interested. 273 */ 274 static void run_exps(run_t *run, stree_exps_t *exps, rdata_item_t **res) 255 275 { 256 276 rdata_item_t *rexpr; … … 261 281 run_expr(run, exps->expr, &rexpr); 262 282 263 if (rexpr != NULL) { 264 printf("Warning: Expression value ignored.\n"); 265 } 283 if (res != NULL) 284 *res = rexpr; 266 285 } 267 286 … … 504 523 return tdata_is_csi_derived_from_ti(payload_o->class_sym->u.csi, 505 524 etype); 525 } 526 527 /** Raise an irrecoverable run-time error, start bailing out. 528 * 529 * Raises an error that cannot be handled by the user program. 530 */ 531 void run_raise_error(run_t *run) 532 { 533 run->thread_ar->bo_mode = bm_error; 534 run->thread_ar->error = b_true; 535 } 536 537 /** Construct a special recovery item. */ 538 rdata_item_t *run_recovery_item(run_t *run) 539 { 540 (void) run; 541 return NULL; 506 542 } 507 543 … … 1136 1172 if (addr_var->vref == NULL) { 1137 1173 printf("Error: Accessing null reference.\n"); 1138 exit(1); 1174 run_raise_error(run); 1175 *ritem = run_recovery_item(run); 1176 return; 1139 1177 } 1140 1178 … … 1144 1182 *ritem = item; 1145 1183 } 1146 1147 1184 1148 1185 run_thread_ar_t *run_thread_ar_new(void) -
uspace/app/sbi/src/run.h
r5da468e r1ebc1a62 35 35 void run_program(run_t *run, stree_program_t *prog); 36 36 void run_proc(run_t *run, run_proc_ar_t *proc_ar, rdata_item_t **res); 37 void run_stat(run_t *run, stree_stat_t *stat );37 void run_stat(run_t *run, stree_stat_t *stat, rdata_item_t **res); 38 38 39 39 void run_print_fun_bt(run_t *run); 40 41 void run_raise_error(run_t *run); 42 rdata_item_t *run_recovery_item(run_t *run); 40 43 41 44 rdata_var_t *run_local_vars_lookup(run_t *run, sid_t name); -
uspace/app/sbi/src/run_expr.c
r5da468e r1ebc1a62 210 210 sym = symbol_lookup_in_csi(run->program, csi, nameref->name); 211 211 212 /* Existence should have been verified in type checking phase. */ 213 assert(sym != NULL); 214 212 215 switch (sym->sc) { 213 216 case sc_csi: … … 857 860 run_dereference(run, arg, &darg); 858 861 862 if (run->thread_ar->bo_mode != bm_none) { 863 *res = run_recovery_item(run); 864 return; 865 } 866 859 867 /* Try again. */ 860 868 run_access_item(run, access, darg, res); … … 1021 1029 run_expr(run, call->fun, &rfun); 1022 1030 1031 if (run->thread_ar->bo_mode != bm_none) { 1032 *res = run_recovery_item(run); 1033 return; 1034 } 1035 1023 1036 if (rfun->ic != ic_value || rfun->u.value->var->vc != vc_deleg) { 1024 1037 printf("Unimplemented: Call expression of this type.\n"); 1025 *res = NULL; 1026 return; 1038 exit(1); 1027 1039 } 1028 1040 … … 1182 1194 printf("Error: Array index (value: %d) is out of range.\n", 1183 1195 arg_val); 1184 exit(1); 1196 run_raise_error(run); 1197 *res = run_recovery_item(run); 1198 return; 1185 1199 } 1186 1200 -
uspace/app/sbi/src/run_t.h
r5da468e r1ebc1a62 80 80 81 81 /** Exception */ 82 bm_exc 82 bm_exc, 83 84 /** Unrecoverable runtime error */ 85 bm_error 83 86 } run_bailout_mode_t; 84 87 … … 96 99 /** Exception payload */ 97 100 struct rdata_value *exc_payload; 101 102 /** @c b_true if a run-time error occured. */ 103 bool_t error; 98 104 } run_thread_ar_t; 99 105 -
uspace/app/sbi/src/run_texpr.c
r5da468e r1ebc1a62 94 94 95 95 sym = symbol_lookup_in_csi(prog, base_csi, taccess->member_name); 96 97 /* Existence should have been verified in type checking phase. */ 98 assert(sym != NULL); 99 96 100 if (sym->sc != sc_csi) { 97 101 printf("Error: Symbol '"); … … 188 192 sym = symbol_lookup_in_csi(prog, ctx, tnameref->name); 189 193 194 /* Existence should have been verified in type-checking phase. */ 195 assert(sym); 196 190 197 if (sym->sc != sc_csi) { 191 198 printf("Error: Symbol '"); -
uspace/app/sbi/src/stype.c
r5da468e r1ebc1a62 61 61 static void stype_raise(stype_t *stype, stree_raise_t *raise_s); 62 62 static void stype_return(stype_t *stype, stree_return_t *return_s); 63 static void stype_exps(stype_t *stype, stree_exps_t *exp_s );63 static void stype_exps(stype_t *stype, stree_exps_t *exp_s, bool_t want_value); 64 64 static void stype_wef(stype_t *stype, stree_wef_t *wef_s); 65 65 … … 164 164 if (titem->tic != tic_tarray) { 165 165 printf("Error: Packed argument is not an array.\n"); 166 exit(1);166 stype_note_error(stype); 167 167 } 168 168 } … … 240 240 while (stat_n != NULL) { 241 241 stat = list_node_data(stat_n, stree_stat_t *); 242 stype_stat(stype, stat );242 stype_stat(stype, stat, b_false); 243 243 244 244 stat_n = list_next(&block->stats, stat_n); … … 251 251 } 252 252 253 /** Type statement */ 254 void stype_stat(stype_t *stype, stree_stat_t *stat) 253 /** Type statement 254 * 255 * Types a statement. If @a want_value is @c b_true, then warning about 256 * ignored expression value will be supressed for this statement (but not 257 * for nested statemens). This is used in interactive mode. 258 * 259 * @param stype Static typer object. 260 * @param stat Statement to type. 261 * @param want_value @c b_true to allow ignoring expression value. 262 */ 263 void stype_stat(stype_t *stype, stree_stat_t *stat, bool_t want_value) 255 264 { 256 265 #ifdef DEBUG_TYPE_TRACE … … 264 273 case st_raise: stype_raise(stype, stat->u.raise_s); break; 265 274 case st_return: stype_return(stype, stat->u.return_s); break; 266 case st_exps: stype_exps(stype, stat->u.exp_s ); break;275 case st_exps: stype_exps(stype, stat->u.exp_s, want_value); break; 267 276 case st_wef: stype_wef(stype, stat->u.wef_s); break; 268 277 } … … 285 294 printf("Error: Duplicate variable declaration '%s'.\n", 286 295 strtab_get_str(vdecl_s->name->sid)); 287 exit(1);296 stype_note_error(stype); 288 297 } 289 298 … … 387 396 printf("Error: Return statement in " 388 397 "setter.\n"); 389 exit(1);398 stype_note_error(stype); 390 399 } 391 400 … … 406 415 407 416 /** Type expression statement */ 408 static void stype_exps(stype_t *stype, stree_exps_t *exp_s )417 static void stype_exps(stype_t *stype, stree_exps_t *exp_s, bool_t want_value) 409 418 { 410 419 #ifdef DEBUG_TYPE_TRACE … … 413 422 stype_expr(stype, exp_s->expr); 414 423 415 if ( exp_s->expr->titem != NULL)424 if (want_value == b_false && exp_s->expr->titem != NULL) 416 425 printf("Warning: Expression value ignored.\n"); 417 426 } … … 468 477 if (dest == NULL) { 469 478 printf("Error: Conversion destination is not valid.\n"); 470 exit(1); 479 stype_note_error(stype); 480 return expr; 471 481 } 472 482 473 483 if (src == NULL) { 474 484 printf("Error: Conversion source is not valid.\n"); 475 exit(1); 485 stype_note_error(stype); 486 return expr; 476 487 } 477 488 … … 519 530 tdata_item_print(dest); 520 531 printf("'.\n"); 521 exit(1);532 stype_note_error(stype); 522 533 } 523 534 … … 531 542 printf(".\n"); 532 543 533 /* XXX We should rather return a bogus expression of type @a dest */534 exit(1);544 stype_note_error(stype); 545 return expr; 535 546 } 536 547 … … 659 670 } 660 671 672 /** Note a static typing error that has been immediately recovered. */ 673 void stype_note_error(stype_t *stype) 674 { 675 stype->error = b_true; 676 } 677 678 /** Construct a special type item for recovery. */ 679 tdata_item_t *stype_recovery_titem(stype_t *stype) 680 { 681 tdata_item_t *titem; 682 tdata_primitive_t *tprimitive; 683 684 (void) stype; 685 686 titem = tdata_item_new(tic_tprimitive); 687 tprimitive = tdata_primitive_new(tpc_int); 688 689 titem->u.tprimitive = tprimitive; 690 691 return titem; 692 } 693 661 694 /** Get current block visit record. */ 662 695 stype_block_vr_t *stype_get_current_block_vr(stype_t *stype) -
uspace/app/sbi/src/stype.h
r5da468e r1ebc1a62 33 33 34 34 void stype_module(stype_t *stype, stree_module_t *module); 35 void stype_stat(stype_t *stype, stree_stat_t *stat); 35 void stype_stat(stype_t *stype, stree_stat_t *stat, bool_t want_value); 36 37 void stype_note_error(stype_t *stype); 38 tdata_item_t *stype_recovery_titem(stype_t *stype); 36 39 37 40 stree_expr_t *stype_convert(stype_t *stype, stree_expr_t *expr, -
uspace/app/sbi/src/stype_expr.c
r5da468e r1ebc1a62 182 182 nameref->name); 183 183 184 if (sym == NULL) { 185 /* Not found. */ 186 if (stype->current_csi != NULL) { 187 printf("Error: Symbol '%s' not found in '", 188 strtab_get_str(nameref->name->sid)); 189 symbol_print_fqn(csi_to_symbol(stype->current_csi)); 190 printf("'.\n"); 191 } else { 192 printf("Error: Symbol '%s' not found.\n", 193 strtab_get_str(nameref->name->sid)); 194 } 195 stype_note_error(stype); 196 *rtitem = stype_recovery_titem(stype); 197 return; 198 } 199 184 200 switch (sym->sc) { 185 201 case sc_var: … … 273 289 274 290 if (binop->arg1->titem == NULL) { 275 /* XXX Make this an error when ready. */276 291 printf("Error First binary operand has no value.\n"); 277 exit(1); 292 stype_note_error(stype); 293 if (binop->arg2->titem != NULL) 294 *rtitem = binop->arg2->titem; 295 else 296 *rtitem = stype_recovery_titem(stype); 297 return; 278 298 } 279 299 280 300 if (binop->arg2->titem == NULL) { 281 /* XXX Make this an error when ready. */282 301 printf("Error: Second binary operand has no value.\n"); 283 exit(1); 302 stype_note_error(stype); 303 *rtitem = binop->arg1->titem; 304 return; 284 305 } 285 306 … … 292 313 tdata_item_print(binop->arg2->titem); 293 314 printf("').\n"); 294 exit(1); 315 stype_note_error(stype); 316 *rtitem = binop->arg1->titem; 317 return; 295 318 } 296 319 … … 311 334 tdata_item_print(titem); 312 335 printf("').\n"); 313 exit(1); 336 stype_note_error(stype); 337 *rtitem = titem; 338 break; 314 339 } 315 340 … … 334 359 case tpc_nil: 335 360 printf("Unimplemented; Binary operation on nil.\n"); 336 exit(1); 361 stype_note_error(stype); 362 rtpc = tpc_nil; 363 break; 337 364 case tpc_string: 338 365 if (binop->bc != bo_plus) { 339 366 printf("Unimplemented: Binary operation(%d) " 340 367 "on strings.\n", binop->bc); 341 exit(1);368 stype_note_error(stype); 342 369 } 343 370 rtpc = tpc_string; … … 345 372 case tpc_resource: 346 373 printf("Error: Cannot apply operator to resource type.\n"); 347 exit(1); 374 stype_note_error(stype); 375 rtpc = tpc_resource; 348 376 } 349 377 … … 425 453 if (arg_ti == NULL) { 426 454 printf("Error: Argument of access has no value.\n"); 427 exit(1); 455 stype_note_error(stype); 456 *rtitem = stype_recovery_titem(stype); 457 return; 428 458 } 429 459 … … 443 473 case tic_tfun: 444 474 printf("Error: Using '.' operator on a function.\n"); 445 exit(1); 475 stype_note_error(stype); 476 *rtitem = stype_recovery_titem(stype); 446 477 break; 447 478 } … … 459 490 tdata_item_print(arg_ti); 460 491 printf("'.\n"); 461 exit(1); 492 stype_note_error(stype); 493 *rtitem = stype_recovery_titem(stype); 462 494 } 463 495 … … 488 520 printf("' has no member named '%s'.\n", 489 521 strtab_get_str(access->member_name->sid)); 490 exit(1); 522 *rtitem = stype_recovery_titem(stype); 523 return; 491 524 } 492 525 … … 500 533 printf("Error: Accessing object member which is nested " 501 534 "CSI.\n"); 502 exit(1); 535 stype_note_error(stype); 536 *rtitem = stype_recovery_titem(stype); 537 break; 503 538 case sc_fun: 504 539 fun = symbol_to_fun(member_sym); … … 536 571 tdata_item_print(arg_ti); 537 572 printf("'.\n"); 538 exit(1); 573 stype_note_error(stype); 574 *rtitem = stype_recovery_titem(stype); 539 575 } 540 576 … … 550 586 tdata_item_print(arg_ti); 551 587 printf("'.\n"); 552 exit(1); 588 stype_note_error(stype); 589 *rtitem = stype_recovery_titem(stype); 553 590 } 554 591 … … 639 676 symbol_print_fqn(fun_to_symbol(fun)); 640 677 printf("'.\n"); 641 exit(1);678 stype_note_error(stype); 642 679 } 643 680 … … 646 683 symbol_print_fqn(fun_to_symbol(fun)); 647 684 printf("'.\n"); 648 exit(1);685 stype_note_error(stype); 649 686 } 650 687 … … 696 733 case tic_tfun: 697 734 printf("Error: Indexing a function.\n"); 698 exit(1); 735 stype_note_error(stype); 736 *rtitem = stype_recovery_titem(stype); 699 737 break; 700 738 } … … 724 762 tdata_item_print(base_ti); 725 763 printf("'.\n"); 726 exit(1); 764 stype_note_error(stype); 765 *rtitem = stype_recovery_titem(stype); 727 766 } 728 767 … … 756 795 tdata_item_print(base_ti); 757 796 printf("' which does not have an indexer.\n"); 758 exit(1); 797 stype_note_error(stype); 798 *rtitem = stype_recovery_titem(stype); 799 return; 759 800 } 760 801 … … 791 832 792 833 printf("Error: Array index is not an integer.\n"); 793 exit(1);834 stype_note_error(stype); 794 835 } 795 836 … … 800 841 printf("Error: Using %d indices with array of rank %d.\n", 801 842 arg_count, base_ti->u.tarray->rank); 802 exit(1);843 stype_note_error(stype); 803 844 } 804 845 … … 817 858 tdata_item_print(base_ti); 818 859 printf("'.\n"); 819 exit(1); 860 stype_note_error(stype); 861 *rtitem = stype_recovery_titem(stype); 820 862 } 821 863 … … 857 899 tdata_item_print(as_op->arg->titem); 858 900 printf("'.\n"); 859 exit(1);901 stype_note_error(stype); 860 902 } 861 903 -
uspace/app/sbi/src/stype_t.h
r5da468e r1ebc1a62 70 70 /** Procedure VR for the current procedure. */ 71 71 stype_proc_vr_t *proc_vr; 72 73 /** @c b_true if an error occured. */ 74 bool_t error; 72 75 } stype_t; 73 76 -
uspace/app/sbi/src/symbol.c
r5da468e r1ebc1a62 75 75 } 76 76 77 /** Lookup symbol reference in CSI. */ 77 /** Lookup symbol reference in CSI. 78 * 79 * @param prog Program to look in. 80 * @param scope CSI in @a prog which is the base for references. 81 * @param name Identifier of the symbol. 82 * 83 * @return Symbol or @c NULL if symbol not found. 84 */ 78 85 stree_symbol_t *symbol_lookup_in_csi(stree_program_t *prog, stree_csi_t *scope, 79 86 stree_ident_t *name) … … 92 99 if (symbol == NULL) 93 100 symbol = symbol_search_global(prog, name); 94 95 if (symbol == NULL) {96 printf("Error: Symbol '%s' not found.\n", strtab_get_str(name->sid));97 exit(1);98 }99 101 100 102 return symbol; -
uspace/app/sbi/src/tdata.c
r5da468e r1ebc1a62 177 177 178 178 printf("["); 179 for (i = 0; i < tarray->rank ; ++i)179 for (i = 0; i < tarray->rank - 1; ++i) 180 180 printf(","); 181 181 printf("]");
Note:
See TracChangeset
for help on using the changeset viewer.