toolchain: replace ifc interface compiler with xpcg
xpcg is used to generate xpc interfaces
This commit is contained in:
346
toolchain/xpcg/parse.c
Normal file
346
toolchain/xpcg/parse.c
Normal file
@@ -0,0 +1,346 @@
|
||||
#include "ctx.h"
|
||||
#include "interface.h"
|
||||
#include "lex.h"
|
||||
#include "msg.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#define report_error(...) fprintf(stderr, __VA_ARGS__)
|
||||
|
||||
static bool peek_keyword(struct lex *lex, enum token_keyword kw)
|
||||
{
|
||||
struct token *tok = lex_peek(lex);
|
||||
return (tok && tok->tok_type == TOK_KEYWORD && tok->tok_kw == kw);
|
||||
}
|
||||
|
||||
static bool parse_keyword(struct lex *lex, enum token_keyword kw)
|
||||
{
|
||||
struct token *tok = lex_peek(lex);
|
||||
if (!tok || tok->tok_type != TOK_KEYWORD || tok->tok_kw != kw) {
|
||||
return false;
|
||||
}
|
||||
|
||||
lex_advance(lex);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool parse_symbol(struct lex *lex, enum token_symbol sym)
|
||||
{
|
||||
struct token *tok = lex_peek(lex);
|
||||
if (!tok || tok->tok_type != TOK_SYMBOL || tok->tok_sym != sym) {
|
||||
return false;
|
||||
}
|
||||
|
||||
lex_advance(lex);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool parse_word(struct lex *lex, char **out)
|
||||
{
|
||||
struct token *tok = lex_peek(lex);
|
||||
if (!tok || tok->tok_type != TOK_WORD) {
|
||||
return false;
|
||||
}
|
||||
|
||||
*out = tok->tok_str;
|
||||
tok->tok_str = NULL;
|
||||
lex_advance(lex);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool parse_int(struct lex *lex, long long *out)
|
||||
{
|
||||
struct token *tok = lex_peek(lex);
|
||||
if (!tok || tok->tok_type != TOK_INT) {
|
||||
return false;
|
||||
}
|
||||
|
||||
*out = tok->tok_int;
|
||||
lex_advance(lex);
|
||||
return true;
|
||||
}
|
||||
|
||||
struct msg_definition *parse_msg_definition(struct ctx *ctx, struct lex *lex)
|
||||
{
|
||||
struct msg_definition *msg = NULL;
|
||||
|
||||
if (!parse_keyword(lex, KW_FUNC)) {
|
||||
report_error("expected `func` keyword\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
char *msg_name = NULL;
|
||||
if (!parse_word(lex, &msg_name)) {
|
||||
report_error("expected function identifier\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
long long msg_id = 0;
|
||||
if (!parse_symbol(lex, SYM_LEFT_BRACKET)) {
|
||||
report_error("expected `[` after function identifier\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!parse_int(lex, &msg_id)) {
|
||||
report_error("expected function id number after `[`\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!parse_symbol(lex, SYM_RIGHT_BRACKET)) {
|
||||
report_error("expected `]` after function id number\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
msg = msg_definition_create(msg_name, msg_id);
|
||||
free(msg_name);
|
||||
|
||||
if (!parse_symbol(lex, SYM_LEFT_PAREN)) {
|
||||
report_error(
|
||||
"expected `(` after function id number specifier\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
size_t i = 0;
|
||||
bool ok = true;
|
||||
while (ok) {
|
||||
if (parse_symbol(lex, SYM_RIGHT_PAREN)) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (i > 0 && !parse_symbol(lex, SYM_COMMA)) {
|
||||
report_error(
|
||||
"expected `,` after function "
|
||||
"parameter\n");
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
|
||||
char *param_name;
|
||||
if (!parse_word(lex, ¶m_name)) {
|
||||
report_error("expected function parameter name\n");
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!parse_symbol(lex, SYM_COLON)) {
|
||||
report_error(
|
||||
"expected `:` after function parameter "
|
||||
"name\n");
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
|
||||
char *type_name;
|
||||
if (!parse_word(lex, &type_name)) {
|
||||
report_error("expected function parameter type\n");
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
|
||||
const struct type *type = ctx_get_type(ctx, type_name);
|
||||
if (!type) {
|
||||
report_error(
|
||||
"function parameter has unknown type "
|
||||
"'%s'\n",
|
||||
type_name);
|
||||
free(type_name);
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
|
||||
free(type_name);
|
||||
|
||||
bool duplicate = msg_definition_has_param(msg, param_name)
|
||||
|| msg_definition_has_result(msg, param_name);
|
||||
if (duplicate) {
|
||||
free(param_name);
|
||||
report_error(
|
||||
"function has multiple "
|
||||
"parameters/results with "
|
||||
"name '%s'\n",
|
||||
param_name);
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
|
||||
msg_definition_add_param(msg, type, param_name);
|
||||
free(param_name);
|
||||
i++;
|
||||
}
|
||||
|
||||
if (!ok) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!parse_symbol(lex, SYM_HYPHEN_RIGHT_ANGLE)) {
|
||||
report_error(
|
||||
"expected `->` after function parameter "
|
||||
"list\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!parse_symbol(lex, SYM_LEFT_PAREN)) {
|
||||
report_error("expected `(` for function results list\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
i = 0;
|
||||
while (ok) {
|
||||
if (parse_symbol(lex, SYM_RIGHT_PAREN)) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (i > 0 && !parse_symbol(lex, SYM_COMMA)) {
|
||||
report_error(
|
||||
"expected `,` or `)` after function "
|
||||
"result\n");
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
|
||||
char *result_name;
|
||||
if (!parse_word(lex, &result_name)) {
|
||||
report_error("expected function parameter name\n");
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!parse_symbol(lex, SYM_COLON)) {
|
||||
report_error(
|
||||
"expected `:` after function result "
|
||||
"name\n");
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
|
||||
char *type_name;
|
||||
if (!parse_word(lex, &type_name)) {
|
||||
report_error("expected function result type\n");
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
|
||||
const struct type *type = ctx_get_type(ctx, type_name);
|
||||
if (!type) {
|
||||
report_error(
|
||||
"function result has unknown type "
|
||||
"'%s'\n",
|
||||
type_name);
|
||||
free(type_name);
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
free(type_name);
|
||||
|
||||
bool duplicate = msg_definition_has_param(msg, result_name)
|
||||
|| msg_definition_has_result(msg, result_name);
|
||||
if (duplicate) {
|
||||
report_error(
|
||||
"function has multiple "
|
||||
"parameters/results with "
|
||||
"name '%s'\n",
|
||||
result_name);
|
||||
free(result_name);
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
|
||||
msg_definition_add_result(msg, type, result_name);
|
||||
free(result_name);
|
||||
i++;
|
||||
}
|
||||
|
||||
if (!parse_symbol(lex, SYM_SEMICOLON)) {
|
||||
report_error("expected `;` after function definition\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
return msg;
|
||||
|
||||
fail:
|
||||
if (msg) {
|
||||
msg_definition_destroy(msg);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct interface_definition *parse_interface_definition(
|
||||
struct ctx *ctx,
|
||||
struct lex *lex)
|
||||
{
|
||||
struct interface_definition *iface = NULL;
|
||||
|
||||
if (!parse_keyword(lex, KW_INTERFACE)) {
|
||||
report_error("expected `interface` keyword");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
char *if_name = NULL;
|
||||
if (!parse_word(lex, &if_name)) {
|
||||
report_error("expected interface name");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
long long if_id = 0;
|
||||
if (!parse_int(lex, &if_id)) {
|
||||
report_error("expected interface id number");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!parse_symbol(lex, SYM_SEMICOLON)) {
|
||||
report_error("expected `;` after interface definition");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
iface = interface_definition_create(if_name, if_id);
|
||||
free(if_name);
|
||||
if (!iface) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
bool ok = true;
|
||||
|
||||
while (ok) {
|
||||
if (!lex_peek(lex) && lex_get_status(lex) == ERR_EOF) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (peek_keyword(lex, KW_FUNC)) {
|
||||
struct msg_definition *msg
|
||||
= parse_msg_definition(ctx, lex);
|
||||
if (!msg) {
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (interface_definition_has_msg(
|
||||
iface,
|
||||
msg->msg_name)) {
|
||||
msg_definition_destroy(msg);
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
|
||||
interface_definition_add_msg(iface, msg);
|
||||
continue;
|
||||
}
|
||||
|
||||
report_error("expected eof or function definition\n");
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!ok) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
return iface;
|
||||
|
||||
fail:
|
||||
if (iface) {
|
||||
interface_definition_destroy(iface);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
Reference in New Issue
Block a user