BASIC C - czy język C może być prosty jak Basic ? Wykorzystanie makr preprocesora.

 Stworzyłem "bibliotekę", dzięki której można programować w C stosując komendy zbliżone do języka Basic, zazwyczaj nie trzeba też używać klamr i średników. Po drobnych modyfikacjach można jej też używać  w C++. Dzięki temu programowanie jest łatwiejsze, a program bardziej czytelny. Ulepszyłem tez obsługę napisów (łańcuchów znaków), planuję dodanie obsługi biblioteki graficznej SDL. Przykładowy program w BASIC C:

#include "BASIC.h"
double a, b, c, f, tim, Timer=0;
FUNCTION (fibo,double n)
  IF (n == 1 OR n==0)
    RETURN (n)
  ENDIF
  LET(a, 1)
  LET (b ,1)
  FOR (i,2,n)
    LET (c ,a)
    LET (a ,b)
    LET (b ,c)
    LET (b ,b+a)
  NEXT
  RETURN (b)
ENDFUNC
MAIN
LET (tim  ,Timer)
FOR(t,1,1)
  FOR (i,0,45)
    LET (f ,fibo(i))
  NEXT
NEXT
LET (tim, Timer - tim)
PR$ ("czas: ") PR(tim) PR$(" fibo(5)=") PRINT(fibo(5))
ENDMAIN

Aby korzystać z tych możliwości wystarczy dołączyć do programu w C plik nagłówkowy BASIC.h (dodać w kodzie np. <#include "BASIC.h">). W pliku tym są zawarte dyrektywy preprocesora C zawierające definicje komend BASIC, w postaci tzw. makr i stałych, przy użyciu komendy #define. Zawiera również komendy #include załączające wymagane biblioteki standardowe, więc nie trzeba ich ponownie zamieszczać w programie głównym.

Ogólnie za komendą #define podajemy "wyraz" i po spacji ciąg znaków, który jest wstawiany zamiast tego wyrazu w programie. Wyraz nie może zawierać spacji.

Poniżej zawartość pliku BASIC.h wraz z opisem. Komendy są pogrupowane wg bibliotek, których wymagają, począwszy od nie wymagających żadnych bibliotek.


#ifndef BASIC    // definiowanie następuje jeśli stała BASIC nie jest jeszcze zdefiniowana

#define BASIC

//  Operatory:

#define AND &&

#define MOD %

#define NOT !

#define OR ||

#define XOR ^

// Proste funkcje

#define ABS(x) (((x)<0) ? -(x):(x))    // Wartość bezwzględna

#define MAX(X,Y) (((X)>(Y)) ? (X):(Y))    // Wybiera większą z 2 liczb

#define MIN(X,Y) (((X)<(Y)) ? (X):(Y))

#define SQR(x) ((x)*(x))    // Kwadrat

// Pętla nieskończona DO..LOOP

#define DO do{

#define LOOP }while(1);


#define FUNCTION(NAME,...) double NAME(__VA_ARGS__){ /* For marking a function returning a double */

#define FUNC(NAME,...) NAME(__VA_ARGS__){ /* For other types, we put before the name, e.g. (int NAME,...) */ 

#define ENDFUNC }

#define RETURN(X) return X;

// Jak widać - ENDFUNC wpisujemy na końcu funkcji zamiast klamry zamykającej

#define FOR(I,P,K) for(int I=P;I<=K;++I){

#define NEXT }

// Bez-klamrowe IF..ELSE..ELSEIF..ENDIF:

#define IF(X) if(X){

#define ELSE }else{

#define ELSEIF(X) }else if(X){

#define ENDIF }

// Komenda podstawienia do zmiennej X wartości Y konwertowanej do (double) - l. rzeczywistej

#define LET(X,Y) X=(double)(Y);

// MAIN..ENDMAIN - główna funkcja/procedura programu

#define MAIN int main(int argc, char *argv[]){

#define ENDMAIN }

// pętla REPEAT..UNTIL - wyjście następuje gdy warunek X będzie prawdziwy (true)

#define REPEAT do{

#define UNTIL(X) }while(!X);

// SELECT..ENDSELECT zamiast switch{..}

#define SELECT(X) switch(X){

#define ENDSELECT }

// procedura SUB - przy wywołaniu używamy średnika, jeśli wymagany

#define SUB(NAME,...) void NAME(__VA_ARGS__) { /* Subroutine, Calling: NAME(); */

#define ENDSUB }

// pętla WHILE..WEND - działa, gdy X jest prawdą (>0)

#define WHILE(X) while(X){

#define WEND }

// definicja typu łańcuch znaków STRING o maks. długości STRLEN=256 -1 (miejsce na końcowy znak \0)

#define STRLEN 256 /* Maximum number of characters in a strings +1 */

typedef char STRING[STRLEN];

// Deklaracja zmiennej pomocniczej STRING$ typu STRING

STRING STRING$;

// zmienna ta jest używana przez niektóre komendy i może być używana przez programistę

// Zalecam stosowanie typu STRING dla łańcuchów i komend tutaj zdefiniowanych, co zmniejsza ryzyko błędów w programie. Długość maksymalną łańcuchów - STRLEN - ustawiamy indywidualnie.

// Często spotykanym błędem jest stosowanie łańcuchów typu *char bez zarezerwowania pamięci

#include <string.h>    // dołączenie biblioteki string.h


#define ADD$(A,B) strncat(A,B,STRLEN-strlen(A));    // dodanie łańcucha B do łańcucha A

#define LEN(A) strlen(A)    // długość łańcucha A

#define LET$(A,B) strncpy(A,B,STRLEN);    // kopiowanie zawartości łańcucha B do A


#include <stdlib.h>


#define VAL(S) atof(S)    // konwertuje zawartość łańcucha na liczbę rzeczywistą

#define RND ((float)rand()/RAND_MAX)    // RND=losowa liczba z przedziału <0..1)

//#define RANDOM(X) ((int)(RND*(X)))    // RANDOM(X)=losowa liczba całkowita <0..X-1)

#define RANDOM(X) (rand()/(RAND_MAX/(X)))    // to samo inaczej


#include <stdio.h>


#define INPUT(S,I) do{printf(S);scanf("%f",&I);}while(0);    // wczytuje liczbę z klawiatury i wstawia do zmiennej podanej jako drugi argument (I), zmienną wpisujemy normalnie, nie jako wskaźnik

// Pierwszy argument to łańcuch - komunikat. Można go pominąć, wtedy zapisujemy INPUT(,I)

#define INPUT$(S,I) {printf(S);fgets(I,STRLEN,stdin);};    // to samo dla łańcucha znaków


#define PRINT$(S) printf("%s\n",S);    // wyświetla napis S i przechodzi do nowej linii

#define PR$(S) printf("%s ",S);    // wyswietla napis S i spacje na końcu

#define PRINT(G) printf("%G\n",(double)G);    // to samo dla liczby

#define PR(G) printf("%G ",(double)G);

// STR$(D) konwertuje liczbę D na łańcuch i zapisuje do zmiennej pomocniczej STRING$

#define STR$(D) snprintf(STRING$, STRLEN, "%G", (double)D);


#endif


Proszę o wszelkie uwagi dotyczące działania tych funkcji oraz wsparcie, najlepiej finansowe ;).

Komentarze

Popularne posty z tego bloga

ODERWANIE KSIĘŻYCA C.D. - teoria względności Einsteina

Kurs programowania gier w RC Basic.

ODERWANIE KSIĘŻYCA