Sunday, November 15, 2015

Day 4 A Forth interpreter in C, more math functions.


For today, we add most of the standard C math library functions to the basic four function calculator oriented interpreter.

#include 
#include 
#include 
#include 
#include 


/*
 day 1 - basic 
 day 2 - tokenizing.
 day 3 - basic function calculator.
 day 4 - more math functions. November 15, 2014.
*/

#define MAXBUFFSIZE 128
#define MAXFSTACKSIZE 32

double FSTACK[MAXFSTACKSIZE];
int    FP = 0;                // index to FSTACK;

char    BUFF[MAXBUFFSIZE];   // input string buffer.

char   delims[] = " \t\n";   // delimiters.
double fval     = 0.0;


enum  Dtypes{ERROR, FNUM, FADD,FSUB, FMUL, FDIV, FPRINT,
             FPI, FE, FABS,FNEG, FEXP, FLN, FLOG10, FSIN, FCOS, FTAN, FSINH, FCOSH, FTANH, 
             FDOWN, FUP,
             ECR,  QUIT};

int  lexer(char* tok)
{
    int  n = strlen(tok);
    char c = *tok;
    if (n == 1){
       if (c == '+') return FADD;
       if (c == '-') return FSUB;
       if (c == '*') return FMUL;
       if (c == '/') return FDIV;
       if (c == '.') return FPRINT;
    }
    // A simplistic individual brute force string comparisons 
    if (strcmp(tok, "pi")==0) return FPI; 
    if (strcmp(tok, "e")==0) return FE;
    if (strcmp(tok, "abs")==0) return FABS;
    if (strcmp(tok, "neg")==0) return FNEG;
    if (strcmp(tok, "exp")==0) return FEXP;
    if (strcmp(tok, "ln")==0)  return FLN;
    if (strcmp(tok, "log10")==0) return  FLOG10;
    if (strcmp(tok, "sin")==0) return FSIN;
    if (strcmp(tok, "cos")==0) return FCOS;
    if (strcmp(tok, "tan")==0) return FTAN;
    if (strcmp(tok, "sinh")==0) return FSINH;
    if (strcmp(tok, "cosh")==0) return FCOSH;
    if (strcmp(tok, "tanh")==0) return FTANH;

    if (strcmp(tok, "fdown")==0) return FDOWN;
    if (strcmp(tok, "fup")==0) return FUP;
    
    if (strcmp(tok, "quit")== 0) {
       return QUIT;
    };
    if (strcmp(tok, "ecr") == 0) {
       return ECR;
    }
    if (getnumber(tok) == 0) {
       return FNUM;
    };
    return ERROR;
}


int checknumber(char *s)
{
  /* Description
     Returns 0 if s is a double real number, otherwise nonzero value.
     It is assumed that leading and trailing white spaces are removed from s.
     1 illegal character after '.'
     2 illegal starting character.
     3 illegal character after 'e'
     4 expected a '\0'
     5 empty string.
   */
  char* t = s;
  /* empty string */
  if (*t == '\0') return 5; 
  /* starts with an optional sign? */
  if ((*t == '-') || (*t == '+'))t++;
  // block of digits starting with a digit 
  if (isdigit(*t)) { /* starts with a digit? */
  while (isdigit(*t)) t++;
  if (*t == '.'){ /* a block starting with a .? */
    t++;
    if (*t == '\0') return 0;  // a number ending with a '.'
    while (isdigit(*t)) t++;
  }
  }else if (*t == '.'){ /* a number starting with a .? */
 t++;
 if (! isdigit(*t)) return 1;
 while (isdigit(*t)) t++;
  } else return 2;  /* illegal starting value! */
    
  /* optional exponent */
  if (tolower(*t) == 'e') {
 t++;
 if ((*t == '-') || (*t == '+')) {
    t++;
 }
 if (!isdigit(*t))return 3;
 while isdigit(*t) t++;
  }
  /* illegal character */
  if (*t != '\0') return 4;
  return 0;
};


int getnumber(char *s){
   int i = checknumber(s);
   if (i==0) {
      fval = atof(s);
   }
   return i;
};

int main() {
  int i =0;
  int exitnow = 0;
  while (1) {
    fputs(">>", stdout);
    fgets(BUFF, MAXBUFFSIZE-1, stdin);
    char *tok = strtok(BUFF, delims);
    while (tok)  {
      // printf("%d %s", ++i, tok);
      if (tok == NULL) break;
     
      // process token.
      int dtype = lexer(tok);
      switch(dtype) {
      // basic floating point operations.
      case  FNUM:
            FSTACK[++FP]= fval; break;
      case  FADD:
            FP--; FSTACK[FP]+= FSTACK[FP+1]; break;  
      case  FSUB:
            FP--; FSTACK[FP]-= FSTACK[FP+1]; break;  
      case  FMUL:
            FP--; FSTACK[FP]*= FSTACK[FP+1]; break;  
      case  FDIV:
            FP--; FSTACK[FP]/= FSTACK[FP+1]; break;  
      case  FPRINT:
            printf("%f", FSTACK[FP]); break;
      case  ECR: // prints new line
            printf("\n"); break;
            
            
      // Constants and One argument math functions.      
      case  FPI:   // constant pi
            FSTACK[++FP] = M_PI; break;
      case  FE:    // constant e
            FSTACK[++FP] = exp(1.0); break;
      case  FABS:  FSTACK[FP] = fabs(FSTACK[FP]); break;
      case  FNEG:  FSTACK[FP] = -FSTACK[FP]; break;
      case  FEXP:  FSTACK[FP] = exp(FSTACK[FP]); break;
      case  FLN:   FSTACK[FP] = log(FSTACK[FP]); break;
      case  FLOG10:FSTACK[FP] = log10(FSTACK[FP]); break;
      case  FSIN:  FSTACK[FP] = sin(FSTACK[FP]); break;
      case  FCOS:  FSTACK[FP] = cos(FSTACK[FP]); break;
      case  FTAN:  FSTACK[FP] = tan(FSTACK[FP]); break;
      case  FSINH: FSTACK[FP] = sinh(FSTACK[FP]); break;
      case  FCOSH: FSTACK[FP] = cosh(FSTACK[FP]); break;
      case  FTANH: FSTACK[FP] = tanh(FSTACK[FP]); break;
      case  FUP:   if (FP < MAXFSTACKSIZE-1) FP++; break; 
      case  FDOWN: if (FP) FP--; break;
      case ERROR:
     printf("ERROR\n");
     break;
      case  QUIT:
            printf("quitting...\n");
     exitnow = 1;
     break;
      };
      tok = strtok(NULL, delims);
    } 
    if (exitnow) {
       puts("Thanks for using easyforth!\n");
       break;
    }
  };
  return 0;
};
Here is a simple compilation and execution run.
toto@toto-VirtualBox:~/Projects/forth$ gcc day4-easyforth.c -lm
toto@toto-VirtualBox:~/Projects/forth$ ./a.out 
>>pi 2 / sin .
1.000000>>1.0 exp .
2.718282>>

Friday, November 13, 2015

Day 3: A Forth interpreter in C, basic four function calculator.


It is day 3 for our Forth interpreter in C. To show that we wrote already has capabilities to compute simple arithmetic we add an evaluator routines inside the main function to the current code.


#include 
#include 
#include 
#include 

/*
 day 2 - tokenizing.
 day 3 - 11.13.2015 basic function calculator.
*/

#define MAXBUFFSIZE 128
#define MAXFSTACKSIZE 32

double FSTACK[MAXFSTACKSIZE];
int    FP = 0;                // index to FSTACK;

char    BUFF[MAXBUFFSIZE];   // input string buffer.

char   delims[] = " \t\n";   // delimiters.
double fval     = 0.0;


enum  Dtypes{ERROR, FNUM, FADD,FSUB, FMUL, FDIV, FPRINT, 
             ECR,  QUIT};

int  lexer(char* tok)
{
    int  n = strlen(tok);
    char c = *tok;
    if (n == 1){
       if (c == '+') return FADD;
       if (c == '-') return FSUB;
       if (c == '*') return FMUL;
       if (c == '/') return FDIV;
       if (c == '.') return FPRINT;
    }
    if (getnumber(tok) == 0) {
       return FNUM;
    };
    if (strcmp(tok, "quit")== 0) {
       return QUIT;
    }
    if (strcmp(tok, "ecr") == 0) {
       return ECR;
    }
    return ERROR;
}


int checknumber(char *s)
{
  /* Description
     Returns 0 if s is a double real number, otherwise nonzero value.
     It is assumed that leading and trailing white spaces are removed from s.
     1 illegal character after '.'
     2 illegal starting character.
     3 illegal character after 'e'
     4 expected a '\0'
     5 empty string.
   */
  char* t = s;
  /* empty string */
  if (*t == '\0') return 5; 
  /* starts with an optional sign? */
  if ((*t == '-') || (*t == '+'))t++;
  // block of digits starting with a digit 
  if (isdigit(*t)) { /* starts with a digit? */
  while (isdigit(*t)) t++;
  if (*t == '.'){ /* a block starting with a .? */
    t++;
    if (*t == '\0') return 0;  // a number ending with a '.'
    while (isdigit(*t)) t++;
  }
  }else if (*t == '.'){ /* a number starting with a .? */
 t++;
 if (! isdigit(*t)) return 1;
 while (isdigit(*t)) t++;
  } else return 2;  /* illegal starting value! */
    
  /* optional exponent */
  if (tolower(*t) == 'e') {
 t++;
 if ((*t == '-') || (*t == '+')) {
    t++;
 }
 if (!isdigit(*t))return 3;
 while isdigit(*t) t++;
  }
  /* illegal character */
  if (*t != '\0') return 4;
  return 0;
};


int getnumber(char *s){
   int i = checknumber(s);
   if (i==0) {
      fval = atof(s);
   }
   return i;
};

int main() {
  int i =0;
  int exitnow = 0;
  while (1) {
    fputs(">>", stdout);
    fgets(BUFF, MAXBUFFSIZE-1, stdin);
    char *tok = strtok(BUFF, delims);
    while (tok)  {
      // printf("%d %s", ++i, tok);
      if (tok == NULL) break;
     
      // process token.
      int dtype = lexer(tok);
      switch(dtype) {
      case  FNUM:
            FSTACK[++FP]= fval; break;
      case  FADD:
            FP--; FSTACK[FP]+= FSTACK[FP+1]; break;  
      case  FSUB:
            FP--; FSTACK[FP]-= FSTACK[FP+1]; break;  
      case  FMUL:
            FP--; FSTACK[FP]*= FSTACK[FP+1]; break;  
      case  FDIV:
            FP--; FSTACK[FP]/= FSTACK[FP+1]; break;  
      case  FPRINT:
            printf("%f", FSTACK[FP]); break;
      case  ECR: // prints new line
            printf("\n"); break;
      case  QUIT:
            printf("quitting...\n");
     exitnow = 1;
     break;
      case ERROR:
     printf("ERROR\n");
     break;
      };
      tok = strtok(NULL, delims);
    } 
    if (exitnow) {
       puts("Thanks for using easyforth!\n");
       break;
    }
  };
  return 0;
};

As a test, we compute, in infix notation, (12 + 34) * -45 + 120) / 456.

toto@toto-VirtualBox:~/Projects/forth$ ./a.out
>>12 34 + -45 * 120 + 456 / .
-4.276316>>quit
quitting...
Thanks for using easyforth!

Using a scientific calculator, gives the result 4276315789.

Thursday, November 12, 2015

Day 2: A forth interpreter in C, tokenizing


On our second day, we analyze each token, determine if it is a number or an operator.


/

#include 
#include 
#include 
#include 

/*
 day 2 - tokenizing.
*/

#define MAXBUFFSIZE 128
char    BUFF[MAXBUFFSIZE];   // input string buffer.

char delims[] = " \t\n";
double fval   = 0;

enum  Dtypes{ERROR, FNUM, FADD,FSUB, FMUL, FDIV, FPRINT, QUIT};

int  lexer(char* tok)
{
    int  n = strlen(tok);
    char c = *tok;
    if (n == 1){
       if (c == '+') return FADD;
       if (c == '-') return FSUB;
       if (c == '*') return FMUL;
       if (c == '/') return FDIV;
       if (c == '.') return FPRINT;
    }
    if (getnumber(tok) == 0) {
       return FNUM;
    };
    if (strcmp(tok, "quit")== 0) {
       return QUIT;
    }
    return ERROR;
}


int checknumber(char *s)
{
  /* Description
     Returns 0 if s is a double real number, otherwise nonzero value.
     It is assumed that leading and trailing white spaces are removed from s.
     1 illegal character after '.'
     2 illegal starting character.
     3 illegal character after 'e'
     4 expected a '\0'
     5 empty string.
   */
  char* t = s;
  /* empty string */
  if (*t == '\0') return 5; 
  /* starts with an optional sign? */
  if ((*t == '-') || (*t == '+'))t++;
  // block of digits starting with a digit 
  if (isdigit(*t)) { /* starts with a digit? */
  while (isdigit(*t)) t++;
  if (*t == '.'){ /* a block starting with a .? */
    t++;
    if (*t == '\0') return 0;  // a number ending with a '.'
    while (isdigit(*t)) t++;
  }
  }else if (*t == '.'){ /* a number starting with a .? */
 t++;
 if (! isdigit(*t)) return 1;
 while (isdigit(*t)) t++;
  } else return 2;  /* illegal starting value! */
    
  /* optional exponent */
  if (tolower(*t) == 'e') {
 t++;
 if ((*t == '-') || (*t == '+')) {
    t++;
 }
 if (!isdigit(*t))return 3;
 while isdigit(*t) t++;
  }
  /* illegal character */
  if (*t != '\0') return 4;
  return 0;
};


int getnumber(char *s){
   int i = checknumber(s);
   if (i==0) {
      fval = atof(s);
   }
   return i;
};

int main() {
  int i =0;
  int exitnow = 0;
  while (1) {
    fputs(">>", stdout);
    fgets(BUFF, MAXBUFFSIZE-1, stdin);
    char *tok = strtok(BUFF, delims);
    while (tok)  {
      printf("%d %s", ++i, tok);
      if (tok == NULL) break;
     
      // process token.
      int dtype = lexer(tok);
      switch(dtype) {
      case  FNUM:
            printf("FNUM %f\n",fval);
            break;
      case  FADD:
      case  FSUB:
      case  FMUL:
      case  FDIV:
      case  FPRINT:
            printf("[%s]\n", tok);  
     break;
      case  QUIT:
            printf("quitting...\n");
     exitnow = 1;
     break;
      case ERROR:
     printf("ERROR\n");
     break;
      };
      tok = strtok(NULL, delims);
    } 
    if (exitnow) {
       puts("Thanks for using easyforth!\n");
       break;
    }
  };
  return 0;
};



Here is a compilation-run of our recent program version.

toto@toto-VirtualBox:~/Projects/forth$ gcc day2-easyforth.c
toto@toto-VirtualBox:~/Projects/forth$ ./a.out
>>-1.2345 320 7 + * - 
1 -1.2345FNUM -1.234500
2 320FNUM 320.000000
3 7FNUM 7.000000
4 +[+]
5 *[*]
6 -[-]
>>quit
7 quitquitting...
Thanks for using easyforth!

In the next installment we add a simple working calculator.


Wednesday, November 11, 2015

Day 1: A fresh restart, A forth interpreter in C.



I do not know why I stop some projects until they are dead or nearly dead. I have forgotten the components of the last Forth interpreter I wrote, and I'd rather rewrite from scratch. So without further ado, here is my latest attempt for a Forth interpreter. As a start, we simply read from the standard input and prints out the tokens. Forth is simple in that tokens are separated by spaces. Here we allow tabs and new lines.


/
#include 
#include 
#define MAXBUFFSIZE 128

char    BUFF[MAXBUFFSIZE];   // input string buffer.

char delims[] = " \t\n";

int main() {
  int i =0;
  int exitnow = 0;
  while (1) {
    fputs(">>", stdout);
    fgets(BUFF, MAXBUFFSIZE-1, stdin);
    char *tok = strtok(BUFF, delims);
    while (tok)  {
      printf("%d %s\n", ++i, tok);
      if (tok == NULL) break;
      if (strcmp(tok, "quit")==0) {
 printf("quitting...\n");
 exitnow = 1;
 break;
      }
      tok = strtok(NULL, delims);
    } 
    if (exitnow) {
       puts("Thanks for using easyforth!\n");
       break;
    }
  };
  return 0;
}

Here is a run of our preliminary interpreter (without token execution).

toto@toto-VirtualBox:~/Projects/forth$ gcc easyforth.c
toto@toto-VirtualBox:~/Projects/forth$ ./a.out
>>123 456 789 10 + + + .
1 123
2 456
3 789
4 10
5 +
6 +
7 +
8 .
>>

next we shall revise the code above to execute simple arithmetic.


Friday, March 14, 2014

A new Forth interpreter written in C


/
/*
File      forth-and-c.c
Author    Ernesto P. Adorio
          ernesto.adorio@gmail.com
Desc
This simple forth interpreter reads from the command line based on the following
prescription.

loop:
  read
  eval
  print

This version uses double floating point numbers for ease in applications.
Version   0.0.1 march 12, 2014
Compile   gcc -std=gnu99 forth-and-c.c  
*/

#include 
#include 
#include 
#include 



/* Constants */
char* ByeMessage = "Thanks for trying out forth-and-c.\n";
char* WelcomeMessage="Welcome to Forth-and-C Version 0.0.1, March 12, 2014.\n";
    
/* Global interpreter variables. */



#define BUFFMAXLEN 1024 
#define EOI '\0'
 char BUFF[BUFFMAXLEN];
 char * tokenstart, *tokenend = BUFF;
 
 #define MAXSTACKDEPTH 10
 union {
   double f;
   long int i;
 }OPSTACK[MAXSTACKDEPTH];
 int opindex = -1;


char PROMPT[32]= ">> ";

/* token system */
double fnum;  /* number read */
enum tokentype  { FPLUS, FMINUS, FDIV, FMUL, DOT,   BYE,  EMIT,   CR, EOL, FNUM, UNDEFINED};
char* symbols[] ={  "+",  "-",    "/",  "*",  ".",  "bye","emit", "cr" };
int NSYMBOLS=8;

char* errmssgs[] = {"NOERROR", "OVERFLOW", "UNDERFLOW"};
enum errorcodes {NOERROR, OVERFLOW, UNDERFLOW};
int error = NOERROR;


int lex(void)
{  
   /* process token pointed to by token start */
   if (*tokenstart==EOI) {
     return EOL;
   }
   for (int i = 0; i < NSYMBOLS; i++){
      if (strcmp(tokenstart, symbols[i]) == 0){
         return i;
      }   
   }
   
   /* Pure Forth assumes a number only after trying other token types */
   fnum = strtod(tokenstart,NULL);
   return FNUM;
   
   /* Error at this stage! */
   return UNDEFINED;
}p
  
  
int parse(void)
/* Parsing system, splits input line into tokens */
{
   tokenstart = tokenend;
   /* Find location of next space character. */ 
   while (! isspace(*tokenend) &&  *tokenend !=EOI)tokenend++;
   if (*tokenend != EOI){
      *tokenend++='\0';
      return 1;
   } else {
     /* reset tokenend */
     return EOL;
   } 
}


int execute(int toktype)
{
  switch(toktype) {
    case FNUM:if (opindex < MAXSTACKDEPTH) {
                 OPSTACK[++opindex].f = fnum;
              } 
       break;
    case DOT: if (opindex >= 0){
                 printf("%f ", OPSTACK[opindex--].f);
       } else {
  error= UNDERFLOW;
       }; 
       break;
    case FPLUS:  
              OPSTACK[--opindex].f += OPSTACK[opindex + 1].f;
              break;
    case FMINUS:
              OPSTACK[--opindex].f -= OPSTACK[opindex + 1].f;
              break;
    case FMUL:
              OPSTACK[--opindex].f *= OPSTACK[opindex + 1].f;
              break;
    case FDIV:
              OPSTACK[--opindex].f /= OPSTACK[opindex + 1].f;                    
              break;
    case EMIT:putchar( (int) (OPSTACK[opindex--].f));
       break;
    case CR:  /* carriage return */
              putchar(10); putchar(13);
              break;
    default:  break;                  
  };    
};


int main()
{
   int ntokens = 0;
   /* print welcome.*/
   printf("%s", WelcomeMessage);
   
   while (1) {
      /* read input */
      printf("%s", PROMPT);
      fgets(BUFF, BUFFMAXLEN, stdin);
      
      /*reset tokenizer */
      tokenend=BUFF;              
      while (parse()!= EOL) {
 ntokens ++;
 int tokentype = lex();
 // printf("%d: %s %d\n",ntokens, tokenstart, tokentype);
 execute(tokentype);
 
 if (tokentype == BYE) {
   printf("%s", ByeMessage);
  
   return (0);
 }  
 if (error) {
   printf("%s", errmssgs[error]);
   switch(error){
     case UNDERFLOW:opindex= -1; break ;
     case OVERFLOW: opindex= MAXSTACKDEPTH - 1; break;
     default: break;
   }  
   error = 0;
 }
      }
   }
}


We have decided to rewrite our Forth interpreter written in C. Default data type are double floating point numbers and this allows you to use it for processing simple arithmetic problems.

Compile the above using the command line invocation

gcc -std=gnu99 forth-and-c.c
Then run the program by typing ./a.out Type the expression 4 3 * 1 - . You should get the answer 11.


Tuesday, August 20, 2013

Extracting and displaying the Astronomy Photo of the Day in a server.


I am having problems presenting this article. Please be patient.

The most astounding photos in astronomy are posted daily in the NASA site
http://apod.nasa.gov The url of the photo
however do not have the same value everyday, say "apod.jpg", instead the
filename is like "http://apod.nasa.gov/apod/image/1308/sunvenusuv3_dove_960.jpg".
This filename is embedded in the redirected url
"http://apod.nasa.gov/apod/astropix.html".


The image filename is enclosed in an IMG tag.Our hope is that all other html
containing the image file has similar html template.
So we read in this file, extract the filename and build up the image url.
We then use the Linux utility wget to download the image file, then move it
to a fixed destination in our server with a fixed filename apod.jpg.
This way we only "disturb" the NASA site once each day instead of linking
each time a browser visits our weather page which hosts the image.

This is our first version. Python has changed much with new recommended
libraries and we will update the following code to make it more readable and
"Pythonic". We are open to experiment with the regular expression library,
and use the Requests module.


#!/usr/bin/env python

import urllib
import os

 
src = "http://apod.nasa.gov/apod/astropix.html"
strstart="<img SRC=\""
l = len(strstart)

contents = urllib.urlopen(src).read()
startpos = contents.find(strstart)
print "parsing and determining graphics file name"
if startpos:
   endpos = startpos + contents[startpos:].find(".jpg\"")+len(".jpg\"")
   imgurl = "http://apod.nasa.gov/apod/"+contents[startpos+l:endpos-1]
   

   print "copying to destination directory"
   os.system("sudo wget -ct 0 %s" % imgurl)  
   srcfile   = imgurl[imgurl.rfind("/")+1:]

   destfile = "/var/www/xxxxx/xxxx/xxx/apod.jpg"

   #print "storing image file to apod.jpg"
   os.system("sudo cp  %s %s" % (srcfile, destfile))
To see how it works out, please click on our weather http://adorio-research.org/wordpress/?page_id=5833 page.

Wednesday, November 14, 2012

Programming in R, computing determinant of matrix.


Assume that the matrix is square with number of rows greater than or equal to 2.
The determinant of the 2 by 2 matrix


$
A = \begin{array}{ll}
a_{11} & a_{12}\\
a_{21} & a_{22} \\
\end{array}
$

is given by A[1,1]* A[2,2] - A[2,1] * A[1,2]. To be continued.....

$\sum_{\forall j} A[1,j] * (-1) ^ {j+1} *det(A[-1,-j]$

where A[-1, -j] denotes the submatrix obtained by deleting the first row and the jth column! R has a clever method of denoting the row or column to be deleted.


here is a simple recursive implementation with debugging statements. We ask the reader to remove them and simplify the code.

"""
# file    mydet.R
# author  your name here!


mydet <- function (A) {
    rows <-nrow(A)
    print (c("rows=", rows))
    if (rows != ncol(A)) {
       print("A is not a square matrix!!!")
    }
    if (rows == 2) {
       result <- (A[1,1] * A[2,2] - A[2,1] * A[1,2])
       print (c("result=", result))
       return(result)
    }

    # expand by first row.
    tot = 0.0
    sign = 1
    for (j in seq(1, rows)){
       tot  = tot + sign * A[1,j] * mydet(A[-1,-j])
       sign = -sign
    }
    return(tot)
}