lexer: Ferro 의 렉서를 Ferro 로 쓴다
셀프호스팅에 손대기 전의 강제 함수다. 아픈 자리를 전부 건드린다: R4 아래의 토큰 구조체, 태그드 유니온, 진단 출력, 유닛 경계. 토큰은 자기가 나온 글자를 담지 않는다. R4 가 대여를 집합 저장소에서 막으므로, 어디서 시작해 얼마나 긴지를 적고 소스는 옆에서 같이 다닌다. 위치도 &mut usize 로 옆에서 다닌다 -- 슬라이스와 함께 구조체에 들어갈 수 없기 때문이다. 이것이 R11 이 말하는 모양이고, 쓸 수 있다. first keyword unit @1 / number 42 @3 / text "hi" @3 / arrow -> @5 keyword 6 name 7 number 1 text 1 punct 15 / total 30 길에서 고친 것: - binding.Type.Variant 가 안 풀렸다. 유닛 경계 이름 조회가 심볼만 보고 타입을 보지 않았다. - 문자열 const 전역이 빈 슬라이스로 나갔다. 포인터는 링커만 아는 수라서 바이트에 구멍을 두고 링커가 채우게 한다. - exec.py 가 OUTPUT 마커를 여러 개 적어도 마지막 하나만 검사했다. 고치자마자 readfile 의 낡은 기대가 드러났다. run.py 217/217, exec.py 27/27.
This commit is contained in:
+17
-1
@@ -16,7 +16,23 @@ FeType *cross_unit_value(FeCheckerState *s, FeNode *n, int *handled)
|
||||
if (!home) return 0;
|
||||
*handled=1;
|
||||
sym=unit_member(s->c,home,n->b && n->b->text ? n->b->text : "");
|
||||
if (!sym) { err(s->c,n->loc,"unknown name"); return unknown(s->c); }
|
||||
if (!sym) {
|
||||
/* A name in another unit can be a type as well as a value --
|
||||
`binding.Enum.Variant` reaches one through the other. */
|
||||
FeType *there=unit_type(s->c,home,n->b && n->b->text ? n->b->text : "");
|
||||
FeNode *decl=unit_type_decl(s->c,home,
|
||||
n->b && n->b->text ? n->b->text : "");
|
||||
if (there && decl) {
|
||||
if (!decl_is_public(decl)) {
|
||||
err(s->c,n->loc,"type is private to its unit");
|
||||
return unknown(s->c);
|
||||
}
|
||||
n->sem_type=there;
|
||||
return there;
|
||||
}
|
||||
err(s->c,n->loc,"unknown name");
|
||||
return unknown(s->c);
|
||||
}
|
||||
if (!decl_is_public(sym->decl)) {
|
||||
err(s->c,n->loc,"name is private to its unit");
|
||||
return unknown(s->c);
|
||||
|
||||
@@ -106,6 +106,20 @@ FeIrGlobal *fe_ir_global(FeIrModule *m, const char *name, FeIrType type,
|
||||
return g;
|
||||
}
|
||||
|
||||
void fe_ir_global_ref(FeIrModule *m, FeIrGlobal *g, unsigned long at,
|
||||
const char *symbol)
|
||||
{
|
||||
FeIrReloc *grown;
|
||||
if (!g) return;
|
||||
grown = (FeIrReloc *)ir_alloc(m, (g->reloc_count + 1) * sizeof(FeIrReloc));
|
||||
if (!grown) return;
|
||||
if (g->relocs) memcpy(grown, g->relocs, g->reloc_count * sizeof(FeIrReloc));
|
||||
grown[g->reloc_count].at = at;
|
||||
grown[g->reloc_count].symbol = symbol;
|
||||
g->relocs = grown;
|
||||
++g->reloc_count;
|
||||
}
|
||||
|
||||
const char *fe_ir_string(FeIrModule *m, const char *bytes, unsigned long length)
|
||||
{
|
||||
FeIrGlobal *g;
|
||||
|
||||
@@ -121,12 +121,22 @@ struct FeIrFunc {
|
||||
struct FeIrFunc *next;
|
||||
};
|
||||
|
||||
/* A place inside a global's bytes that holds the address of something else.
|
||||
The value is not known until the linker places it, so the bytes carry a hole
|
||||
and this says what fills it. */
|
||||
typedef struct FeIrReloc {
|
||||
unsigned long at;
|
||||
const char *symbol;
|
||||
} FeIrReloc;
|
||||
|
||||
typedef struct FeIrGlobal {
|
||||
const char *name;
|
||||
FeIrType type;
|
||||
unsigned long size;
|
||||
unsigned align;
|
||||
const unsigned char *init; /* size bytes, or null for zero */
|
||||
FeIrReloc *relocs;
|
||||
unsigned reloc_count;
|
||||
struct FeIrGlobal *next;
|
||||
} FeIrGlobal;
|
||||
|
||||
@@ -155,6 +165,9 @@ FeIrBlock *fe_ir_block(FeIrModule *m, FeIrFunc *f);
|
||||
FeIrGlobal *fe_ir_global(FeIrModule *m, const char *name, FeIrType type,
|
||||
unsigned long size, unsigned align,
|
||||
const unsigned char *init);
|
||||
/* Say that `at` bytes into `g` there is the address of `symbol`. */
|
||||
void fe_ir_global_ref(FeIrModule *m, FeIrGlobal *g, unsigned long at,
|
||||
const char *symbol);
|
||||
/* A string literal's bytes, interned so the same text is stored once. */
|
||||
const char *fe_ir_string(FeIrModule *m, const char *bytes,
|
||||
unsigned long length);
|
||||
|
||||
@@ -504,6 +504,41 @@ void lower_global(Lower *L, FeNode *n)
|
||||
unsigned char *init = 0;
|
||||
unsigned long size = ir_size(t);
|
||||
if (!n->cname) return;
|
||||
/* A text constant is a pointer and a length. The pointer is not a number
|
||||
anyone knows yet, so the bytes carry a hole and the linker fills it. */
|
||||
if (n->b && n->b->kind == FE_N_LITERAL && n->b->text &&
|
||||
n->b->text[0] == '"' && t &&
|
||||
(t->kind == FE_TYPE_SLICE || t->kind == FE_TYPE_STR)) {
|
||||
char text[1024];
|
||||
unsigned long raw = strlen(n->b->text);
|
||||
unsigned long len = 0;
|
||||
unsigned long i;
|
||||
const char *label;
|
||||
FeIrGlobal *g;
|
||||
if (raw >= 2) raw -= 2;
|
||||
for (i = 0; i < raw && len + 1 < sizeof text; ++i) {
|
||||
char ch = n->b->text[1 + i];
|
||||
if (ch == 92 && i + 1 < raw) {
|
||||
++i;
|
||||
switch (n->b->text[1 + i]) {
|
||||
case 'n': ch = 10; break;
|
||||
case 't': ch = 9; break;
|
||||
case 'r': ch = 13; break;
|
||||
case '0': ch = 0; break;
|
||||
default: ch = n->b->text[1 + i]; break;
|
||||
}
|
||||
}
|
||||
text[len++] = ch;
|
||||
}
|
||||
label = fe_ir_string(L->m, text, len);
|
||||
init = (unsigned char *)fe_arena_alloc(&L->m->arena, 8);
|
||||
if (!init || !label) return;
|
||||
for (i = 0; i < 8; ++i) init[i] = 0;
|
||||
for (i = 0; i < 4; ++i) init[4 + i] = (unsigned char)((len >> (i * 8)) & 0xFF);
|
||||
g = fe_ir_global(L->m, n->cname, FE_IR_MEM, 8, 4, init);
|
||||
fe_ir_global_ref(L->m, g, (unsigned long)SLICE_PTR_OFFSET, label);
|
||||
return;
|
||||
}
|
||||
if (n->b && n->b->kind == FE_N_LITERAL && size && size <= 8) {
|
||||
long v = literal_value(n->b);
|
||||
unsigned long i;
|
||||
|
||||
+23
-4
@@ -634,10 +634,29 @@ void fe_x86_emit(const FeIrModule *m, FILE *out)
|
||||
fprintf(out, " db %lu dup(0)\n", g->size ? g->size : 1UL);
|
||||
continue;
|
||||
}
|
||||
for (i = 0; i < g->size; ++i) {
|
||||
if (i % 16 == 0) fputs(" db ", out);
|
||||
fprintf(out, "%u%s", g->init[i],
|
||||
(i + 1 == g->size || (i % 16) == 15) ? "\n" : ",");
|
||||
for (i = 0; i < g->size; ) {
|
||||
unsigned r;
|
||||
unsigned long j;
|
||||
for (r = 0; r < g->reloc_count; ++r)
|
||||
if (g->relocs[r].at == i) break;
|
||||
if (r < g->reloc_count) {
|
||||
/* A hole the linker fills with an address. */
|
||||
fprintf(out, " dd offset %s\n",
|
||||
g->relocs[r].symbol);
|
||||
i += 4;
|
||||
continue;
|
||||
}
|
||||
fputs(" db ", out);
|
||||
j = 0;
|
||||
while (i < g->size && j < 16) {
|
||||
unsigned q;
|
||||
for (q = 0; q < g->reloc_count; ++q)
|
||||
if (g->relocs[q].at == i) break;
|
||||
if (q < g->reloc_count) break;
|
||||
fprintf(out, "%s%u", j ? "," : "", g->init[i]);
|
||||
++i; ++j;
|
||||
}
|
||||
fputc('\n', out);
|
||||
}
|
||||
if (!g->size) fputs(" db 0\n", out);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user