📄 seh.c
字号:
/* seh.c: Structured exception handling in the compiler */
#include "c.h"
extern int getTvalValue(void);
extern int getLevel(void);
int hasExceptions=0;
typedef struct tagExceptionInfo {
struct tagExceptionInfo *Next;
struct tagExceptionInfo *Previous;
int l1;
int l2;
int l3;
int value;
int Flags;
} ExceptionInfo;
#define FINISHED 1
static ExceptionInfo *pCurrentException=NULL;
static ExceptionInfo *rootException=NULL;
static int StaticDataEmitted = 0;
/* Add another exception to the exception stack */
ExceptionInfo *PushException(void)
{
ExceptionInfo *result;
if (rootException == NULL) {
rootException = (ExceptionInfo *)allocate(sizeof(ExceptionInfo),FUNC);
result = rootException;
memset(result,0,sizeof(ExceptionInfo));
}
else {
/* search the last element */
result = rootException;
while (result->Next) {
result = result->Next;
}
result->Next = (ExceptionInfo *)allocate(sizeof(ExceptionInfo),FUNC);
memset(result->Next,0,sizeof(ExceptionInfo));
result->Next->Previous = result;
result = result->Next;
}
return(result);
}
/*
No 'free' is done, since all the data is allocated in the FUNC heap
that will be freed at the end of the function.
*/
void PopException(void)
{
if (pCurrentException->Previous) {
pCurrentException = pCurrentException->Previous;
pCurrentException->Next = NULL;
}
else {
rootException = NULL;
pCurrentException = NULL;
}
}
/*
Utility function to add an assembler instruction to the code list.
*/
static void AddAsm(char *str)
{
char *s;
s = stringn(str,strlen(str));
walk(0, 0, 0);
code(Start); /* prevent unreachable code message */
code(Asm);
codelist->u.acode.code = s;
codelist->u.acode.argv = NULL;
}
int doTry(void)
{
char tmpnom[25],tmpbuf[256];
int l1,l2,l3;
Symbol sl;
/* 1. Push the exceptions stack by one */
pCurrentException = PushException();
/* Announce to the runtime that the static data is active
within this block. Exceptions are enabled */
AddAsm("\tmovl\t$0x0,-4(%ebp)");
/* Update this global variable used in a few parts of lcc */
hasExceptions++;
/* Generate 3 labels:
The first (label 1) marks the beginning of the first part
of code that will be called to determine if the handler
handles the exception or not.
The second label will announce the start of the exception
handler.
The third announces the continuation of the normal code
section
*/
l1 = genlabel(1);
sl = findlabel(l1);
sl->ref = 1.0;
sl->firstuse = sl->lastuse = StatementCount;
l2 = genlabel(1);
sl = findlabel(l2);
sl->ref = 1.0;
sl->firstuse = sl->lastuse = StatementCount;
l3 = genlabel(1);
sl = findlabel(l3);
sl->ref = 1.0;
sl->firstuse = sl->lastuse = StatementCount;
pCurrentException->l1 = l1;
pCurrentException->l2 = l2;
pCurrentException->l3 = l3;
/* The static data needed here should be emitted only once
per compiled file
*/
if (StaticDataEmitted == 0) {
AddAsm("\t.data");
sprintf(tmpbuf,"_$ExcepData:",tmpnom);
AddAsm(tmpbuf);
AddAsm("\t.long\t0xffffffff");
sprintf(tmpbuf,"\t.long\t_$%d",l1);
AddAsm(tmpbuf);
sprintf(tmpbuf,"\t.long\t_$%d",l2);
AddAsm(tmpbuf);
AddAsm("\t.text");
StaticDataEmitted = 1;
}
/* If we are in a nested exception block, the static data
should point to the two labels that contain the two blocks
of code to be called by the runtime
*/
if (pCurrentException != rootException) {
AddAsm("\tmovl\t$_$ExcepData,%eax");
sprintf(tmpbuf,"\tmovl\t$_$%d,4(%%eax)",l1);
AddAsm(tmpbuf);
sprintf(tmpbuf,"\tmovl\t$_$%d,8(%%eax)",l2);
AddAsm(tmpbuf);
}
return(1);
}
static void RestorePreviousException(void)
{
char tmpbuf[256];
/*
To avoid traps in the trap handlers, the runtime stores
a continuation address at -4(%ebp). If we arrive here,
everything is O.K. We have to restore then the zero at
-4(%ebp) to go on normally
*/
AddAsm("\tmovl\t$0x0,-4(%ebp)");
AddAsm("\tmovl\t$_$ExcepData,%eax");
sprintf(tmpbuf,"\tmovl\t$_$%d,4(%%eax)",pCurrentException->Previous->l1);
AddAsm(tmpbuf);
sprintf(tmpbuf,"\tmovl\t$_$%d,8(%%eax)",pCurrentException->Previous->l2);
AddAsm(tmpbuf);
}
static void EmitFilterCode(void)
{
char tmpbuf[256];
sprintf(tmpbuf,"_$%d:",pCurrentException->l1);
AddAsm(tmpbuf);
sprintf(tmpbuf,"\tmovl\t$%d,%%eax",pCurrentException->value);
AddAsm(tmpbuf);
AddAsm("\tret");
}
int FinishTryBlock(void)
{
char tmpbuf[256];
if (pCurrentException->Flags & FINISHED) return(0);
if (pCurrentException == rootException) {
/* no exceptions are now active. Announce it to the
runtime
*/
AddAsm("\tmovl\t$-1,-4(%ebp)");
}
else {
RestorePreviousException();
}
/* emit a jump to the end of the exception stuff */
sprintf(tmpbuf,"\tjmp\t_$%d",pCurrentException->l3);
AddAsm(tmpbuf);
/* Avoid emitting this code again */
pCurrentException->Flags |= FINISHED;
return(1);
}
int doExcept(void)
{
char tmpbuf[20];
/* No error treatment yet. Any syntax error leaves the parser
in a mess...
*/
t = gettok();
if (t != '(') {
error(StrTab[98]);// <Incorrect __except syntax\n>
return(0);
}
t = gettok();
if (t != ICON) {
error(StrTab[99]);// <Incorrect __except expression!>
return(0);
}
/* This should be actually an evaluation of an integer expression */
pCurrentException->value = getTvalValue();
t = gettok();
if (t != ')') {
error(StrTab[100]);// <missing ')' in __except expression>
return(0);
}
FinishTryBlock();
EmitFilterCode();
/* Emit the label that marks the beginning of the exception handler
code
*/
sprintf(tmpbuf,"_$%d:",pCurrentException->l2);
AddAsm(tmpbuf);
/* Emit code to restore the stack when the exception
handler is called
*/
AddAsm("\tmovl\t-24(%ebp),%esp");
/* Parse the exception handler code */
t = gettok(); /* swallow the '{' */
compound(0,NULL,getLevel());
if (pCurrentException == rootException) {
/*
We are at the end of the top level exception block.
Announce to the runtime there is no exception handler active
*/
AddAsm("\tmovl\t$-1,-4(%ebp)");
}
else {
RestorePreviousException();
}
/* Continuation of the normal code sequence */
sprintf(tmpbuf,"_$%d:",pCurrentException->l3);
AddAsm(tmpbuf);
/* Clean up the exception stack, popping one level */
PopException();
return(1);
}
void ResetExceptions(void)
{
rootException = NULL;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -