/*
**-------------------------------------------------------------------
**
** A Mini Language:
** C-like/Script type, compiled ( x86 ) 32 bits.
**
** FILE:
** mini.c
**
** MAIN FUNCTION:
** int Parse (ASM *a, char *text);
**
** RESERVED WORDS:
** int, char *, struct *,
** if, for, break.
**
** COMPILE:
** gcc mini.c -o mini -Wall
**
** BUILD/VERSION:
** 0001 - 22/08/2015 - 18:50
**
** BY: Francisco G. A. - "gokernel" ( gokernel@hotmail.com )
**
**-------------------------------------------------------------------
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#ifdef _WIN32
#include <windows.h>
#endif
#ifdef __linux__
#include <unistd.h>
#include <sys/mman.h> // to: mprotect()
#endif
//-------------------------------------------------------------------
//######################## DEFINE/ENUM ############################
//-------------------------------------------------------------------
//
#define ASM_DEFAULT_SIZE 50000
#define PROG_SIZE 50000
#define UCHAR unsigned char
enum {
TOK_INT = 255, TOK_CHAR, TOK_STRUCT, TOK_IF, TOK_FOR, TOK_BREAK,
//----------------------------
TOK_ID, // identifier
TOK_NUMBER,
TOK_STRING,
TOK_PLUS_PLUS, // ++
TOK_MINUS_MINUS // --
};
//-------------------------------------------------------------------
//########################### STRUCT ##############################
//-------------------------------------------------------------------
//
typedef struct ASM ASM;
typedef struct ASM_label ASM_label;
typedef struct ASM_jump ASM_jump;
struct ASM {
UCHAR *p; // to increment ...
UCHAR *code; // code_len=: p - code
ASM_label *label;
ASM_jump *jump;
int label_len; // len of ( label ) array to realloc
int jump_len; // len of ( jump ) array to realloc
};
struct ASM_label {
char *text;
int pos;
};
struct ASM_jump {
char *text;
int pos;
int type;
};
//-------------------------------------------------------------------
//########################### PROTOTYPE ###########################
//-------------------------------------------------------------------
//
void expression (ASM *a);
//-------------------------------------------------------------------
//########################### VARIABLE ############################
//-------------------------------------------------------------------
//
static char
*str,
prog[PROG_SIZE], token[1024]
;
static int
tok, erro, line
;
static int lex (void)
{
switch (*str) {
case 0: return 0;
default:
return *str++;
}
return 0;
}
static int stmt (ASM *a)
{
tok = lex();
switch (tok) {
case TOK_INT: break;
default:
expression(a);
}
return tok;
}
void expression (ASM *a)
{
// ...
}
//-------------------------------------------------------------------
//########################### ASM API #############################
//-------------------------------------------------------------------
//
ASM *asm_new (unsigned int size)
{
ASM *a = (ASM*)malloc(sizeof(ASM));
if (a && (a->code=(UCHAR*)malloc(size)) != NULL) {
a->p = a->code;
a->label = NULL; // this use realloc
a->jump = NULL; // this use realloc
a->label_len = 0;
a->jump_len = 0;
return a;
}
return NULL;
}
//-------------------------------------------------------------------
// This function use the code of Fabrice Bellard:
//
// LIB: tcc-0.9.25
// FILE: libtcc.c
// FUNC: void set_pages_executable (void *ptr, unsigned long length);
// LINE: 400
//
// Set executable: a->code
//
//-------------------------------------------------------------------
void asm_set_executable (void *ptr, unsigned long len)
{
#ifdef _WIN32
unsigned long old_protect;
if (!VirtualProtect(ptr, len, PAGE_EXECUTE_READWRITE, &old_protect))
{
printf ("ERROR: asm_set_executable() ... NOT FOUND - VirtualProtect()\n");
exit (-1);
}
#endif
#ifdef __linux__
unsigned long start, end, PageSize;
PageSize = sysconf (_SC_PAGESIZE);
start = (unsigned long)ptr & ~(PageSize - 1);
end = (unsigned long)ptr + len;
end = (end + PageSize - 1) & ~(PageSize - 1);
if (mprotect((void *)start, end - start, PROT_READ | PROT_WRITE | PROT_EXEC) == -1)
{
printf ("ERROR: asm_set_executable() ... NOT FOUND - mprotec()\n");
exit (-1);
}
#endif
}
void asm_begin (ASM *a) {
a->p[0] = 0x55; //: 55 push %ebp
a->p[1] = 0x89; a->p[2] = 0xe5; //: 89 e5 mov %esp,%ebp
a->p += 3;
}
void asm_end (ASM *a) {
a->p[0] = 0xc9; // leave
a->p[1] = 0xc3; // ret
a->p += 2;
// if (a->jump_len)
// asm_change_label (a);
}
int Parse (ASM *a, char *text)
{
str = text;
line = 1;
erro = 0;
asm_begin(a);
while (!erro && stmt(a)) { }
asm_end(a);
if (erro) printf("<<<<<<< ERRO >>>>>>>\n");
return erro;
}
int main (int argc, char *argv[])
{
ASM *a;
FILE *fp;
if (argc >= 2 && (a=asm_new(ASM_DEFAULT_SIZE))!=NULL && (fp=fopen(argv[1], "rb"))!=NULL) {
int c, i = 0;
while ((c=getc(fp))!=EOF) prog[i++] = c; // store prog[];
prog[i] = 0;
fclose(fp);
if ( !Parse(a,prog) ) {
asm_set_executable (a->code, (int)(a->p - a->code)+5);
( (void(*)()) a->code ) (); // <<<<<<< execute here >>>>>>>
}
//--------------------------------
//########## Free ASM ##########
//--------------------------------
if (a->label) {
for(i=0;i<a->label_len;i++)
if (a->label[i].text) free(a->label[i].text);
free (a->label);
}
if (a->jump) {
for(i=0;i<a->jump_len;i++)
if (a->jump[i].text) free(a->jump[i].text);
free(a->jump);
}
free(a->code);
free(a);
printf ("\nExiting With Sucess !!!\n");
}
else printf ("USAGE: mini <file.cs>\n");
return 0;
}