win 32 写多项试运算程序
在这个论坛上看见很多人说要写一个多项式运算,下面是我写的一个程序是以win 32 的形式写的,能持支双符号运算,并且还能像编译器一样能检查项式的错误。。。。。。。现在发出来给大家学习一下本人在学win 32 SDK编程很想认识一些学windows 程序设计的朋友们
// 多项式运算.cpp : Defines the entry point for the application.
//
#include "stdafx.h"
#include "resource.h"
#include "tree.h"
#define MAX_LOADSTRING 100
// Global Variables:
//HINSTANCE hInst; // current instance
//TCHAR szTitle[MAX_LOADSTRING]; // The title bar text
//TCHAR szWindowClass[MAX_LOADSTRING]; // The title bar text
// Foward declarations of functions included in this code module:
//ATOM MyRegisterClass(HINSTANCE hInstance);
//BOOL InitInstance(HINSTANCE, int);
//LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
//LRESULT CALLBACK About(HWND, UINT, WPARAM, LPARAM);
BOOL CALLBACK Dialog(HWND, UINT, WPARAM, LPARAM);
HINSTANCE hInst;
int APIENTRY WinMain(HINSTANCE hInstance, //win32主程序
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
// TODO: Place code here.
// MSG msg;
// HACCEL hAccelTable;
hInst = hInstance;
DialogBox(hInstance, (LPCTSTR)IDD_DIALOG1, NULL, (DLGPROC)Dialog); //创建一个对话框 IDD_DIALOG1 是一个对话框资源标识
// Initialize global strings
// LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
// LoadString(hInstance, IDC_MY, szWindowClass, MAX_LOADSTRING);
// MyRegisterClass(hInstance);
// Perform application initialization:
// if (!InitInstance (hInstance, nCmdShow))
// {
// return FALSE;
// }
//
// hAccelTable = LoadAccelerators(hInstance, (LPCTSTR)IDC_MY);
// Main message loop:
// while (GetMessage(&msg, NULL, 0, 0))
// {
// if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
// {
// TranslateMessage(&msg);
// DispatchMessage(&msg);
// }
// }
return 0;//msg.wParam;
}
//
// FUNCTION: MyRegisterClass()
//
// PURPOSE: Registers the window class.
//
// COMMENTS:
//
// This function and its usage is only necessary if you want this code
// to be compatible with Win32 systems prior to the 'RegisterClassEx'
// function that was added to Windows 95. It is important to call this function
// so that the application will get 'well formed' small icons associated
// with it.
//
//ATOM MyRegisterClass(HINSTANCE hInstance)
//{
// WNDCLASSEX wcex;
//
// wcex.cbSize = sizeof(WNDCLASSEX);
// wcex.style = CS_HREDRAW | CS_VREDRAW;
// wcex.lpfnWndProc = (WNDPROC)WndProc;
// wcex.cbClsExtra = 0;
// wcex.cbWndExtra = 0;
// wcex.hInstance = hInstance;
// wcex.hIcon = LoadIcon(hInstance, (LPCTSTR)IDI_MY);
// wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
// wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
// wcex.lpszMenuName = (LPCSTR)IDC_MY;
// wcex.lpszClassName = szWindowClass;
// wcex.hIconSm = LoadIcon(wcex.hInstance, (LPCTSTR)IDI_SMALL);
// return RegisterClassEx(&wcex);
//}
//
// FUNCTION: InitInstance(HANDLE, int)
//
// PURPOSE: Saves instance handle and creates main window
//
// COMMENTS:
//
// In this function, we save the instance handle in a global variable and
// create and display the main program window.
//
//BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
//{
// HWND hWnd;
//
// hInst = hInstance; // Store instance handle in our global variable
// hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
// CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
// if (!hWnd)
// {
// return FALSE;
//}
//ShowWindow(hWnd, nCmdShow);
//UpdateWindow(hWnd);
//return TRUE;
//}
//
// FUNCTION: WndProc(HWND, unsigned, WORD, LONG)
//
// PURPOSE: Processes messages for the main window.
//
// WM_COMMAND - process the application menu
// WM_PAINT - Paint the main window
// WM_DESTROY - post a quit message and return
//
//
//LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
//{
// int wmId, wmEvent;
// PAINTSTRUCT ps;
// HDC hdc;
// TCHAR szHello[MAX_LOADSTRING];
// LoadString(hInst, IDS_HELLO, szHello, MAX_LOADSTRING);
//
// switch (message)
// {
// case WM_COMMAND:
// wmId = LOWORD(wParam);
// wmEvent = HIWORD(wParam);
// // Parse the menu selections:
// switch (wmId)
// {
// case IDM_ABOUT:
// DialogBox(hInst, (LPCTSTR)IDD_ABOUTBOX, hWnd, (DLGPROC)About);
// break;
// case IDM_EXIT:
// DestroyWindow(hWnd);
// break;
// default:
// return DefWindowProc(hWnd, message, wParam, lParam);
// }
// break;
// case WM_PAINT:
// hdc = BeginPaint(hWnd, &ps);
// // TODO: Add any drawing code here...
// RECT rt;
// GetClientRect(hWnd, &rt);
// DrawText(hdc, szHello, strlen(szHello), &rt, DT_CENTER);
// EndPaint(hWnd, &ps);
// break;
// case WM_DESTROY:
// PostQuitMessage(0);
// break;
// default:
// return DefWindowProc(hWnd, message, wParam, lParam);
// }
//return 0;
//}
// Mesage handler for about box.
//LRESULT CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
//{
// switch (message)
// {
// case WM_INITDIALOG:
// return TRUE;
//
// case WM_COMMAND:
// if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
// {
// EndDialog(hDlg, LOWORD(wParam));
// return TRUE;
// }
// break;
// }
// return FALSE;
//}
//void DeleteString()
//{
// while(count_error--)
// {
// free(error[count_error]);
// error[count_error] = NULL;
// }
// while(count_warn--)
// {
// free(warn[count_warn]);
// warn[count_warn] = NULL;
// }
// count_error = count_warn = 0;
//}
BOOL CALLBACK Dialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) //回调函数
{
static pBinaryTree p = NULL;
static BOOL change = FALSE;
int i,j;
switch (message)
{
case WM_INITDIALOG:
SetWindowText(GetDlgItem(hDlg,IDC_STATIC1),TEXT(""));
return TRUE;
case WM_COMMAND:
if (LOWORD(wParam) == IDOK && change && !count_error)
{
TCHAR string[100];
i = GetWindowText(GetDlgItem(hDlg,IDC_EDIT1),string,100);
if(i == 0) //如果编辑框无字符
{
SetWindowText(GetDlgItem(hDlg,IDC_STATIC1),TEXT(""));
change = FALSE;
}
Delete(p);
CheckStrings(string,i); //检查是否有错误
HWND ListHwnd = GetDlgItem(hDlg,IDC_LIST1); //取得例表框的窗口句柄
SendMessage(ListHwnd,LB_RESETCONTENT,0,0); //清除当前的信息
if(count_error) //有错误
{
MessageBeep(MB_ICONINFORMATION);
for(j = 0; j < count_error; j++)
{
SendMessage(ListHwnd,LB_ADDSTRING,0,(LPARAM)error[j]); //将错误信息加入列表框
free(error[j]); //复制后删除字符串
error[j] = NULL; //指针为空
}
}
if(count_warn) //输出注意事项
{
for(j = 0; j < count_warn; j++)
{
SendMessage(ListHwnd,LB_ADDSTRING,(WPARAM) 0,(LPARAM)warn[j]);
free(warn[j]);
warn[j] = NULL;
}
}
//否则出输出结果
if(!count_error) //没错误输出结果
{
TCHAR a[11];
p = CreateTree(string,i);
sprintf(a,"%d",Number(p));
SetWindowText(GetDlgItem(hDlg,IDC_STATIC1),a);
}
for(j = 0; j < count_error; j++) free(error[j]);
for(j = 0; j < count_warn; j++) free(warn[j]);
change = FALSE;
count_error = count_warn = 0;
}
if(LOWORD(wParam) == IDC_EDIT1 && HIWORD(wParam) == EN_CHANGE)
{
change = TRUE; //编辑框发生改变change为真
}
else if(LOWORD(wParam) == IDC_BUTTON1)
{
SetWindowText(GetDlgItem(hDlg,IDC_EDIT1),TEXT("0"));
SetWindowText(GetDlgItem(hDlg,IDC_STATIC1),TEXT(""));
SendMessage(GetDlgItem(hDlg,IDC_LIST1),LB_RESETCONTENT,0,0);
//DeleteString();
//count_error = count_warn = 0;
}
return TRUE;
case WM_PAINT:
{
HICON hIcon = LoadIcon(hInst,MAKEINTRESOURCE(IDB_BITMAP1));
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hDlg,&ps);
DrawIcon(hdc,0,0,hIcon);
EndPaint(hDlg,&ps);
}
return TRUE;
case WM_CLOSE:
if(IDYES == MessageBox(hDlg,"Are you sure!!","message",MB_YESNO|MB_ICONINFORMATION))
{
Delete(p);
SendMessage(hDlg,WM_DESTROY,0,0);
return TRUE;
}
break;
case WM_DESTROY:
EndDialog(hDlg, LOWORD(wParam));
PostQuitMessage(0);
return TRUE;
}
return FALSE;
}
/////////////////////////////////////////////////////////////////////////头文件
#ifndef STR_H
#define STR_H
#include <string.h>
#include <stdio.h>
#include "stdafx.h"
#define MAX_CHAR 50
#define ADD 0x1 //加
#define SUM 0x2 //减
#define CMP 0x4 //*
#define DIV 0x8 //除
#define RUN (ADD|SUM|CMP|DIV) //运算符
#define NUM 0xc //数字符
#define LEFT 0x9 //左括号
#define RIGHT 0xa //右括号
#define ERRORS 0xb //错误字符
#define VIOD 0xd //空格
#define TOP 0xe //小数点
#define ZERO 0x0 //无
TCHAR *error[MAX_CHAR]; //错误提示输出指针
TCHAR *warn [MAX_CHAR];
//TCHAR Buffer[MAX_CHAR]; //转换缓冲区
int count_error = 0, count_warn = 0; //统计错误
bool IsNumber(const char n) //判断是否是操作数
{
if((n >= 0x30) && (n <= 0x39)) return true;
return false;
}
bool IsChar(const char n) //判断是否是运算符
{
return ((n == 0x2a) || (n == 0x2b) || (n == 0x2d) || (n == 0x2f));
}
bool IsChars(const char ch)
{
return (((ch <= 0x5a) || (ch >= 0x41)) || ((ch <= 0x7a) || (ch >= 0x61)));
}
char *ToNumber(char a[], int e = 1) //拆成字符串
{
if(e & 0x80000000) abort();
if(e < 1) e=1;
char *p = (char*)calloc(e+1,sizeof(char));
p[e] = 0x0;
for(int i = 0; i < e&&a[i]; i++) p[i] = a[i];
return p;
}
int Numbers(char *ch, int len) //转换整数函数
{
int b = 0, ten = 0, sig = 0;
int i = 0;
if(ch[i] == '-' || ch[i] == '+') i++;
for(int j = i; j < len; j++)
{
if(b) ten = 10;
switch(ch[j])
{
case '0': if(b) b *= ten; break;
case '1': b = ten * b + 1; break;
case '2': b = ten * b + 2; break;
case '3': b = ten * b + 3; break;
case '4': b = ten * b + 4; break;
case '5': b = ten * b + 5; break;
case '6': b = ten * b + 6; break;
case '7': b = ten * b + 7; break;
case '8': b = ten * b + 8; break;
case '9': b = ten * b + 9; break;
default: MessageBox(NULL,"转换数字中有不明字符","错误",MB_ABORTRETRYIGNORE|MB_ICONHAND); abort();
break;
}
}
if(ch[0] == '-') return (b^0xffffffff) + 1;
return b;
}
TCHAR* CallocString(TCHAR a[],int n)
{
TCHAR *p = (TCHAR*) calloc(n+1,sizeof(TCHAR));
p[n] = 0x00;
while(n--)
{
p[n] = a[n];
}
return p;
}
void CheckStrings(TCHAR a[], int n) //检查错误函数
{
int flag = ZERO;
int count_num = 0;
int left = 0, right = 0;
TCHAR Buffer[50]; //字符缓冲区
for(int i = 0; i < n; i++)
{
switch(a[i])
{
case '+':
case '-':
case '*':
case '/':
switch(flag)
{
case ADD:
case SUM:
if(a[i] == '+') warn[count_warn++] = CallocString(Buffer,sprintf(Buffer,"注意: 位置%d的%c符号可以省略",i,a[i]));
if(!IsNumber(a[i+1])) error[count_error++] = CallocString(Buffer,sprintf(Buffer,"错误: 位置%d双符号后面必须是数字才能区别正负",i));
case CMP:
case DIV:
if(a[i] == '*' || a[i] == '/') error[count_error++] = CallocString(Buffer,sprintf(Buffer,"错误: 位置%d语法错误",i));
if( !IsNumber(a[i+1]))
{
if(a[i+1] != '(') error[count_error++] = CallocString(Buffer,sprintf(Buffer,"错误: 位置%d语法错误%c",i,a[i]));
}
break;
case NUM:
break;
case LEFT:
if(a[i] == '*' || a[i] == '/') error[count_error++] = CallocString(Buffer,sprintf(Buffer,"错误: 位置%d左括号不能出现运算符",i));
break;
case RIGHT:
break;
case ERRORS:
error[count_error++] = CallocString(Buffer,sprintf(Buffer,"错误: 位置%d前面出现不明字符",i));
break;
case VIOD:
break;
case ZERO:
if(a[i] == '*' || a[i] == '/') error[count_error++] = CallocString(Buffer,sprintf(Buffer,"错误: 位置%d不能以%c开头",i,a[i]));
break;
}
switch(a[i])
{
case '+': flag = ADD; break;
case '-': flag = SUM; break;
case '*': flag = CMP; break;
case '/': flag = DIV; break;
}
count_num = 0;
break;
case '0':
if(!flag&&a[i+1] != '.') warn[count_warn++] = CallocString(Buffer,sprintf(Buffer,"注意: 注意0开头的数字无意义"));
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
if(count_num >= 10){ error[count_error++] = CallocString(Buffer,sprintf(Buffer,"错误: 位置%d数字过长",i)); count_num = 0; }
switch(flag)
{
case NUM:
break;
case LEFT:
break;
case RIGHT:
error[count_error++] = CallocString(Buffer,sprintf(Buffer,"错误: 位置%d右括号后必须有运算符",i));
break;
case ERRORS:
error[count_error++] = CallocString(Buffer,sprintf(Buffer,"错误: 位置%d前面出现不明字符",i));
break;
case VIOD:
break;
case ZERO:
break;
}
count_num++;
flag = NUM;
break;
case '(':
switch(flag)
{
//case ADD:
//case SUM:
//if(a[i] == '+') warn[count_warn++] = CallocString(Buffer,sprintf(Buffer,"错误: 位置%d注意正负号符可以省略",i));
// break;
//case CMP:
//case DIV:
//error[count_error++] = CallocString(Buffer,sprintf(Buffer,"错误: 位置%d运算符摆放错误",i));
// break;
case NUM:
error[count_error++] = CallocString(Buffer,sprintf(Buffer,"错误: 位置%d左括号前要有运算符",i));
break;
case LEFT:
break;
case RIGHT:
error[count_error++] = CallocString(Buffer,sprintf(Buffer,"错误: 位置%d左括号前要有运算符",i));
break;
case ERRORS:
error[count_error++] = CallocString(Buffer,sprintf(Buffer,"错误: 位置%d前面出现不明字符",i));
break;
case VIOD:
break;
case ZERO:
break;
}
left++;
count_num = 0;
flag = LEFT;
break;
case ')':
switch(flag)
{
case ADD:
case SUM:
case CMP:
case DIV:
error[count_error++] = CallocString(Buffer,sprintf(Buffer,"错误: 位置%d右括号前多了一个运算符 %c",i,a[i]));
break;
case NUM:
break;
case LEFT:
error[count_error++] = CallocString(Buffer,sprintf(Buffer,"错误: 位置%d括号内无参数",i));
break;
case RIGHT:
break;
case ERRORS:
error[count_error++] = CallocString(Buffer,sprintf(Buffer,"错误: 位置%d右括号前面出现不明字符",i));
break;
case VIOD:
break;
case ZERO:
error[count_error++] = CallocString(Buffer,sprintf(Buffer,"错误: 位置%d右括号位置错误",i));
break;
}
right++;
count_num = 0;
flag = RIGHT;
break;
case ' ':
count_num = 0;
break;
default: error[count_error++] = CallocString(Buffer,sprintf(Buffer,"错误: 位置%d不明字符出现",i)); flag = ERROR; count_num = 0;
break;
}
}
if((left - right) > 0) error[count_error++] = CallocString(Buffer,sprintf(Buffer,"错误: 缺少%d个右括号",left-right));
else if(left - right < 0) error[count_error++] = CallocString(Buffer,sprintf(Buffer,"错误: 缺少%d个左括号",right-left));
warn[count_warn++] = CallocString(Buffer,sprintf(Buffer,"共有%d条错误 %d条警告",count_error,count_warn));
}
#endif
////////////////////////////////////////////////////////////////头文件
#ifndef TREE_H
#define TREE_H
#include "str.h"
typedef struct inBinaryTree *pBinaryTree;
typedef struct inBinaryTree //二叉树的数据
{
char *ch;
struct inBinaryTree *L,*R;
}BinaryTree;
pBinaryTree MakeTree(char *a,pBinaryTree L = NULL, pBinaryTree R = NULL) //建一棵树
{
pBinaryTree p = (struct inBinaryTree*)malloc(sizeof(inBinaryTree));
p->ch = a;
p->L = L;
p->R = R;
return p;
}
pBinaryTree MakeTree(char *a, int n) //建一棵树
{
pBinaryTree p = (struct inBinaryTree*)malloc(sizeof(inBinaryTree));
p->ch = (char*) calloc(n+1,sizeof(char));
for(int i = 0; i < n; i++) p->ch[i] = a[i];
p->L = p->R = NULL;
return p;
}
typedef struct inStackNode //堆数据区
{
pBinaryTree root; //二叉树指针
struct inStackNode *link;
}StackNode,*pStackNode;
typedef struct inStack //堆栈
{
pStackNode top;
}Stack,*pStack;
void Push(pStack stack, pBinaryTree a) //进栈函数
{ //pBinaryTree a为二叉树指针
pStackNode p = (struct inStackNode*)malloc(sizeof(inStackNode));
p->root = a;
if(stack->top)
{
p->link = stack->top;
stack->top = p;
}
else
{
p->link = NULL;
stack->top = p;
}
}
pBinaryTree Pop(pStack stack) //出栈
{
pBinaryTree p = NULL;
if(stack->top)
{
p = stack->top->root;
pStackNode next = stack->top->link;
free(stack->top);
stack->top = next;
}
return p;
}
pBinaryTree Top(pStack stack) //栈的顶部
{
if(stack->top) return stack->top->root;
return NULL;
}
void Free(pBinaryTree p) //释放二叉树
{
//MessageBox(NULL,p->ch,"ss",MB_OK);
free(p->ch);
free(p);
}
void PostOrder(void (*Visit) (pBinaryTree p),pBinaryTree root) //后序遍历
{
if(root)
{
if(root->L) PostOrder(Visit,root->L);
if(root->R) PostOrder(Visit,root->R);
Visit(root);
}
}
void Delete(pBinaryTree p) //释放全部二叉树
{
if(p) PostOrder(Free,p);
p = NULL;
}
//pBinaryTree CreateTree(char a[],int n) //建立二叉树 成功
//{
// if(!n) return NULL;
// pBinaryTree l,r; //二叉树指针
// Stack nu;
// int i = 0;
// nu.top = NULL;
// char *ch = (char*)calloc(n,sizeof(char)); //字符栈
// int top = n-1;
// while(i < n)
// {
// if(IsNumber(a[i])) //是操作数
// {
// int j = i;
// while(++i < n && IsNumber(a[i]));
// Push(&nu,MakeTree(ToNumber(&a[j],i-j)));
// }
// else if(IsChar(a[i])) //运算符
// {
// if(top < n-1 && ch[top] != '(') //不为空
// {
// if(ch[top] == '*' || ch[top] == '/')
// {
// r = Pop(&nu); l = Pop(&nu);
// Push(&nu,MakeTree(ToNumber(&ch[top]),l,r));
// ch[top] = a[i++];
// }
// else
// {
// if(a[i] == '*' || a[i] == '/') ch[--top] = a[i++];
// else
// {
// r = Pop(&nu); l = Pop(&nu);
// Push(&nu,MakeTree(ToNumber(&ch[top]),l,r));
// ch[top] = a[i++]; //入栈
// }
// }
// }
// else ch[--top] = a[i++];
// }
// else if(a[i] == ')')
// {
// while(ch[top] != '('&&top<n-1)
// {
// r = Pop(&nu); l = Pop(&nu);
// Push(&nu,MakeTree(ToNumber(&ch[top++]),l,r)); //建立分枝
// }
// top++;
// i++;
//}
//else if(a[i] == '(') ch[--top] = a[i++];
//}
//while(top < n-1)
//{
// r = Pop(&nu); l = Pop(&nu);
//Push(&nu,MakeTree(ToNumber(&ch[top++]),l,r));
//}
//free(ch);
//return Pop(&nu);
//}
pBinaryTree CreateTree(char a[],int n) //建立二叉树 成功
{
if(!n) return NULL;
pBinaryTree l,r; //二叉树指针
Stack nu;
int i = 0,number = 1;
nu.top = NULL;
char *ch = (char*)calloc(n,sizeof(char)); //字符栈
int top = n-1;
while(i < n)
{
if(a[i] == ' '&& i++) continue;
if(a[i] == ')')
{
while(ch[top] != '('&&top<n-1)
{
r = Pop(&nu); l = Pop(&nu);
Push(&nu,MakeTree(ToNumber(&ch[top++]),l,r)); //建立分枝
}
top++;
}
else if(a[i] == '(') ch[--top] = a[i];
else if(number) //是操作数
{
int j = i;
while(++i < n && IsNumber(a[i]));
Push(&nu,MakeTree(ToNumber(&a[j],i-j)));
i--;
number = 0; //指定下一个是运算符
}
else //运算符
{
if(top < n-1 && ch[top] != '(') //不为空
{
if(ch[top] == '*' || ch[top] == '/')
{
r = Pop(&nu); l = Pop(&nu);
Push(&nu,MakeTree(ToNumber(&ch[top]),l,r));
ch[top] = a[i];
}
else
{
if(a[i] == '*' || a[i] == '/') ch[--top] = a[i];
else
{
r = Pop(&nu); l = Pop(&nu);
Push(&nu,MakeTree(ToNumber(&ch[top]),l,r));
ch[top] = a[i]; //入栈
}
}
}
else ch[--top] = a[i];
number = 1; //指定下一个是数字
}
i++;
}
while(top < n-1)
{
r = Pop(&nu); l = Pop(&nu);
Push(&nu,MakeTree(ToNumber(&ch[top++]),l,r));
}
free(ch);
return Pop(&nu);
}
int Number(pBinaryTree root) //运算函数
{
if(IsChar(*root->ch)&&root->L&&root->R)
{
switch(*root->ch)
{
case '+': return (Number(root->L)) + (Number(root->R));
case '-': return (Number(root->L)) - (Number(root->R));
case '*': return (Number(root->L)) * (Number(root->R));
case '/': return (Number(root->L)) / (Number(root->R));
}
}
else{ int i = Numbers(root->ch,strlen(root->ch)); printf("%d ",i); return i;}
}
#endif