Makefile v0.4 driver support added
authorken <ken@mihrtec.com>
Fri, 16 Dec 2016 07:40:56 +0000 (23:40 -0800)
committerken <ken@mihrtec.com>
Fri, 16 Dec 2016 07:40:56 +0000 (23:40 -0800)
Makefile
src/apc.c [new file with mode: 0644]
src/testapc.c [new file with mode: 0644]

index d37a162..7968b66 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -21,10 +21,12 @@ CFLAGS ?= -Wall
 CCMD    = $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $<
 
 # Linker
-LD      ?= ld
-LDFLAGS ?= 
-LDLIBS  ?= -lunistring
-LDCMD    = $(LD) $(LDFLAGS) $(LDLIBS) -o $@ $^
+LD        ?= ld
+LDFLAGS   ?= 
+LDLIBS    ?= -lunistring
+apcLIBS   ?= 
+apc-dLIBS ?= 
+LDCMD      = $(LD) $(LDFLAGS) $(LDLIBS) $($1LIBS) -o $@ $^
 
 # APC is built from Ragel, Bison and C source code only.
 ySRC  := $(shell find ./src -type f -name '*.y')
@@ -35,17 +37,19 @@ cSRC  := $(shell find ./src -type f -name '*.c')
 hGEN  := $(ySRC:%.y=%.tab.h)
 cGEN  := $(strip $(ySRC:%.y=%.tab.c) $(rlSRC:%.rl=%.c))
 
-# Functions
-cGENDEP = $(if $(wildcard $1),$(subst src/,,$(filter-out $1 \ %:,$(shell $(CC) -MM -MG $1))),$(info <$1>))
-ldFLAGS = $(strip $(LDFLAGS) $(LDLIBS) $(VA_ARGS))
+# Deps generation function
+cGENDEP = $(if $(wildcard $1),$(subst $(dir $1),,$(filter-out $1 \ %:,$(shell $(CC) -MM -MG $1))),$(info <$1>))
 
-# Rules
-apcSRC   := $(patsubst %.c,%.o,$(cSRC) $(cGEN))
-apc-dSRC := $(patsubst %.o,%-d.o,$(apcSRC))
+# Driver sources
+DRIVERS  := apc testapc
+$(foreach drv,$(DRIVERS),\
+$(eval $(drv)SRC   := $(patsubst %.c,%.o,$(filter-out $(patsubst %,src/%.c,$(filter-out $(drv),$(DRIVERS))),$(cSRC) $(cGEN))))\
+$(eval $(drv)-dSRC := $(patsubst %.o,%-d.o,$($(drv)SRC))))
 
+# Rules
 .SECONDEXPANSION:
-apc-d apc: $$($$@SRC) | $(hGEN)
-       $(strip $(LDCMD))
+$(DRIVERS:%=%-d) $(DRIVERS): $$($$@SRC) | $(hGEN)
+       $(strip $(call LDCMD,$@))
 
 %-d.o: CFLAGS+= -Og -ggdb
 %.o %-d.o: %.c $$(call cGENDEP,$$(dir $$@)%.c)
@@ -59,4 +63,4 @@ apc-d apc: $$($$@SRC) | $(hGEN)
        $(strip $(RLCMD))
 
 clean: $(wildcard $(cGEN) $(hGEN) $(apcSRC) $(apc-dSRC))
-       rm $^
+       $(if $^,rm $^)
diff --git a/src/apc.c b/src/apc.c
new file mode 100644 (file)
index 0000000..2307ccc
--- /dev/null
+++ b/src/apc.c
@@ -0,0 +1,84 @@
+/*!@file
+  \brief   APC main driver
+  \details The driver assumes the existence of a bison-generated parser,
+           referenced by the external function 'yyparse'.
+           It also assumes the existence of a lexer which must be initialized
+           before parsing, referenced by the external function 'lexer_init'
+           which assumes standard error handling.
+           All input arguments are made available through the exposed (that is,
+           non-static) array of character pointers 'cargs', which point
+           to the non-duplicated strings in 'argv' directly from the system.
+  \author  Jordan Lavatai
+  \date    Aug 2016
+  ----------------------------------------------------------------------------*/
+/* Standard */
+#include <stdio.h>  //print
+#include <errno.h>  //errors
+#include <string.h> //strndupa
+/* Posix */
+#include <stdlib.h> //exit
+#include <unistd.h> //getopt
+/* Internal */
+#include <apc/parser.tab.h> //bison
+
+const char* cargs['Z'] = {0};
+
+int main(int, char*[]);
+
+extern //bison
+int yyparse(void);
+extern //lexer.c
+int  lexer_init(void);
+
+extern //apc/parser.tab.c
+YYSTYPE yylval;
+extern //lexer.c
+int  lexer(void);
+
+/* Main entry from terminal
+   parses the command line and kicks off recursive scanning
+*/
+int main
+( int   argc,
+  char* argv[]
+)
+#define $($)#$ //stringifier
+#define MAXSTR 255
+#define MAXERR "-%c allows at most " $(MAXSTR) " input characters\n", opt
+#define OPTS  "d:o:h-"
+#define USAGE "Usage %s [-d dir_root][-o output_file][-h]\n", argv[0]
+#define USAGE_LONG                                     \
+  "\tOptions:\n"                                       \
+  "\t\t-d\tRoot directory to parse from \t[./]\n"      \
+  "\t\t-o\tOutput filename \t\t[a.asspak]\n"           \
+  "\t\t-h\tPrint this help\n"
+#define DONE   -1
+{ int   opt;
+
+ getopt:
+  switch (opt = getopt(argc, argv, OPTS))
+  { case DONE:
+      break;
+    case 'd' :
+    case 'o' :
+      if (strnlen(optarg, MAXSTR) != MAXSTR)
+        { cargs[opt] = optarg;
+          goto getopt;
+        }
+      fprintf(stderr, MAXERR);
+    default :
+      fprintf(stderr, USAGE);
+      exit(EXIT_FAILURE);
+    case 'h' :
+      printf(USAGE);
+      printf(USAGE_LONG);
+      exit(EXIT_SUCCESS);
+  }
+  if (lexer_init())
+    { perror("lexer");
+      exit(EXIT_FAILURE);
+    }
+  yyparse();
+  exit(EXIT_SUCCESS);
+}
+
diff --git a/src/testapc.c b/src/testapc.c
new file mode 100644 (file)
index 0000000..77b825e
--- /dev/null
@@ -0,0 +1,146 @@
+/*!@file
+  \brief   APC test driver
+  \details This driver does what APC does, but in staggered stages with
+           additional debugging information
+  \author  Jordan Lavatai
+  \date    Aug 2016
+  ----------------------------------------------------------------------------*/
+/* Standard */
+#include <stdio.h>  //print
+#include <errno.h>  //errors
+#include <string.h> //strnlen
+#include <setjmp.h> //non-local jumps
+/* Posix */
+#include <stdlib.h> //exit
+#include <unistd.h> //getopt
+/* Internal */
+#include <apc/parser.tab.h> //bison
+#include <apc/ir.h>         //ir
+
+/* Import apc.c but redefine its primary symbols for jumping */
+#define main apc_main
+#define yyparse testapc_yyparse
+#include <bin/tools/apc.c>
+#undef yyparse
+#undef main
+
+int main(int, char*[]);
+int testapc_yyparse(void);
+int test_yyparse(void);
+
+extern //bison
+int  yyparse(void);
+extern //lexer.c
+int  lexer_init(void);
+extern //scanner.c
+int  scanner_init(void);
+extern //apc.c
+const char* cargs['Z'];
+
+extern //apc/parser.tab.c
+YYSTYPE yylval;
+extern //lexer.c
+int  lexer(void);
+
+static
+jmp_buf testapc_jump;
+
+/* Ansi Term Colors */
+#define RED     "\x1b[31m"
+#define GREEN   "\x1b[32m"
+#define YELLOW  "\x1b[33m"
+#define BLUE    "\x1b[34m"
+#define MAGENTA "\x1b[35m"
+#define CYAN    "\x1b[36m"
+#define CLRC    "\x1b[0m" //clear current color
+
+/* Main entry from terminal
+   parses debugging options for testing apc, and calls apc_main
+*/
+int main
+( int   argc,
+  char* argv[]
+)
+{ setjmp(testapc_jump);
+  apc_main(argc, argv);
+  printf(GREEN "PASS" CLRC "\n");
+  exit(EXIT_SUCCESS);
+}
+
+#define MAX_TOK 1024
+char tok_lval[MAX_TOK];
+
+/* yyparse intercept 
+   tests yyparse internally, then resets the scanner and runs bison's 'yyparse'
+   implementation after validating it with 'test_yyparse'.
+*/
+int testapc_yyparse
+#ifndef YYABORT
+#define YYABORT 1
+#endif
+()
+{ static char bPassedTest = 'f';
+  if (bPassedTest == 'f')
+    { if (test_yyparse())
+       { printf("Parse test aborted\n");
+         return YYABORT;
+       }
+      bPassedTest = 't';
+      longjmp(testapc_jump,0);
+    }
+  return yyparse();
+}
+
+/* test_yyparse
+   runs 'lexer' 'PASSES' times, or until finished
+*/
+int test_yyparse
+#define PASSES 1000
+()
+{ int i, tok;
+  static char* tok_string;
+  static char  tok_pattern[] = "[" RED " %9s " CLRC "][" CYAN " %-12i " CLRC "]";
+  for (i = 0; i < PASSES; i++)
+    { switch (tok = lexer())
+      #define TOFFS 9
+      #define LOFFS 27
+      #define $($)#$
+      #define TOK_CASE(T,C)                    \
+       case T:                                 \
+         tok_string = $(T);                    \
+         tok_pattern[LOFFS] = C;               \
+         break
+       { TOK_CASE(STR,'s');
+         TOK_CASE(NAME,'s');
+         TOK_CASE(REF,'x');
+         TOK_CASE(FPTR,'x');
+         TOK_CASE(NUM,'i');
+         TOK_CASE(SS,'i');
+         TOK_CASE(SSD,'i');
+         TOK_CASE(CLOPEN,'i');
+         TOK_CASE(CLCLOSE,'i');
+         default:
+           tok_string = 0;
+           tok_pattern[LOFFS] = 'i';
+           break;
+          case 0:
+           goto done;
+       }
+      if (tok_string == NULL)
+       { tok_pattern[TOFFS] = 'i';
+         printf(tok_pattern, tok, yylval.val);
+       }
+      else
+       { tok_pattern[TOFFS] = 's';
+         printf(tok_pattern, tok_string, yylval.val);
+       }
+      if (i % 4 == 0 || yylval.val == 0)
+       printf(";\n");
+    }
+ done:
+  printf(";\n" GREEN "Done" CLRC ".\n");
+  return 0;
+ error:
+  printf(";\n" RED "FAILED" CLRC ".\n");
+  return -1;
+}