Added full number, based number (both int and float), string and character literals handling

This commit is contained in:
Pawel Szostek 2011-02-04 17:51:51 +01:00 committed by Stephen Williams
parent 0395eadbc8
commit 77a346ffb1
8 changed files with 527 additions and 25 deletions

View File

@ -57,10 +57,10 @@ CXXFLAGS = @WARNING_FLAGS@ @WARNING_FLAGS_CXX@ @CXXFLAGS@
LDFLAGS = @LDFLAGS@
LIBS = @LIBS@ @EXTRALIBS@
M = StringHeap.o LineInfo.o
M = StringHeap.o LineInfo.o
O = main.o compiler.o entity.o entity_elaborate.o \
lexor.o lexor_keyword.o parse.o $M
lexor.o lexor_keyword.o parse.o vhdlreal.o vhdlint.o $M
all: dep vhdlpp@EXEEXT@

View File

@ -19,17 +19,20 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* aint64_t with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
# include "parse_api.h"
# include "lexor_keyword.h"
# include "vhdlnum.h"
# include "vhdlint.h"
# include "vhdlreal.h"
# include "parse_wrap.h"
# include <cmath>
# include <cassert>
# include <iostream>
# include <set>
//class vhdlnum;
//class vhdlreal;
@ -45,10 +48,16 @@ extern int lexor_keyword_code (const char*str, unsigned len);
*/
extern YYLTYPE yylloc;
static int check_underscores(char* text);
static bool are_underscores_correct(char* text);
static bool is_based_correct(char* text);
static char* escape_quot_and_dup(char* text);
static char* escape_apostrophe_and_dup(char* text);
vhdlnum* make_unisized_dec(char* text);
vhdlnum* make_unisized_based(char* text);
static double make_double_from_based(char* text);
static int64_t make_long_from_based(char* text);
static int64_t lpow(int64_t left, int64_t right);
static unsigned short short_from_hex_char(char ch);
static char* strdupnew(char const *str)
{
@ -90,13 +99,26 @@ based_integer [0-9a-fA-F](_?[0-9a-fA-F])*
<CCOMMENT>\n { yylloc.first_line += 1; }
<CCOMMENT>"*/" { BEGIN(comment_enter); }
\'.\' {
yylval.text = escape_apostrophe_and_dup(yytext);
return CHARACTER_LITERAL;
}
(\"([^"]|(\"\"))*?\")|(\"[^\"]*\") {
/* first pattern: string literals with doubled quotation mark */
/* second pattern: string literals without doubled quotation */
yylval.text = escape_quot_and_dup(yytext);
assert(yylval.text);
return STRING_LITERAL;
}
[a-zA-Z][a-zA-Z0-9_]* {
int rc = lexor_keyword_code(yytext, yyleng);
switch (rc) {
case IDENTIFIER:
if(check_underscores(yytext))
std::cerr << "An invalid underscore in the identifier" << std::endl;
if(!are_underscores_correct(yytext))
std::cerr << "An invalid underscore in the identifier:"
<< yytext << std::endl;
//yywarn(yylloc, "An invalid underscore in the identifier");
yylval.text = strdupnew(yytext);
break;
@ -106,26 +128,43 @@ based_integer [0-9a-fA-F](_?[0-9a-fA-F])*
return rc;
}
\\(.|\\\\)*\\ { /* extended identifiers */
\\([^\\]|\\\\)*\\ { /* extended identifiers */
yylval.text = strdupnew(yytext);
printf("special %s\n", yytext);
return IDENTIFIER;
}
{decimal_literal} {
if(!are_underscores_correct(yytext))
std::cerr << "An invalid underscore in the decimal literal:"
<< yytext << std::endl;
if(strchr(yytext, '.')) {
yylval.real = new vhdlreal(yytext);
return REAL_LITERAL;
} else {
yylval.integer = new vhdlnum(yytext);
yylval.integer = new vhdlint(yytext);
return INT_LITERAL;
}
}
{based_literal} {
yylval.integer = new vhdlnum(yytext);
return INT_LITERAL;
if(!are_underscores_correct(yytext) || !is_based_correct(yytext))
std::cerr << "An invalid form of based literal:"
<< yytext << std::endl;
if(strchr(yytext, '.'))
{
double val = make_double_from_based(yytext);
yylval.real = new vhdlreal(val);
return REAL_LITERAL;
}
else
{
int64_t val = make_long_from_based(yytext);
yylval.integer = new vhdlint(val);
return INT_LITERAL;
}
}
@ -158,7 +197,14 @@ based_integer [0-9a-fA-F](_?[0-9a-fA-F])*
extern void yyparse_set_filepath(const char*path);
static int check_underscores(char* text)
/**
* This function checks if underscores in an identifier
* or in a number are correct.
*
* \return true is returned if underscores are placed
* correctly according to specification
*/
static bool are_underscores_correct(char* text)
{
unsigned char underscore_allowed = 0;
const char* cp;
@ -167,13 +213,285 @@ static int check_underscores(char* text)
if (*cp == '_')
{
if (!underscore_allowed || *(cp+1) == '\0')
return 1;
return 0;
underscore_allowed = 0;
}
else
underscore_allowed = 1;
}
return 0;
return 1;
}
/**
* This function checks if the format of a based number
* is correct according to the VHDL standard
*
* \return true is returned if a based number
* is formed well according to specification
*/
static bool is_based_correct(char* text)
{
char* ptr;
//BASE examination
char clean_base[4];
clean_base[3] = '\0';
char* clean_base_ptr = clean_base;
for(ptr = text; ptr != strchr(text, '#'); ++ptr)
{
if(*ptr == '_')
++ptr;
if(!(*ptr >= '0' && *ptr <= '9')) //the base uses chars other than digits
return 0;
if(*clean_base_ptr == '\0')
break;
*clean_base_ptr = *ptr;
++clean_base_ptr;
}
unsigned length = clean_base_ptr - clean_base;
unsigned base;
if(length > 2 || length == 0)
return 0; //the base is too big or too small
if(length == 2)
{
base = 10*(clean_base[0] - '0') + (clean_base[1] - '0');
//the base exceeds 16 or equals 0
if(base > 16 || base == 0)
return 0;
}
else
{ //the base consists of one char and is equal to zero
base = clean_base[0] - '0';
if(base == 0)
return 0;
}
bool point = 0;
set<char> allowed_chars;
unsigned c;
if(base <= 10) {
for(c = 0; c < base; ++c)
allowed_chars.insert(c + '0');
}
else
{
for(c = 0; c < 10; ++c)
allowed_chars.insert(c + '0');
for(c = 0; c < base - 10; ++c)
allowed_chars.insert(c + 'a');
}
//MANTISSA examination
for(ptr = strchr(text, '#') + 1, length = 0; ptr != strrchr(text, '#'); ++ptr)
{
if(*ptr == '.')
{
//we found a dot and another one was already found
if(point == 1)
return 0;
else
{
//notice the fact of finding a point and continue, without increasing the length
point = 1;
continue;
}
}
//the number consists of other chars than allowed
if(allowed_chars.find(*ptr) == allowed_chars.end())
return 0;
++length;
}
if(length == 0)
return 0;
//EXPONENT examination
if(strchr(text, '\0') - strrchr(text, '#') > 1) { //the number contains an exponent
if(*(strrchr(text, '#') + 2) == '-')
return 0;
length = 0;
for(ptr = strrchr(text, '#')+2; *ptr != '\0'; ++ptr)
{
//the exponent consists of other chars than {'0'.,'9','a'..'f'}
if(!((*ptr >= '0' && *ptr <= '9') || (*ptr >= 'a' && *ptr <= 'f')))
return 0;
}
}
return 1;
}
/**
* This function takes a string literal, gets rid of
* quotation marks and copies the remaining characters
* to a new persistent C-string
*
* \return pointer to the new string is returned
*/
static char* escape_quot_and_dup(char* text)
{
char* newstr = new char[strlen(text)+1];
unsigned old_idx, new_idx;
for(new_idx = 0, old_idx = 0; old_idx < strlen(text); )
{
if(text[old_idx] == '"' && old_idx == 0)
{ //the beginning of the literal
++old_idx;
continue;
}
else
if(text[old_idx] == '"' && text[old_idx+1] == '\0')
{ //the end
newstr[new_idx] = '\0';
return newstr;
}
else
if(text[old_idx] == '"' && text[old_idx+1] == '"')
{
newstr[new_idx++] = '"';
old_idx += 2; //jump across two chars
}
else
{
newstr[new_idx] = text[old_idx];
++old_idx;
++new_idx;
}
}
//the function should never reach this point
return 0;
}
/**
* This function takes a character literal, gets rid
* of the apostrophes and returns new C-string
*
* \return pointer to the new string is returned
*/
static char* escape_apostrophe_and_dup(char* text)
{
char* newstr = new char[2];
newstr[0] = text[1];
newstr[1] = '\0';
return newstr;
}
/**
* This function takes a floating point based number
* in form of a C-strings and converts it to a double.
*
* \return new double is returned
*/
static double make_double_from_based(char* text)
{
char* first_hash_ptr = strchr(text, '#');
char* second_hash_ptr = strrchr(text, '#');
char* last_char_ptr = strchr(text, '\0') - 1;
//put null byte in lieu of hashes
*first_hash_ptr = '\0';
*second_hash_ptr = '\0';
//now lets deduce the base
unsigned base = (unsigned)strtol(text, 0, 10) ;
double mantissa = 0.0;
char*ptr = first_hash_ptr + 1;
for( ; ptr != second_hash_ptr ; ++ptr)
{
if(*ptr == '.')
break;
if(*ptr != '_')
{
mantissa = mantissa*base + short_from_hex_char(*ptr);
}
}
double fraction = 0.0;
double factor = 1.0/base;
for(++ptr ; ptr != second_hash_ptr; ++ptr)
{
if(*ptr != '_')
{
fraction = fraction + short_from_hex_char(*ptr)*factor;
factor = factor / base;
}
}
if(last_char_ptr == second_hash_ptr) //there is no exponent
{
return mantissa + fraction;
}
//now calculate the value of the exponent
double exponent = 0.0;
//leave 'e'/'E' and '+'
ptr = *(second_hash_ptr + 2) == '+' ? second_hash_ptr + 3 : second_hash_ptr + 2;
for( ; *ptr != '\0'; ++ptr)
{
if(*ptr != '_')
{
exponent = exponent*base + short_from_hex_char(*ptr);
}
}
return pow(mantissa + fraction, exponent);
}
/**
* This function takes a hexadecimal digit in form of
* a char and returns its litteral value as short
*/
static unsigned short short_from_hex_char(char ch)
{
if(ch >= '0' && ch <= '9')
return ch - '0';
else
return ch - 'a' + 10;
}
/**
* This function takes a based number in form of
* a C-strings and converts it to a int64_t.
*
* \return new double is returned
*/
static int64_t make_long_from_based(char* text) {
char* first_hash_ptr = strchr(text, '#');
char* second_hash_ptr = strrchr(text, '#');
char* end_ptr = strrchr(text, '\0');
//now lets deduce the base
*first_hash_ptr = '\0';
unsigned base = (unsigned)strtol(text, 0, 10) ;
char *ptr = first_hash_ptr + 1;
int64_t mantissa = 0;
for( ; ptr != second_hash_ptr ; ++ptr)
{
if(*ptr != '_')
{
mantissa = mantissa * base + short_from_hex_char(*ptr);
}
}
//if there is an exponent
if(end_ptr - second_hash_ptr > 1)
{
int64_t exponent = 0L;
ptr = *(second_hash_ptr + 2) == '+' ? second_hash_ptr + 3 : second_hash_ptr + 2;
for( ; *ptr != '\0'; ++ptr)
{
if(*ptr != '_')
exponent = base*exponent + short_from_hex_char(*ptr);
}
return lpow(mantissa, exponent);
}
else
return mantissa;
}
/**
* Recursive power function for int64_t
*/
static int64_t lpow(int64_t left, int64_t right) {
if(right == 0)
return 1;
else
return left*lpow(left, right - 1);
}
void reset_lexor(FILE*fd, const char*path)

View File

@ -20,7 +20,7 @@
*/
# include "vhdlpp_config.h"
# include "vhdlnum.h"
# include "vhdlint.h"
# include "vhdlreal.h"
# include "compiler.h"
# include "parse_api.h"
@ -45,7 +45,7 @@ int parse_errors = 0;
%union {
port_mode_t port_mode;
char*text;
vhdlnum* integer;
vhdlint* integer;
vhdlreal* real;
InterfacePort*interface_element;

View File

@ -26,7 +26,7 @@
*/
# include <list>
# include "vhdlnum.h"
# include "vhdlint.h"
# include "vhdlreal.h"
# include "parse.h"

68
vhdlpp/vhdlint.cc Normal file
View File

@ -0,0 +1,68 @@
#include "config.h"
#include "vhdlint.h"
#include <cstring>
#include <cstdlib>
#include <sstream>
bool vhdlint::is_negative() const
{
return value_ < 0L;
}
bool vhdlint::is_positive() const
{
return value_ > 0L;
}
bool vhdlint::is_zero() const
{
return value_ == 0L;
}
vhdlint::vhdlint(const char* text)
{
unsigned text_length = strlen(text);
if(text_length == 0)
{
value_ = 0L;
return;
}
char* new_text = new char[text_length + 1];
const char* ptr;
char* new_ptr;
for(ptr = text, new_ptr = new_text; *ptr != '\0'; ++ptr)
{
if(*ptr == '_')
continue;
else
{
*new_ptr = *ptr;
++new_ptr;
++ptr;
}
}
*new_ptr = '\0';
istringstream str(new_text);
delete[] new_text;
//TODO: check if numbers greater than MAX_INT are handled correctly
str >> value_;
}
vhdlint::vhdlint(const int64_t& val)
{
value_ = val;
}
vhdlint::vhdlint(const vhdlint& val)
{
value_ = val.as_long();
}
int64_t vhdlint::as_long() const
{
return value_;
}

28
vhdlpp/vhdlint.h Normal file
View File

@ -0,0 +1,28 @@
#ifndef __vhdlint_H
#define __vhdlint_H
#include "config.h"
#include <stdint.h>
using namespace std;
class vhdlint
{
public:
explicit vhdlint(const char* text);
explicit vhdlint(const int64_t& val);
explicit vhdlint(const vhdlint& val);
bool is_negative() const;
bool is_positive() const;
bool is_zero() const;
int64_t as_long() const;
//vhdlv get(const unsigned index) const;
//void set(const unsigned index, const unsigned val);
// unsigned short operator[](const unsigned index);
private:
int64_t value_;
};
#endif

59
vhdlpp/vhdlreal.cc Normal file
View File

@ -0,0 +1,59 @@
#include "config.h"
#include "compiler.h"
#include "vhdlreal.h"
#include <assert.h>
#include <cstring>
#include <cstdlib>
vhdlreal::vhdlreal() {
value_ = 0.0;
}
vhdlreal::vhdlreal(const double& r) {
value_ = r;
}
vhdlreal::vhdlreal(const vhdlreal& val) {
value_ = val.as_double();
}
vhdlreal::vhdlreal(const char* text) {
assert(strlen(text) != 0);
char* buffer = new char[strlen(text)+1];
char* buf_ptr;
for(buf_ptr = buffer; *text != 0; ++buf_ptr, ++text) {
if(*text == '_')
continue;
*buf_ptr = *text;
}
*buf_ptr = '\0';
value_ = strtod(buffer, NULL);
delete[] buffer;
}
ostream& operator<< (ostream& str, const vhdlreal& r) {
return (str << r.as_double());
}
vhdlreal operator+ (const vhdlreal& r1, const vhdlreal& r2) {
return vhdlreal(r1.as_double() + r2.as_double());
}
vhdlreal operator- (const vhdlreal& r1, const vhdlreal& r2) {
return vhdlreal(r1.as_double() - r2.as_double());
}
vhdlreal operator* (const vhdlreal& r1, const vhdlreal& r2) {
return vhdlreal(r1.as_double() * r2.as_double());
}
vhdlreal operator/ (const vhdlreal& r1, const vhdlreal& r2) {
return vhdlreal(r1.as_double() / r2.as_double());
}
vhdlreal operator% (const vhdlreal& r1, const vhdlreal& r2) {
return vhdlreal(fmod(r1.as_double(), r2.as_double()));
}
vhdlreal pow(const vhdlreal& r1, const vhdlreal& r2) {
return vhdlreal(pow(r1.as_double(), r2.as_double()));
}
vhdlreal operator- (const vhdlreal& r) {
return vhdlreal(-r.as_double());
}

View File

@ -2,10 +2,39 @@
#define __vhdlreal_h
#include "config.h"
#include <iostream>
#include <cmath>
class vhdlreal {
public:
vhdlreal(char* text) {}
using namespace std;
/*
* This class holds a floating point decimal number. The number is
* stored as double. All based numbers are converted by an external
* function to a double and then stored as class instance.
*/
class vhdlreal
{
public:
friend ostream& operator<< (ostream&, const vhdlreal&);
friend vhdlreal operator+ (const vhdlreal&, const vhdlreal&);
friend vhdlreal operator- (const vhdlreal&, const vhdlreal&);
friend vhdlreal operator* (const vhdlreal&, const vhdlreal&);
friend vhdlreal operator/ (const vhdlreal&, const vhdlreal&);
friend vhdlreal operator% (const vhdlreal&, const vhdlreal&);
friend vhdlreal pow(const vhdlreal&, const vhdlreal&);
// Unary minus.
friend vhdlreal operator- (const vhdlreal&);
explicit vhdlreal();
explicit vhdlreal(const char*text);
explicit vhdlreal(const double& val);
vhdlreal(const vhdlreal& val);
virtual ~vhdlreal() {};
double as_double() const
{
return value_;
}
protected:
double value_;
};
#endif
#endif