Browse Source

Reimplement command evaluation

master
Jake Wakeling 1 year ago
parent
commit
de472f3d6e
  1. 2
      src/alias.c
  2. 2
      src/alias.h
  3. 26
      src/bltn.c
  4. 2
      src/bltn.h
  5. 8
      src/bltns/cd.c
  6. 87
      src/bltns/eval.c
  7. 10
      src/bltns/pwd.c
  8. 4
      src/bltns/set.c
  9. 18
      src/esh.h
  10. 71
      src/eval.c
  11. 16
      src/exec.c
  12. 34
      src/main.c
  13. 24
      src/parse.c

2
src/alias.c

@ -60,7 +60,7 @@ void pushalias(akas_t *akas, aka_t aka) {
return;
}
int bltn_alias(char *argv[]) {
int bltn_alias(int ac, char *argv[]) {
if (!argv[1]) { for (aka_t *a = akas.dat; a->str; ++a) {
printf("alias %s='%s'\n", a->str, a->com);
} return 0; }

2
src/alias.h

@ -43,6 +43,6 @@ extern void initalias(void);
extern void freealias(void);
extern void pushalias(akas_t *akas, aka_t aka);
extern int bltn_alias(char *argv[]);
extern int bltn_alias(int ac, char *argv[]);
#endif // ESH_ALIAS_H_0BXOPDLM

26
src/bltn.c

@ -39,17 +39,17 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE SOFTWARE.
#include <stdio.h>
static int bltn_eval(char *av[]) { warn("eval: Unimplemented"); return -1; }
static int bltn_exit(char *av[]) { (void)(av); _loop = 0; return 0; }
static int bltn_false(char *av[]) { (void)(av); return 1; }
static int bltn_help(char *av[]);
static int bltn_true(char *av[]) { (void)(av); return 0; }
static int bltn_exit(int ac, char *av[]) { _loop = 0; return 0; }
static int bltn_false(int ac, char *av[]) { return 1; }
static int bltn_help(int ac, char *av[]);
static int bltn_true(int ac, char *av[]) { return 0; }
extern int bltn_cd(char *av[]);
extern int bltn_pwd(char *av[]);
extern int bltn_set(char *av[]);
extern int bltn_cd(int ac, char *av[]);
extern int bltn_eval(int ac, char *av[]);
extern int bltn_pwd(int ac, char *av[]);
extern int bltn_set(int ac, char *av[]);
static int getret(char *av[]) { printf("%i\n", _ret); return 0; }
static int getret(int ac, char *av[]) { printf("%i\n", _ret); return 0; }
struct bltn bltns[] = {
{"alias", &bltn_alias},
@ -65,6 +65,10 @@ struct bltn bltns[] = {
{NULL, NULL}
};
static int bltn_help(char *av[]) { (void)(av);
puts("ESH, version " PROJECT_VERSION); return 0;
static int bltn_help(int ac, char *av[]) {
puts("ESH, version " PROJECT_VERSION);
puts("Copyright (C) 2020, Jakob Wakeling");
puts("All rights reserved.");
puts("OMKOV Permissive Licence (https://www.omkov.net/OLPE)");
return 0;
}

2
src/bltn.h

@ -33,7 +33,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE SOFTWARE.
#ifndef OMKOV_ESH_BLTN_H_XQ5D812A
#define OMKOV_ESH_BLTN_H_XQ5D812A
struct bltn { const char *s; int (*f)(char *[]); };
struct bltn { const char *s; int (*f)(int, char *[]); };
extern struct bltn bltns[];
#endif // OMKOV_ESH_BLTN_H_XQ5D812A

8
src/bltns/cd.c

@ -1,4 +1,4 @@
// cd.c, version 0.1.1
// cd.c
// cd builtin source file for ESH
// Copyright (C) 2020, Jakob Wakeling
// All rights reserved.
@ -39,8 +39,6 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE SOFTWARE.
#include <stdlib.h>
#include <string.h>
#define VERSION "0.1.1"
static struct lop lops[] = {
{ "help", ARG_NUL, 256 },
{ "version", ARG_NUL, 257 },
@ -52,7 +50,7 @@ static int mode = 0;
static void hlp(void);
static void ver(void);
int bltn_cd(char *av[]) {
int bltn_cd(int ac, char *av[]) {
struct opt opt = OPTGET_INIT; opt.str = "LP"; opt.lops = lops;
for (int o; (o = optget(&opt, av, 1)) != -1;) switch (o) {
case 'L': { mode = 0; break; }
@ -85,7 +83,7 @@ static void hlp(void) {
}
static void ver(void) {
puts("ESH cd, version " VERSION);
puts("ESH, version " PROJECT_VERSION);
puts("Copyright (C) 2020, Jakob Wakeling");
puts("All rights reserved.");
puts("OMKOV Permissive Licence (https://www.omkov.net/OLPE)");

87
src/bltns/eval.c

@ -0,0 +1,87 @@
// eval.c
// eval builtin source file for ESH
// Copyright (C) 2020, Jakob Wakeling
// All rights reserved.
/*
OMKOV Permissive Licence, version 1.0
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal with
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimers.
* Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimers in the documentation and/or
other materials provided with the distribution.
* Neither the names of the copyright holders, nor the names of its contributors
may be used to endorse or promote products derived from this Software without
specific prior written permission.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT
HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE SOFTWARE.
*/
#include "../esh.h"
#include "../util/util.h"
#include "../cll/optget.h"
#include <stdio.h>
#include <string.h>
static struct lop lops[] = {
{ "help", ARG_NUL, 256 },
{ "version", ARG_NUL, 257 },
{ NULL, 0, 0 }
};
static void hlp(void);
static void ver(void);
int bltn_eval(int ac, char *av[]) {
struct opt opt = OPTGET_INIT; opt.str = ""; opt.lops = lops;
for (int o; (o = optget(&opt, av, 1)) != -1;) switch (o) {
case 256: { hlp(); return 0; }
case 257: { ver(); return 0; }
default: { return 1; }
}
u8 *args, *dest; UINT size = 0;
for (UINT i = 0; i != ac - opt.ind; i += 1) {
size += (strlen(av[opt.ind + i]) + 1);
}
args = assert_calloc(size, sizeof (*args)); dest = args;
for (UINT i = 0; i != ac - opt.ind; i += 1) {
if (i != 0) { strncat((char *)dest, " ", 1); dest += 1; }
strcat((char *)dest, av[opt.ind + i]); dest += strlen(av[opt.ind + i]);
}
eval(args, size); return 0;
}
static void hlp(void) {
puts("eval - Execute arguments as a command\n");
puts("Usage: eval [argument...]\n");
puts("Options:");
puts(" --help Display help information");
puts(" --version Display version information");
}
static void ver(void) {
puts("ESH, version " PROJECT_VERSION);
puts("Copyright (C) 2020, Jakob Wakeling");
puts("All rights reserved.");
puts("OMKOV Permissive Licence (https://www.omkov.net/OLPE)");
}

10
src/bltns/pwd.c

@ -1,5 +1,5 @@
// pwd.c, version 1.0.1b
// OMKOV coreutils pwd adapted as an ESH builtin
// pwd.c
// pwd builtin source file for ESH
// Copyright (C) 2020, Jakob Wakeling
// All rights reserved.
@ -37,8 +37,6 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE SOFTWARE.
#include <stdio.h>
#include <stdlib.h>
#define VERSION "1.0.1b"
static struct lop lops[] = {
{ "help", ARG_NUL, 256 },
{ "version", ARG_NUL, 257 },
@ -50,7 +48,7 @@ static int mode = 0;
static void hlp(void);
static void ver(void);
int bltn_pwd(char *av[]) {
int bltn_pwd(int ac, char *av[]) {
struct opt opt = OPTGET_INIT; opt.str = "LP"; opt.lops = lops;
for (int o; (o = optget(&opt, av, 1)) != -1;) switch (o) {
case 'L': { mode = 0; break; }
@ -82,7 +80,7 @@ static void hlp(void) {
}
static void ver(void) {
puts("OMKOV coreutils pwd, version " VERSION);
puts("ESH, version " PROJECT_VERSION);
puts("Copyright (C) 2020, Jakob Wakeling");
puts("All rights reserved.");
puts("OMKOV Permissive Licence (https://www.omkov.net/OLPE)");

4
src/bltns/set.c

@ -46,12 +46,10 @@ static struct lop lops[] = {
{ NULL, 0, 0 }
};
static int mode = 0;
static void hlp(void);
static void ver(void);
int bltn_set(char *av[]) {
int bltn_set(int ac, char *av[]) {
struct opt opt = OPTGET_INIT; opt.str = ""; opt.lops = lops;
for (int o; (o = optget(&opt, av, 1)) != -1;) switch (o) {
case 256: { hlp(); return 0; }

18
src/esh.h

@ -43,11 +43,14 @@ typedef enum {
typedef enum { AK_NULL, AK_COMP, AK_COMM } ast_k;
typedef struct ast_ *ast;
typedef struct { tok_k k; u8 *s; } tok;
typedef struct { u8 *s; UINT sp, sl; tok t; } lex;
typedef struct { ast_k k; u8 *s; array c; } ast;
struct ast_ { ast_k k; u8 *s; array c; };
extern bool Lflag, Pflag;
extern int _loop, _ret;
extern u8 *tok_ks[];
@ -57,14 +60,17 @@ extern lex lex_init(u8 *src, UINT len);
extern tok lex_next(lex *l);
extern tok lex_peek(lex *l);
extern ast *ast_init(void);
extern void ast_free(ast *a);
extern ast ast_init(void);
extern void ast_free(ast a);
extern ast parse(lex *l);
extern ast *parse(lex *l);
extern int execute(ast a);
extern int execute(ast *a);
extern void eval(u8 *src, UINT len);
extern void eval_file(const u8 *file);
extern void lex_debug(lex *l);
extern void ast_debug(ast *a);
extern void ast_debug(ast a);
#endif // ESH_ESH_H_SAZDXXFN

71
src/eval.c

@ -0,0 +1,71 @@
// eval.c
// Evaluation source file for ESH
// Copyright (C) 2020, Jakob Wakeling
// All rights reserved.
/*
OMKOV Permissive Licence, version 1.0
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal with
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimers.
* Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimers in the documentation and/or
other materials provided with the distribution.
* Neither the names of the copyright holders, nor the names of its contributors
may be used to endorse or promote products derived from this Software without
specific prior written permission.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT
HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE SOFTWARE.
*/
#include "esh.h"
#include "util/util.h"
#include "cll/error.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* Evaluate a string. */
extern void eval(u8 *src, UINT len) {
lex l = lex_init(src, len);
if (Lflag) { lex_debug(&l); goto ret; }
ast a = parse(&l); if (!a) { goto ret; }
if (Pflag) { ast_debug(a); goto ret; }
_ret = WEXITSTATUS(execute(a));
ret:;
ast_free(a);
}
/* Evaluate a file. */
extern void eval_file(const u8 *file) {
FILE *fi; u8 *fb; size_t fl;
if (!(fi = fopen((char *)file, "r"))) {
warn("%s: %s", file, serr());
_ret = WEXITSTATUS(-1); return;
}
fseek(fi, 0, SEEK_END); fl = ftell(fi); rewind(fi);
fb = assert_malloc((fl + 1) * sizeof (*fb));
fread(fb, 1, fl, fi); fb[fl] = 0; fclose(fi);
eval(fb, fl); free(fb); return;
}

16
src/exec.c

@ -1,5 +1,5 @@
// exec.c
// Exec source file for ESH
// Execution source file for ESH
// Copyright (C) 2020, Jakob Wakeling
// All rights reserved.
@ -44,13 +44,13 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE SOFTWARE.
#include <stdlib.h>
#include <string.h>
static int execute_comp(ast *a);
static int execute_comm(ast *a);
static int execute_comp(ast a);
static int execute_comm(ast a);
static int launch(u8 *av[]);
/* Execute a program. */
int execute(ast *a) {
int execute(ast a) {
switch (a->k) {
case AK_COMP: { return execute_comp(a); }
case AK_COMM: { return execute_comm(a); }
@ -59,7 +59,7 @@ int execute(ast *a) {
}
/* Execute a compound statement. */
static int execute_comp(ast *a) {
static int execute_comp(ast a) {
register int ret = 0;
for (UINT i = 0; i != a->c->size; i += 1) {
@ -70,11 +70,13 @@ static int execute_comp(ast *a) {
}
/* Execute a command statement. */
static int execute_comm(ast *a) {
static int execute_comm(ast a) {
if (!a->s) { return _ret; } /* What does this achieve? */
for (struct bltn *b = bltns; b->s; b += 1) {
if (strcmp((char *)a->s, b->s) == 0) { return b->f((char **)a->c->data); }
if (strcmp((char *)a->s, b->s) == 0) {
return b->f(a->c->size - 1, (char **)a->c->data);
}
}
return launch((u8 **)a->c->data);

34
src/main.c

@ -45,13 +45,14 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE SOFTWARE.
#include <string.h>
static struct lop lops[] = {
{ "help", ARG_NUL, 256 },
{ "version", ARG_NUL, 257 },
{ "help", ARG_NUL, 256 },
{ "version", ARG_NUL, 257 },
{ "debug-lex", ARG_NUL, 258 },
{ "debug-parse", ARG_NUL, 259 },
{ NULL, 0, 0 }
};
static bool Lflag = false, Pflag = false;
bool Lflag = false, Pflag = false;
int _loop = 1, _ret;
static jmp_buf jmp;
@ -63,12 +64,12 @@ static void hlp(void);
static void ver(void);
int main(int ac, char *av[]) { (void)(ac); A0 = av[0];
struct opt opt = OPTGET_INIT; opt.str = "LP"; opt.lops = lops;
struct opt opt = OPTGET_INIT; opt.str = ""; opt.lops = lops;
for (int o; (o = optget(&opt, av, 1)) != -1;) switch (o) {
case 'L': { Lflag = true; } break;
case 'P': { Pflag = true; } break;
case 256: { hlp(); return 0; }
case 257: { ver(); return 0; }
case 258: { Lflag = true; } break;
case 259: { Pflag = true; } break;
default: { return 1; }
}
@ -81,16 +82,7 @@ int main(int ac, char *av[]) { (void)(ac); A0 = av[0];
u8 *line = lineread();
if (!line) { if (errno) { warn("%s, %d", serr(), errno); } break; }
lex l = lex_init(line, strlen((char *)line));
if (Lflag) { lex_debug(&l); goto loop; }
ast *a = parse(&l); if (!a) { goto loop; }
if (Pflag) { ast_debug(a); goto loop; }
_ret = WEXITSTATUS(execute(a));
loop:;
ast_free(a); free(line);
eval(line, strlen((char *)line)); free(line);
} while (_loop);
linefree(); return warned;
@ -102,12 +94,10 @@ static void reset(int signo) { (void)(signo);
static void hlp(void) {
puts("ESH - Executive Shell\n");
puts("Usage: esh [-LP]\n");
puts("Usage: esh\n");
puts("Options:");
puts(" -L Print lexer debug output");
puts(" -P Print parser debug output");
puts(" --help Display help information");
puts(" --version Display version information");
puts(" --help Display help information");
puts(" --version Display version information");
return;
}

24
src/parse.c

@ -41,29 +41,29 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE SOFTWARE.
u8 *ast_ks[] = { (u8 *)"NULL", (u8 *)"COMP", (u8 *)"COMM" };
static ast *parse_comp(lex *l);
static ast *parse_comm(lex *l);
static ast parse_comp(lex *l);
static ast parse_comm(lex *l);
/* Initialise an AST node. */
ast *ast_init(void) {
return assert_calloc(1, sizeof (ast));
ast ast_init(void) {
return assert_calloc(1, sizeof (struct ast_));
}
/* Uninitialise an AST node. */
void ast_free(ast *a) {
void ast_free(ast a) {
if (a) { array_free(a->c); free(a); }
}
/* Parse a program. */
ast *parse(lex *l) {
ast parse(lex *l) {
if (lex_peek(l).k == LK_EOF) { return NULL; }
return parse_comp(l);
}
/* Parse a comound statement. */
static ast *parse_comp(lex *l) {
ast *a = ast_init(); a->k = AK_COMP;
static ast parse_comp(lex *l) {
ast a = ast_init(); a->k = AK_COMP;
a->c = array_init((void (*)(ptr))&ast_free);
/* Push each command onto the array */
@ -73,8 +73,8 @@ static ast *parse_comp(lex *l) {
}
/* Parse a command statement. */
static ast *parse_comm(lex *l) {
ast *a = ast_init(); a->k = AK_COMM;
static ast parse_comm(lex *l) {
ast a = ast_init(); a->k = AK_COMM;
a->c = array_init(NULL);
/* Push each command argument onto the array. */
@ -85,7 +85,7 @@ static ast *parse_comm(lex *l) {
}
/* Print parser debug output with an indent. */
static void ast_debug_indent(ast *a, UINT i) {
static void ast_debug_indent(ast a, UINT i) {
for (UINT j = 0; j != i; ++j) { printf("\t"); }
printf("%s: %s", ast_ks[a->k], a->s);
@ -108,4 +108,4 @@ static void ast_debug_indent(ast *a, UINT i) {
}
/* Print parser debug output. */
void ast_debug(ast *a) { ast_debug_indent(a, 0); }
void ast_debug(ast a) { ast_debug_indent(a, 0); }

Loading…
Cancel
Save