flat assembler
Message board for the users of flat assembler.

Index > Projects and Ideas > Universal Fasm

Author
Thread Post new topic Reply to topic
emil



Joined: 16 Dec 2003
Posts: 76
Location: egypt
emil 21 Feb 2015, 19:27
hi all ,

my main goal is to make a compiler that will understand small basic of many programming languages syntax, such as C,pascal,basic,powerbasic, sphinx c--,asm,Amiga BlitzBasic2 , Oxygen basic ,and so on. ofcourse that will mix with Fasm as a backend.

at the same time i want it to be simple and easy , so that i have picked up the small C and tried to extend it.

i have made some progress in that , if any one interested and want to contribute me , i will go ahead and post the project here .

Notewell , it is a beta stage , so may has a bugs

here is a small Example
Code:

//
//  test program
//

 format PE GUI  //this is inline asm 

 entry main    // start point is main c function

        
 include 'MACRO/PROC32.inc' ; tell fasm to include PORC32.inc header file
 
// declare a function that called from c code later
extern  stdcall MessageBoxA();
 $ nop    // empty section gives error 

// declare a global c variable
int val = 100;


/*  Fasm Proc syntax , found in fasm forum */
proc itoa  value,buf,base 

  local table db '0123456789ABCDEF' ;Table used in conversion 

  cmp  [base],16      ;Nothing over base 16(Hex) is supported. You could add support for them by just modifying this line and the table above
  ja   .base_error 
  cmp  [base],2       ;Nothing below base 2 is supported 
  jb   .base_error 

  pushad              ;Save the registers. No one likes a procedure that thrashes everything

  mov  eax,[value]    ;Load up the registers 
  mov  ebx,[base] 
  mov  edi,[buf] 
  mov  edx,0          ;Important note if you didn't know this, division by a dword is a 64-bit divide, edx will interfere if it's not cleared 
                      ;Division by a dword does edx:eax div r/m32      where edx:eax is treated as one 64-bit number 

  push 0xFFFF         ;This push is used later in the reversing part, it tells it that it's done.

  @@: 
    or   eax,eax      ;Is the value to convert zero? 
    jz   .reverse     ;If so, we're done here, lets reverse it. 
    div  ebx          ;Else, divide it by the base.  Result stored in eax, remainder in edx
    lea  edx,[edx+table] ;Point edx to the byte in the table holding the value we need 
    movzx edx,byte[edx]  ;Put that byte in edx 
    push edx             ;Push it 
    mov  edx,0           ;and as I explained earlier, edx MUST be zero before the next divide, or it will interfere with the divide
    jmp @b               ;Lather, rinse, and repeat 



;The routine above gets the numbers backwards, so we must reverse them. 
  .reverse: 
    pop  eax          ;Pop a converted value off the stack 
    cmp  eax,0xFFFF   ;Are we done reversing(was the popped value the 0xFFFF we pushed before we started)?
    je   @f 
    stosb             ;If not, store the byte in the buffer 
    jmp  .reverse 

  @@: 
    mov  eax,0        ;The string needs to be zero terminated, so this just places a 0x0 at the end
    stosb 

  popad 
  mov  eax,0          ;Out: eax = 0, everything went fine 
  ret 

  .base_error: 
    mov  eax,-1       ;Out: eax = -1, Bad base 
    ret 
endp 

/*   c function Sytax */
print(x)
 int x;
{
    char buf[255];
    itoa(x,buf,10);
    MessageBoxA(0,buf,"the Value Is",0);
} 



main()
{
    
   int k,m,c; 
  
   k = 10;
   m = 20;
   c = m + k + val;
   
   print(c);
}


#asm

section '.idata' import data readable writeable

  dd 0,0,0,RVA kernel_name,RVA kernel_table
  dd 0,0,0,RVA user_name,RVA user_table
  dd 0,0,0,0,0

  kernel_table:
    ExitProcess dd RVA _ExitProcess
    dd 0
  user_table:
    MessageBoxA dd RVA _MessageBoxA
    dd 0

  kernel_name db 'KERNEL32.DLL',0
  user_name db 'USER32.DLL',0

  _ExitProcess dw 0
    db 'ExitProcess',0
  _MessageBoxA dw 0
    db 'MessageBoxA',0

section '.reloc' fixups data readable discardable       ; needed for Win32s
            
#endasm            
    


i will post more examples , and post the source code fro contributing.

waiting for your opinion.
Post 21 Feb 2015, 19:27
View user's profile Send private message Reply with quote
HaHaAnonymous



Joined: 02 Dec 2012
Posts: 1178
Location: Unknown
HaHaAnonymous 21 Feb 2015, 19:37
[ Post removed by author. ]


Last edited by HaHaAnonymous on 28 Feb 2015, 17:54; edited 1 time in total
Post 21 Feb 2015, 19:37
View user's profile Send private message Reply with quote
emil



Joined: 16 Dec 2003
Posts: 76
Location: egypt
emil 21 Feb 2015, 20:08
HaHaAnonymous wrote:

If that will be achieved without inserting compiler directives (e.g.: c_code_start, c_code_end and bla bla bla) then that will be amazing! Very Happy


ofcourse my goal is without any directive , i made some progress , but still there are long work have to be done.

you can see from previous Example that Proc is a directive that accepts asm syntax untill endp directive found so here is the main Pares function

Code:


void parse()
{
  while (eof == 0) {
    if     (amatch("extern", 6)) { if(match("WINAPI")) doextern();  else if(match("stdcall")) dodeclare(EXTERNAL);  else {match("cdecl"); dodeclare(EXTERNAL_C);}}
    else if(dodeclare(STATIC));
    else if( match("#asm"))      doasm();
    else if( match("#include"))  doinclude();
    else if( match("#incpath"))  doincludepath();
    else if( match("#define"))   dodefine();
    else if( match("$"))         doinlineasm();
    else if( match("procedure")) {Pasfunc = -1; doprocedure();}
    else if( match("function"))  {Pasfunc = 0; doprocedure();}
    else if( match("sub"))       dosub();
    else if( match("fastproc"))  dofastproc();
    else if( match("proc"))      doproc();
    else if( match("statement")) doBlitzStmt();
    else if( match("."))         doBltz2subrotin();
    else if( match("#"))         doBltzResidnt();
    else if(doglblabel()) ;
    else if( dofunction() == 0 ) { ccode = ASM_code; fputs(lptr, output); fputs("\15", output); Inline(); ccode = C_code;   }

    blanks();                 /* force eof if pending */
    }
  }
    


as you can see compiler will act , i hope that , in language block.

here is a big test Example
=====================
File test6.c
Code:
//
//  test program
//

 format  PE console   

 include 'win32ax.inc' 
 
 entry start

char tmp[255];
int cmnd;
dim as integer stdout;
dim dff.b,sdd.w,ase.l;
dim Adff.b[20],Asdd.w(5),Aase.l[2*2];
int ary2[10][4]={1,0,8,7};
short sWord;

CurTime: dd 0
totTime: db 2
shrTime: dw 1 

extern stdcall MessageBoxA();
extern stdcall GetCommandLine();
extern stdcall GlobalAlloc();
extern stdcall GlobalFree();

extern WINAPI "msvcrt.dll"
{
   printf();
  cdecl system();
   exit();
}

#WINDOWS_7 = 3 
//#define WINDOWS_7  3


mydata:
  Dc.w 10,15,13;


#include "test6_1.c"

#include "test6_3.c"

#include "test6_4.c"

#include "test6_5.c"

#include "test6_6.c"

#asm 

.data

  _caption db 'Win32 assembly program',0
  _message db 'Hello World!',0
  
  display_handle dd 0
    
.code

  start:
        mov     [display_handle],STD_OUTPUT_HANDLE
        invoke  GetStdHandle,[display_handle]
        mov     [stdout],eax     
        GetCommandLine ();         // using high level function call
        mov     [cmnd],eax
            
        call    main
        
        printf("\n\nbay ....");
        system("pause>NULL");
               
        push    0
        call    [ExitProcess] 
        
;==========[ Import Sec ]=======

  section '.idata' import data readable writeable 
     library msvcrt, 'msvcrt.dll', kernel32, 'kernel32.dll', user32, 'user32.dll', advapi32, 'advapi32.dll', shell32, 'shell32.dll'
  
     import_kernel32
     import_user32
     import_gdi32
     import_advapi32
     import_comctl32
     import_comdlg32
     import_shell32
     import_wsock32

     import msvcrt,   printf, 'printf',  system, 'system' 
     
     all_api                             
                
                         
#endasm  
    


file test6_1.c
==========
Code:



#include "test6_2.c"

procedure MsgBox;
begin
    MessageBoxA(0,"i am pascal","",0);
    $ invoke  MessageBoxA,HWND_DESKTOP,"Hi! I'm the example program!",invoke GetCommandLine,MB_OK
end; 

procedure MyAdd(x,y)int x,y;
begin
    return x+y;
end; 

procedure MyAdd2(x,y)int x,y;
var  int k,p;
begin
    k = 10;
    p := 20;
    return x+y+k;
end; 

procedure findMin(x,y,z,m)int x,y,z;int* m;    /* (x, y, z: integer; var m: integer); */ 
/* Finds the minimum of the 3 values */
begin
   if x < y  then 
      m := x;
   else
      m := y;
   if z <m then m := z;
end; /*{ end of procedure findMin }*/


/* function returning the max between two numbers */
function max(num1,num2) int num1,num2;                      /*(num1, num2: integer): integer;*/
var
   /* local variable declaration */
  /* result: integer; */
   int result; 
begin
   if (num1 > num2) then
      result := num1;
   else
      result := num2;
   max := result;
end;
    


file test6_2.c
==========
Code:


print(x)int x;
{
   int p;
   if(x) p=10;
   $    push    0
   $    push    _caption
   $    push    _message
   $    push    0
   $    call    [MessageBoxA]
        
}


print2(char x,int y)
{
   int p;
   if(x) p=10;
   $    push    0
   $    push    _caption
   $    push    _message
   $    push    0
   $    call    [MessageBoxA]
   tmp[0] = 0;      
}


strlen(char *s)
{
   char *ptr;
   ptr=s;
   while(*ptr)
   {
      ++ptr;
   }
   return (ptr-s);
}
    


file test6_3.c
==========
Code:


#asm
.data
  bytes_count dd 0
.code
display_string:
        mov     edi,esi
        or      ecx,-1
        xor     al,al
        repne   scasb
        neg     ecx
        sub     ecx,2
        invoke  WriteFile,dword[stdout],esi,ecx,bytes_count,0
        retn                                                  
#endasm


.bltzRotn

   Adff[2] = Adff[1] + 2;  
   
  return

.SubRotn:

   Adff[1] = 5*30+1; 
   
   gosub bltzRotn;
   
  return
        
main()
{
   local pp; 
      
   int k,m,c;
   int* ptr;
   
      
   DEFTYPE.w lm,ld
   
   dim cc.b,bb.l,kk.w
     
   cc = 'A';
   bb = -10;
   kk = 0xFFFF;
     
   dff = cc;
   sdd = kk;
   ase = bb;
   
   Aase[2]= bb * 2;
     
   gosub  SubRotn;  
      
   mov EAX , WINDOWS_7;
     
   print(5);
  
   k = 10;
   m = k > 5 ? 30 : 60;
   
   ptr = &m;
   
  // lm = 100;
  // ld = 200; 
   
   MsgBox();
   
   MyAdd(20,40);
   
   MyAdd2(60,80);
   
   max(30,40);
   
   emit();
   
   empty();
   
   fast();
   
   fast2(c);
   
   #asm
      
      stdcall itoa,4660,tmp,10 
      invoke  MessageBoxA,HWND_DESKTOP,tmp,"the number is",MB_OK
      
      mov ESI,[cmnd]
      call display_string
   #endasm
   
   push 6*m +20 , EDX + 5;
   pop  EDX , m;
   push EAX;
   $pop eax
   
   mov  EDX , 10*k+c;
   
   mov m , 10*k+ 4 : ECX , 10 :  ESI , strlen(tmp);
   
   EDX = 10 * max(200,300); 
   
   DX = 10 * max(200,300); 
   
   DL = 10 * max(10,30) + CH;
   
   lea EDX , [strlen]
   
   ECX=EDX(tmp); 
   
   sWord = 50;
   DX = sWord * 20;
    
   mov ESI,cmnd;
   display_string();
   
   EDX = GetCommandLine();
   MessageBoxA(HWND_DESKTOP,"Hi! I'm the example program!",EDX,MB_OK);
   
   MessageBoxA(HWND_DESKTOP,_message,_caption,MB_OK);
   
  // MessageBoxA(HWND_DESKTOP,"Hi! I'm the example program!",GetCommandLine(),MB_OK);
   
   itoa(0xffef,tmp,16); 
 
  // MessageBoxA(HWND_DESKTOP,tmp,cmnd,MB_OK);
  
   push MB_OK,cmnd,tmp,HWND_DESKTOP;
   call MessageBoxA
   
   ptr = sizeof  int;
    
   ptr = new int[100];
   
   delete ptr;
   
   MessageBoxA(HWND_DESKTOP,"...Good bay...","",MB_OK);
}

#asm
__NEW:
        push eax
        push GMEM_FIXED
        call [GlobalAlloc]
    ret

__DELETE:
        push eax
        call [GlobalFree]
    ret
#endasm    
    


file test6_4.c
==========
Code:

sub empty;
/*  */
   tmp[0] = 0; 
endsub

sub emit()

  int h;
  h = 500;
  $ invoke  MessageBoxA,HWND_DESKTOP,"I'm in subroutin","",MB_OK
  begin
    h = h + 1;
  end;
endsub


fastproc fast;
   $ mov eax,1
endfastproc


fastproc fast2(x) int x;
   $ mov eax,1
   $ add eax, [esp+4]            ;  eax = x + 1      
endfastproc


fastproc fast3(ECX,EDX)
   $ mov eax,edx
   EAX = ECX * 2 + EDX;
endfastproc
    


file test6_5.c
==========
Code:
/*  value,buf,base      ;Return will be in eax, 0:fine, -1:base too small/large */

proc itoa  value,buf,base 

  local table db '0123456789ABCDEF' ;Table used in conversion 

  cmp  [base],16      ;Nothing over base 16(Hex) is supported. You could add support for them by just modifying this line and the table above
  ja   .base_error 
  cmp  [base],2       ;Nothing below base 2 is supported 
  jb   .base_error 

  pushad              ;Save the registers. No one likes a procedure that thrashes everything

  mov  eax,[value]    ;Load up the registers 
  mov  ebx,[base] 
  mov  edi,[buf] 
  mov  edx,0          ;Important note if you didn't know this, division by a dword is a 64-bit divide, edx will interfere if it's not cleared 
                      ;Division by a dword does edx:eax div r/m32      where edx:eax is treated as one 64-bit number 

  push 0xFFFF         ;This push is used later in the reversing part, it tells it that it's done.

  @@: 
    or   eax,eax      ;Is the value to convert zero? 
    jz   .reverse     ;If so, we're done here, lets reverse it. 
    div  ebx          ;Else, divide it by the base.  Result stored in eax, remainder in edx
    lea  edx,[edx+table] ;Point edx to the byte in the table holding the value we need 
    movzx edx,byte[edx]  ;Put that byte in edx 
    push edx             ;Push it 
    mov  edx,0           ;and as I explained earlier, edx MUST be zero before the next divide, or it will interfere with the divide
    jmp @b               ;Lather, rinse, and repeat 



;The routine above gets the numbers backwards, so we must reverse them. 
  .reverse: 
    pop  eax          ;Pop a converted value off the stack 
    cmp  eax,0xFFFF   ;Are we done reversing(was the popped value the 0xFFFF we pushed before we started)?
    je   @f 
    stosb             ;If not, store the byte in the buffer 
    jmp  .reverse 

  @@: 
    mov  eax,0        ;The string needs to be zero terminated, so this just places a 0x0 at the end
    stosb 

  popad 
  mov  eax,0          ;Out: eax = 0, everything went fine 
  ret 

  .base_error: 
    mov  eax,-1       ;Out: eax = -1, Bad base 
    ret 
endp 
    


file test6_6.c
==========
Code:



statement bltzAdd{ kilo.l , metr.w , mch.b }

  int cc; 
  cc = 10;  
  tmp[cc+10] = 2;

  if ( cmnd == 0 ) cmnd = 0;
  
  ary2[6][2] = 5; 

endstatement
    
Post 21 Feb 2015, 20:08
View user's profile Send private message Reply with quote
baldr



Joined: 19 Mar 2008
Posts: 1651
baldr 22 Feb 2015, 09:53
emil,

Please, add Brainfuck to the list… Wink

Compiler using fasm as a back-end? That would be great.
Post 22 Feb 2015, 09:53
View user's profile Send private message Reply with quote
emil



Joined: 16 Dec 2003
Posts: 76
Location: egypt
emil 22 Feb 2015, 17:39
baldr;

hope you will like it , as i mintioned above , i have picked up Small C that found in fasm forum that was already uese Fasm as a backend.

i have only extend it , it is not optimized yet , in this stage focus in muliti language compatibility.

ok here is another Example , showing you how to declare a global variable in
many language syntax then use them as usual variable.
Code:
//
//  Global Decleraion test program
//

 format  PE console   

 include 'win32ax.inc' 
 
 entry main

// c syntax decleration
char  chr;
int   cmnd;
short sWord;
unsigned len; 
char name[255];
char* Cptr;
int*  Aptr;
int  scrn[200][100];
// basic syntax
dim as integer stdout;
dim as char basic_char;
dim as word basic_word;
//Amiga BlitzBasic2 syntax
dim dff.b,sdd.w,ase.l;
dim Adff.b[20],Asdd.w(5),Aase.l[2*2];
DEFTYPE.w lm,ld;
// fasm syntax
CurTime: dd 0
totTime: db 2
shrTime: dw 1 
//Amiga Asm syntax
mydata:
  Dc.w 10,15,13;
// inline fasm syntax  
#asm 
.data
caption db 'AAAAAA',0
message db 'HHHHHH',0
disply  dd 0
#endasm

extern printf();
extern  exit();
extern  system();

init()
{
    int i,j;

    chr = 'A';
    cmnd = 100;
    sWord = 200;
    len   = 2000;
    for(i=0;i<254;i++) name[i]='A';  
    Cptr = &name[100];
    for(i=0;i<200;i++) 
      for(j=0;j<100;j++)
          scrn[i+j*200]=i+j;  
    Aptr = scrn;  
    stdout = 100;
    basic_char = name[50];
    basic_word = 0xFFEE;
    dff = 0xAA;
    sdd = 0xAABB;
    ase = 0xAABBCCDD;
    Adff[10] = 0x11;
    Asdd[2] = 0x1122;
    Aase[3] = 0x11223344;     
    lm = ld = Asdd[2];
    CurTime = 0xFFAAAAFF;   //amazing using it as usual variable
    totTime = 0x55;        //amazing using it as usual variable
    shrTime = 0x2288;    //amazing using it as usual variable
  //  mydata = 10;     // in todo list
    caption = 'C';     //amazing using it as usual variable  
    message = 'A';
    disply = 300;      //amazing using it as usual variable
    
}

main()
{
  init();
  printf( "Test program\n" );
  printf( "%d\n", disply );
  printf( "%c\n", message );
  printf( "%c\n", caption );
  printf( "%x\n", shrTime );  //did not work correctly ,i will see
  printf( "%x\n", totTime );
  printf( "%x\n", CurTime );
  system( "pause>NULL" );
  exit(0);
}

section 'idata' import data readable 
library msvcrt, 'msvcrt.dll' 
import msvcrt, system,'system',printf,'printf',exit,'exit'
    
    
Post 22 Feb 2015, 17:39
View user's profile Send private message Reply with quote
Display posts from previous:
Post new topic Reply to topic

Jump to:  


< Last Thread | Next Thread >
Forum Rules:
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Copyright © 1999-2025, Tomasz Grysztar. Also on GitHub, YouTube.

Website powered by rwasa.