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:
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
Komentarze
Prześlij komentarz