support for unbounded integers

This commit is contained in:
krangelov
2021-08-27 11:31:10 +02:00
parent 684f85ff94
commit 8195f8b0cb
10 changed files with 113 additions and 23 deletions

View File

@@ -7,10 +7,11 @@ PgfLiteral PgfDBMarshaller::match_lit(PgfUnmarshaller *u, PgfLiteral l)
{
switch (ref<PgfLiteral>::get_tag(l)) {
case PgfLiteralInt::tag: {
return u->lint(ref<PgfLiteralInt>::untagged(l)->val);
auto lint = ref<PgfLiteralInt>::untagged(l);
return u->lint(lint->size, lint->val);
}
case PgfLiteralFlt::tag: {
return u->lflt(ref<PgfLiteralInt>::untagged(l)->val);
return u->lflt(ref<PgfLiteralFlt>::untagged(l)->val);
}
case PgfLiteralStr::tag: {
return u->lstr(&ref<PgfLiteralStr>::untagged(l)->val);
@@ -285,7 +286,10 @@ void PgfExprParser::token()
if (ch == '>') {
ch = getc();
token_tag = PGF_TOKEN_RARROW;
}
} else if (isdigit(ch)) {
putc('-');
goto digit;
}
break;
case ',':
ch = getc();
@@ -329,10 +333,11 @@ void PgfExprParser::token()
} while (pgf_is_ident_rest(ch));
token_tag = PGF_TOKEN_IDENT;
} else if (isdigit(ch)) {
while (isdigit(ch)) {
digit:
do {
putc(ch);
ch = getc();
}
} while (isdigit(ch));
if (ch == '.') {
putc(ch);
@@ -422,8 +427,23 @@ PgfExpr PgfExprParser::parse_term()
return e;
}
case PGF_TOKEN_INT: {
int n = atoi((const char*) &token_value->text);
PgfLiteral lit = u->lint(n);
size_t size = (token_value->size + LINT_BASE_LOG - 1)/LINT_BASE_LOG;
uintmax_t *value = (uintmax_t *) alloca(size*sizeof(uintmax_t));
char *p = token_value->text + token_value->size;
for (size_t i = size; i > 0; i--) {
char tmp = *p; *p = 0;
char *s = p - LINT_BASE_LOG;
if (s < token_value->text)
s = token_value->text;
value[i-1] = (uintmax_t)
(s == token_value->text) ? strtoll(s, NULL, 10)
: strtoull(s, NULL, 10);
*p = tmp;
p = s;
}
PgfLiteral lit = u->lint(size, value);
PgfExpr e = u->elit(lit);
u->free_ref(lit);
token();

View File

@@ -13,7 +13,8 @@ struct PGF_INTERNAL_DECL PgfLiteralStr {
struct PGF_INTERNAL_DECL PgfLiteralInt {
static const uint8_t tag = 1;
int val;
size_t size;
uintmax_t val[];
} ;
struct PGF_INTERNAL_DECL PgfLiteralFlt {

View File

@@ -75,6 +75,25 @@ typedef struct {
PgfType type;
} PgfTypeHypo;
/* Arbitrary size integers are represented as an array of uintmax_t
* values. Each value in the array is at most LINT_BASE-1 big.
* LINT_BASE itself is always 10 ^ LINT_BASE_LOG. */
#if __WORDSIZE == 8
#define LINT_BASE 100
#define LINT_BASE_LOG 2
#elif __WORDSIZE == 16
#define LINT_BASE 10000
#define LINT_BASE_LOG 4
#elif __WORDSIZE == 32
#define LINT_BASE 1000000000
#define LINT_BASE_LOG 9
#elif __WORDSIZE == 64
#define LINT_BASE 10000000000000000000
#define LINT_BASE_LOG 19
#else
#error "Platforms with the current __WORDSIZE are not supported yet"
#endif
/* The PgfUnmarshaller structure tells the runtime how to create
* abstract syntax expressions and types in the heap of
* the host language. For instance, when used from Haskell the runtime
@@ -105,7 +124,7 @@ struct PgfUnmarshaller {
virtual PgfExpr evar(int index)=0;
virtual PgfExpr etyped(PgfExpr expr, PgfType typ)=0;
virtual PgfExpr eimplarg(PgfExpr expr)=0;
virtual PgfLiteral lint(int v)=0;
virtual PgfLiteral lint(size_t size, uintmax_t *v)=0;
virtual PgfLiteral lflt(double v)=0;
virtual PgfLiteral lstr(PgfText *v)=0;
virtual PgfType dtyp(int n_hypos, PgfTypeHypo *hypos,

View File

@@ -249,15 +249,25 @@ PgfExpr PgfPrinter::eimplarg(PgfExpr expr)
return 0;
}
PgfLiteral PgfPrinter::lint(int v)
#define xstr(s) str(s)
#define str(s) #s
PgfLiteral PgfPrinter::lint(size_t size, uintmax_t *v)
{
nprintf(16, "%d", v);
if (size == 0)
puts("0");
else {
nprintf(32, "%jd", v[0]);
for (size_t i = 1; i < size; i++) {
nprintf(32, "%0" xstr(LINT_BASE_LOG) "ju", v[i]);
}
}
return 0;
}
PgfLiteral PgfPrinter::lflt(double v)
{
nprintf(16,"%lg",v);
nprintf(32,"%lg",v);
return 0;
}

View File

@@ -53,7 +53,7 @@ public:
virtual PgfExpr evar(int index);
virtual PgfExpr etyped(PgfExpr expr, PgfType typ);
virtual PgfExpr eimplarg(PgfExpr expr);
virtual PgfLiteral lint(int v);
virtual PgfLiteral lint(size_t size, uintmax_t *v);
virtual PgfLiteral lflt(double v);
virtual PgfLiteral lstr(PgfText *v);
virtual PgfType dtyp(int n_hypos, PgfTypeHypo *hypos,

View File

@@ -195,8 +195,9 @@ PgfLiteral PgfReader::read_literal()
}
case PgfLiteralInt::tag: {
ref<PgfLiteralInt> lit_int =
DB::malloc<PgfLiteralInt>(tag);
lit_int->val = read_int();
DB::malloc<PgfLiteralInt>(sizeof(PgfLiteralInt)+sizeof(uintmax_t));
lit_int->size = 1;
lit_int->val[0] = read_int();
lit = ref<PgfLiteralInt>::tagged(lit_int);
break;
}