Skip to content

Commit

Permalink
Added support for floating points lexing in all bases :)
Browse files Browse the repository at this point in the history
`src/tokenizer.c`:
  `consume_floating_number` and `consume_hex_floating_number` are pretty
  much identical, barring how they accept the base character set, but
  finally that hurdle is over and done with.

`tests/`:
  Added relevant passing/failing regression tests.
  • Loading branch information
unazed committed Aug 5, 2024
1 parent 962de2d commit 0aee55f
Show file tree
Hide file tree
Showing 8 changed files with 196 additions and 3 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,5 @@ build/*
.venv/*
.cache/*
.ccls-cache/*
a.out
t.c
144 changes: 142 additions & 2 deletions src/tokenizer.c
Original file line number Diff line number Diff line change
Expand Up @@ -233,16 +233,156 @@ consume_integer_suffix (struct lexeme* constant,
return copy_lexeme_into_heap(*constant);
}

bool
consume_floating_suffix (impln(bytestream_t) stream, struct lexeme* lex)
{
size_t start = lex->length;
char *current = stream->peek (lex->length++);
size_t suffix_length = 1;

if (tolower (*current) == 'f')
lex->ctx_for.floating_constant.suffix = FloatSuffix;
else if (tolower (*current) == 'l')
lex->ctx_for.floating_constant.suffix = LongDoubleSuffix;

while (current != NULL && (current = stream->peek (lex->length++)))
{
if (!isalnum (*current))
break;
suffix_length++;
}
lex->length--;

if (suffix_length != 1)
{
richloc_ctx->push_error ("invalid suffix on floating constant",
start, suffix_length);
return false;
}

ucc_log("Parsed float suffix (%zu bytes): '%.*s'\n",
suffix_length, suffix_length, stream->peek (lex->length) - suffix_length);
return true;
}

bool
consume_number_exponent (impln(bytestream_t) stream, struct lexeme* lex)
{
char *current = stream->peek (lex->length++),
*next = stream->peek (lex->length);
size_t exp_length = 1;

if (next && (*next == '+' || *next == '-'))
{
lex->length++;
exp_length++;
}

while (current != NULL && (current = stream->peek (lex->length)))
{
if (!isdigit (*current))
break;
lex->length++;
exp_length++;
}

if (lex->length - 1 == 1)
{
richloc_ctx->push_error ("expected numeric exponent",
lex->length, 1);
return false;
}
ucc_log("Parsed exponent (%zu bytes): %.*s\n",
exp_length, exp_length, stream->peek (lex->length - exp_length));
return true;
}

struct lexeme*
consume_hex_floating_number (impln(bytestream_t) stream)
{
__builtin_unimplemented ();
struct lexeme lex = {
.type = FloatingConstant,
.ctx_for.floating_constant.base = HexadecimalFloatingConstant,
.raw = stream->peek (0),
.length = 2
};

char* current = stream->peek (0);
bool has_exponent = false;

while (current != NULL && (current = stream->peek (lex.length)))
{
if (!has_exponent && tolower (*current) == 'p')
{
if (!consume_number_exponent (stream, &lex))
{
stream->consume (lex.length);
return NULL;
}
has_exponent = true;
continue;
}
if (!isxdigit (*current) && isalpha (*current))
{
if (!consume_floating_suffix (stream, &lex))
{
stream->consume (lex.length);
return NULL;
}
break;
}
else if (*current != '.' && !isxdigit (*current))
break;
lex.length++;
}

ucc_log("HexFloat(%zu bytes): '%.*s'\n", lex.length, lex.length, lex.raw);
stream->consume (lex.length);
return copy_lexeme_into_heap (lex);
}

struct lexeme*
consume_floating_number (impln(bytestream_t) stream)
{
__builtin_unimplemented ();
struct lexeme lex = {
.type = FloatingConstant,
.ctx_for.floating_constant.base = DecimalFloatingConstant,
.raw = stream->peek (0),
.length = 0
};

char* current = stream->peek (0);
bool has_exponent = false;

while (current != NULL && (current = stream->peek (lex.length)))
{
if (!has_exponent && tolower (*current) == 'e')
{
if (!consume_number_exponent (stream, &lex))
{
stream->consume (lex.length);
return NULL;
}
has_exponent = true;
continue;
}
if (isalpha (*current))
{
if (!consume_floating_suffix (stream, &lex))
{
stream->consume (lex.length);
return NULL;
}
break;
}
else if (*current != '.' && !isdigit (*current))
break;
lex.length++;
}

ucc_log("Float(%zu bytes): '%.*s'\n", lex.length, lex.length, lex.raw);
stream->consume (lex.length);
return copy_lexeme_into_heap (lex);
}

struct lexeme*
Expand Down
2 changes: 1 addition & 1 deletion tests/empty_character.fail.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
int
main (void)
{
char c = 'a';
char c = '';
}
9 changes: 9 additions & 0 deletions tests/float_numbers.pass.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
int
main (void)
{
float a = .123456789;
float b = 1.;
float c = 1.e-123;
float d = .123e123;
float e = 1.1;
}
12 changes: 12 additions & 0 deletions tests/float_numbers_suffix.fail.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
int
main (void)
{
float a = .123456789asd;
float a_ = .123456789fl;
float b = 1.Lf;
float b_ = 1.asd;
float c = 1.e-123ff;
float c_ = 1.e-123ll;
float d = .123e123FF;
float d_ = .123e123lLL;
}
14 changes: 14 additions & 0 deletions tests/float_numbers_suffix.pass.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
int
main (void)
{
float a = .123456789f;
float a_ = .123456789l;
float b = 1.f;
float b_ = 1.l;
float c = 1.e-123f;
float c_ = 1.e-123l;
float d = .123e123f;
float d_ = .123e123l;
float e = 1.1f;
float e_ = 1.1l;
}
16 changes: 16 additions & 0 deletions tests/hex_float_numbers.pass.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/*
* fragment HexadecimalFloatingConstant
* : HexadecimalPrefix (HexadecimalFractionalConstant | HexadecimalDigitSequence) BinaryExponentPart FloatingSuffix?
* ;
*/

int
main (void)
{
float a = 0x123456789abcdef.123456789abcdefp1;
float b = 0x123456789abcdef.123456789abcdefp-1;
float c = 0x.0p-1;
float d = 0x.0p1;
float e = 0x.0p1f;
float f = 0x.0p1l;
}
Binary file modified ucc
Binary file not shown.

0 comments on commit 0aee55f

Please sign in to comment.