/***************************************************************/ /* */ /* IFELSE.C */ /* */ /* Logic for tracking the state of the IF... ELSE... ENDIF */ /* */ /* This file is part of REMIND. */ /* Copyright (C) 1992-2025 by Dianne Skoll */ /* SPDX-License-Identifier: GPL-2.0-only */ /* */ /***************************************************************/ #include "config.h" #include "types.h" #include "protos.h" #include "globals.h" #include "err.h" /* Allow up to 64 levels if IF...ELSE nesting across all files */ #define IF_NEST 64 /* Points to the next unused IF entry structure */ static int if_pointer = 0; /* The base pointer for the current file */ static int base_pointer = 0; /* True if a "RETURN" statement was encountered in current file */ static int return_encountered = 0; /* * The current state of the IF...ELSE...ENDIF context is stored in * an array of "ifentry" objects, from the outermost to the * innermost. * * The if_true element is true of the IF expression was true; false * otherwise. * * The before_else element is true if the current line is after * the IF but before any ELSE; false otherwise. * * The was_constant element is true if the IF expression was constant. * * Each time a new file is INCLUDed, we reset the base pointer to the * current location of the if_pointer. */ typedef struct ifentry_struct { int lineno; unsigned char if_true; unsigned char before_else; unsigned char was_constant; } ifentry; static ifentry IfArray[IF_NEST]; /***************************************************************/ /* */ /* push_if - push an if entry onto the stack. */ /* */ /***************************************************************/ int push_if(int is_true, int was_constant) { if (if_pointer >= IF_NEST) { return E_NESTED_IF; } IfArray[if_pointer].if_true = is_true; IfArray[if_pointer].before_else = 1; IfArray[if_pointer].was_constant = was_constant; IfArray[if_pointer].lineno = LineNo; if_pointer++; return OK; } /***************************************************************/ /* */ /* if_stack_full - returns OK or E_NESTED_IF */ /* */ /***************************************************************/ int if_stack_full(void) { if (if_pointer >= IF_NEST) { return E_NESTED_IF; } return OK; } /***************************************************************/ /* */ /* encounter_else - note that the most-recently-pushed IF */ /* has encountered an ELSE */ /* */ /***************************************************************/ int encounter_else(void) { if (if_pointer <= base_pointer) { return E_ELSE_NO_IF; } if (!IfArray[if_pointer-1].before_else) { return E_ELSE_NO_IF; } IfArray[if_pointer-1].before_else = 0; return OK; } /***************************************************************/ /* */ /* DoReturn - handle the RETURN command */ /* */ /***************************************************************/ int DoReturn(ParsePtr p) { int r = VerifyEoln(p); return_encountered = 1; return r; } /***************************************************************/ /* */ /* encounter_endif - note that the most-recently-pushed IF */ /* has encountered an ENDIF */ /* */ /***************************************************************/ int encounter_endif(void) { if (if_pointer <= base_pointer) { return E_ENDIF_NO_IF; } if_pointer--; return OK; } /***************************************************************/ /* */ /* get_base_if_pointer - get the current base_pointer */ /* */ /***************************************************************/ int get_base_if_pointer(void) { return base_pointer; } /***************************************************************/ /* */ /* get_if_pointer - get the current if_pointer */ /* */ /***************************************************************/ int get_if_pointer(void) { return if_pointer; } /***************************************************************/ /* */ /* set_base_if_pointer - set the base_pointer to n */ /* */ /***************************************************************/ void set_base_if_pointer(int n) { base_pointer = n; } /***************************************************************/ /* */ /* should_ignore_line - return 1 if current line should be */ /* ignored. */ /* */ /***************************************************************/ int should_ignore_line(void) { int i; if (return_encountered) { return 1; } for (i=base_pointer; i base_pointer) { if (!Hush) { fprintf(ErrFp, tr("%s(%d): IF without ENDIF"), fname, IfArray[if_pointer-1].lineno); fprintf(ErrFp, "\n"); } if_pointer--; } }