📄 gbc_trans_ctrl.c
字号:
/*************************************************************************** trans_ctrl.c Control structures compiler (c) 2000-2004 Beno� Minisini <gambas@users.sourceforge.net> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 1, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.***************************************************************************/#define _TRANS_CTRL_C#include <stdlib.h>#include <string.h>#include <stdio.h>#include "gb_common.h"#include "gb_error.h"#include "gbc_compile.h"#include "gbc_trans.h"#include "gb_code.h"#include "gb_limit.h"/*#define DEBUG*//*#define DEBUG_GOTO*/PRIVATE int ctrl_level;PRIVATE int ctrl_id;PRIVATE int ctrl_local;PRIVATE TRANS_CTRL ctrl_data[MAX_CTRL_LEVEL];PRIVATE TRANS_CTRL *current_ctrl;PRIVATE TRANS_GOTO *goto_info;PRIVATE TRANS_LABEL *label_info;PRIVATE short *ctrl_parent;PRIVATE void control_set_value(long value){ if (ctrl_level <= 0) return; current_ctrl->value = value;}PRIVATE long control_get_value(){ if (ctrl_level <= 0) return 0; return current_ctrl->value;}PRIVATE void control_add_pos(short **tab_pos, short pos){ if (!(*tab_pos)) ARRAY_create(tab_pos); *((short *)ARRAY_add(tab_pos)) = pos;}PRIVATE void control_add_current_pos(){ control_add_pos(¤t_ctrl->pos, CODE_get_current_pos());}PRIVATE void control_jump_each_pos_with(short *tab_pos){ int i; if (!tab_pos) return; for (i = 0; i < ARRAY_count(tab_pos); i++) CODE_jump_length(tab_pos[i], CODE_get_current_pos());}PRIVATE void control_jump_each_pos(){ control_jump_each_pos_with(current_ctrl->pos);}PRIVATE TRANS_CTRL *control_get_inner(void){ int level = ctrl_level; TRANS_CTRL *ctrl_look; for(;;) { if (!level) return NULL; level--; ctrl_look = &ctrl_data[level]; if ((ctrl_look->type == RS_DO) || (ctrl_look->type == RS_WHILE) || (ctrl_look->type == RS_REPEAT) || (ctrl_look->type == RS_FOR) || (ctrl_look->type == RS_EACH)) return ctrl_look; }}PRIVATE TRANS_CTRL *control_get_inner_with(void){ int level = ctrl_level; TRANS_CTRL *ctrl_look; for(;;) { if (!level) return NULL; level--; ctrl_look = &ctrl_data[level]; if (ctrl_look->type == RS_WITH) return ctrl_look; }}PRIVATE void add_goto(long index){ TRANS_GOTO *info; if (goto_info == NULL) ARRAY_create(&goto_info); info = ARRAY_add(&goto_info); info->index = index; info->pos = CODE_get_current_pos(); info->ctrl_id = (ctrl_level == 0) ? 0 : current_ctrl->id; info->line = JOB->line; #ifdef DEBUG_GOTO printf("add_goto: ctrl_id = %d (%ld)\n", info->ctrl_id, ARRAY_count(goto_info)); #endif CODE_jump();}PRIVATE void control_enter(long type){ short *parent; if (ctrl_level >= MAX_CTRL_LEVEL) THROW("Too many nested control structures."); ctrl_id++; current_ctrl = &ctrl_data[ctrl_level]; current_ctrl->type = type; current_ctrl->value = 0; current_ctrl->pos = NULL; current_ctrl->state = 0; current_ctrl->local = ctrl_local; current_ctrl->id = ctrl_id; current_ctrl->loop_var = -1; parent = ARRAY_add(&ctrl_parent); if (ctrl_level == 0) *parent = 0; else *parent = ctrl_data[ctrl_level - 1].id; switch (type) { case RS_FOR: case RS_EACH: ctrl_local += 2; break; case RS_SELECT: case RS_WITH: ctrl_local += 1; break; } JOB->func->nctrl = Max(JOB->func->nctrl, ctrl_local - JOB->func->nlocal); ctrl_level++;}PRIVATE void control_leave(){ control_jump_each_pos_with(current_ctrl->pos_break); ARRAY_delete(¤t_ctrl->pos); ARRAY_delete(¤t_ctrl->pos_break); ARRAY_delete(¤t_ctrl->pos_continue); ctrl_local = current_ctrl->local; ctrl_level--; if (ctrl_level > 0) current_ctrl = &ctrl_data[ctrl_level - 1]; else current_ctrl = NULL;}PRIVATE void control_check(long type, const char *msg1, const char *msg2){ if (ctrl_level <= 0) THROW(msg1); if (current_ctrl->type != type) THROW(msg2);}PRIVATE void control_check_two(long type1, long type2, const char *msg1, const char *msg2){ if (ctrl_level <= 0) THROW(msg1); if (current_ctrl->type != type1 && current_ctrl->type != type2) THROW(msg2);}static void control_check_loop_var(short var){ int i; for (i = 0; i < (ctrl_level - 1); i++) { if (ctrl_data[i].loop_var == var) THROW("Loop variable already in use"); } current_ctrl->loop_var = var;}PUBLIC void TRANS_control_init(){ ctrl_level = 0; ctrl_id = 0; current_ctrl = NULL; goto_info = NULL; label_info = NULL; ctrl_local = JOB->func->nlocal; JOB->func->nctrl = 0; ARRAY_create(&ctrl_parent);}PUBLIC void TRANS_control_exit(){ int i; CLASS_SYMBOL *sym; long line; TRANS_LABEL *label; short id; /* R�olution des GOTO */ if (goto_info) { line = JOB->line; for (i = 0; i < ARRAY_count(goto_info); i++) { JOB->line = goto_info[i].line; /*printf("%d\n", JOB->line);*/ sym = CLASS_get_symbol(JOB->class, goto_info[i].index); if (TYPE_get_kind(sym->local.type) != TK_LABEL) THROW("Label '&1' not declared", TABLE_get_symbol_name(JOB->class->table, goto_info[i].index)); label = &label_info[sym->local.value]; id = goto_info[i].ctrl_id; for(;;) { if (label->ctrl_id == id) break; if (id == 0) THROW("Forbidden GOTO"); #ifdef DEBUG_GOTO printf("id = %d ctrl_parent[id - 1] = %d (%ld)\n", id, ctrl_parent[id - 1], ARRAY_count(ctrl_parent)); #endif id = ctrl_parent[id - 1]; } CODE_jump_length(goto_info[i].pos, label->pos); } JOB->line = line; } /* Remove previously declared labels */ if (label_info) { for (i = 0; i < ARRAY_count(label_info); i++) { sym = CLASS_get_symbol(JOB->class, label_info[i].index); TYPE_clear(&sym->local.type); } } ARRAY_delete(&goto_info); ARRAY_delete(&ctrl_parent); ARRAY_delete(&label_info); /* On ne doit pas laisser une structure de controle ouverte */ if (ctrl_level == 0) return; switch (ctrl_data[ctrl_level - 1].type) { case RS_IF: THROW("ENDIF missing"); case RS_FOR: case RS_EACH: THROW("NEXT missing"); case RS_DO: THROW("LOOP missing"); case RS_REPEAT: THROW("UNTIL missing"); case RS_WHILE: THROW("WEND missing"); case RS_SELECT: THROW("END SELECT missing"); case RS_WITH: THROW("END WITH missing"); }}PUBLIC void TRANS_if(){ control_enter(RS_IF); TRANS_expression(FALSE); if (!PATTERN_is(*JOB->current, RS_THEN)) THROW("Syntax error. THEN expected"); JOB->current++; control_set_value(CODE_get_current_pos()); CODE_jump_if_false(); if (PATTERN_is_newline(*JOB->current)) return; TRANS_statement(); TRANS_endif();}PUBLIC void TRANS_else(){ control_check(RS_IF, "ELSE without IF", "Unexpected ELSE"); if (current_ctrl->state) THROW("Unexpected ELSE"); control_add_current_pos(); CODE_jump(); CODE_jump_length(control_get_value(), CODE_get_current_pos()); if (PATTERN_is(*JOB->current, RS_IF)) { JOB->current++; TRANS_expression(FALSE); if (!PATTERN_is(*JOB->current, RS_THEN)) THROW("Syntax error. THEN expected"); JOB->current++; control_set_value(CODE_get_current_pos()); CODE_jump_if_false(); } else current_ctrl->state = 1;}PUBLIC void TRANS_endif(){ control_check(RS_IF, "ENDIF without IF", "Unexpected ENDIF"); if (current_ctrl->state == 0) CODE_jump_length(control_get_value(), CODE_get_current_pos()); control_jump_each_pos(); control_leave();}PUBLIC void TRANS_goto(){ long index; if (!PATTERN_is_identifier(*JOB->current)) THROW(E_SYNTAX); index = PATTERN_index(*JOB->current); JOB->current++; add_goto(index);}PUBLIC void TRANS_do(PATTERN type){ boolean is_until; control_enter(type); control_set_value(CODE_get_current_pos()); if (type == RS_REPEAT) return; is_until = PATTERN_is(*JOB->current, RS_UNTIL); if (PATTERN_is(*JOB->current, RS_WHILE) || is_until) { JOB->current++; TRANS_expression(FALSE); control_add_current_pos(); if (is_until) CODE_jump_if_true(); else CODE_jump_if_false(); }}PUBLIC void TRANS_loop(PATTERN type){ short pos;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -