1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168
|
# -*- tcl -*-
#
# Copyright (c) 2009 by Andreas Kupries <andreas_kupries@users.sourceforge.net>
# # ## ### ##### ######## ############# #####################
## Package description
## Implementation of the PackRat Machine (PARAM), a virtual machine on
## top of which parsers for Parsing Expression Grammars (PEGs) can be
## realized. This implementation is written in C, for parsers written in
## Tcl. As such the parsers themselves are tied to Tcl for control flow.
#
## RD stands for Recursive Descent.
# # ## ### ##### ######## ############# #####################
## Requisites
package require Tcl 8.4
package require critcl
# @sak notprovided pt_rde_critcl
package provide pt_rde_critcl 1.3.1
# # ## ### ##### ######## ############# #####################
## Implementation
namespace eval ::pt {
# # ## ### ##### ######## ############# #####################
## Supporting code for the main command.
catch {
#critcl::cheaders -g
#critcl::debug memory symbols
}
critcl::cheaders rde_critcl/*.h
critcl::csources rde_critcl/*.c
critcl::ccode {
/* -*- c -*- */
#include <util.h> /* Allocation macros */
#include <p.h> /* Public state API */
#include <ms.h> /* Instance command */
/* .................................................. */
/* Global PARAM management, per interp
*/
typedef struct PARAMg {
long int counter;
char buf [50];
} PARAMg;
static void
PARAMgRelease (ClientData cd, Tcl_Interp* interp)
{
ckfree((char*) cd);
}
static CONST char*
PARAMnewName (Tcl_Interp* interp)
{
#define KEY "tcllib/pt::rde/critcl"
Tcl_InterpDeleteProc* proc = PARAMgRelease;
PARAMg* paramg;
paramg = Tcl_GetAssocData (interp, KEY, &proc);
if (paramg == NULL) {
paramg = (PARAMg*) ckalloc (sizeof (PARAMg));
paramg->counter = 0;
Tcl_SetAssocData (interp, KEY, proc,
(ClientData) paramg);
}
paramg->counter ++;
sprintf (paramg->buf, "rde%d", paramg->counter);
return paramg->buf;
#undef KEY
}
static void
PARAMdeleteCmd (ClientData clientData)
{
/* Release the whole PARAM. */
param_delete ((RDE_STATE) clientData);
}
}
# # ## ### ##### ######## ############# #####################
## Main command, PARAM creation.
critcl::ccommand rde_critcl {dummy interp objc objv} {
/* Syntax: No arguments beyond the name
*/
CONST char* name;
RDE_STATE param;
Tcl_Obj* fqn;
Tcl_CmdInfo ci;
Tcl_Command c;
#define USAGE "?name?"
if ((objc != 2) && (objc != 1)) {
Tcl_WrongNumArgs (interp, 1, objv, USAGE);
return TCL_ERROR;
}
if (objc < 2) {
name = PARAMnewName (interp);
} else {
name = Tcl_GetString (objv [1]);
}
if (!Tcl_StringMatch (name, "::*")) {
/* Relative name. Prefix with current namespace */
Tcl_Eval (interp, "namespace current");
fqn = Tcl_GetObjResult (interp);
fqn = Tcl_DuplicateObj (fqn);
Tcl_IncrRefCount (fqn);
if (!Tcl_StringMatch (Tcl_GetString (fqn), "::")) {
Tcl_AppendToObj (fqn, "::", -1);
}
Tcl_AppendToObj (fqn, name, -1);
} else {
fqn = Tcl_NewStringObj (name, -1);
Tcl_IncrRefCount (fqn);
}
Tcl_ResetResult (interp);
if (Tcl_GetCommandInfo (interp,
Tcl_GetString (fqn),
&ci)) {
Tcl_Obj* err;
err = Tcl_NewObj ();
Tcl_AppendToObj (err, "command \"", -1);
Tcl_AppendObjToObj (err, fqn);
Tcl_AppendToObj (err, "\" already exists", -1);
Tcl_DecrRefCount (fqn);
Tcl_SetObjResult (interp, err);
return TCL_ERROR;
}
param = param_new ();
c = Tcl_CreateObjCommand (interp, Tcl_GetString (fqn),
paramms_objcmd, (ClientData) param,
PARAMdeleteCmd);
param_setcmd (param, c);
Tcl_SetObjResult (interp, fqn);
Tcl_DecrRefCount (fqn);
return TCL_OK;
}
}
# # ## ### ##### ######## ############# #####################
## Ready
package provide pt::rde::critcl 1
return
|