From 103c4d93af7e5e84f0406f1ea25ee5f0e7ffd723 Mon Sep 17 00:00:00 2001 From: picomeg <megordon5@gmail.com> Date: Fri, 14 Feb 2020 08:04:02 +0000 Subject: [PATCH] add several combinators that are more recent than the old JNI this update started from. --- src/bindings/jni/Example.java | 14 ++ .../com/upstandinghackers/hammer/Hammer.java | 9 + .../jni/com_upstandinghackers_hammer_Hammer.c | 185 +++++++++++++++++- 3 files changed, 207 insertions(+), 1 deletion(-) diff --git a/src/bindings/jni/Example.java b/src/bindings/jni/Example.java index 4e6d7682..52f89e27 100644 --- a/src/bindings/jni/Example.java +++ b/src/bindings/jni/Example.java @@ -84,6 +84,20 @@ public static void main(String args[]) Parser i3parsers[] = {Hammer.ch((byte)'i'), Hammer.uInt8(), Hammer.int8()}; handle(Hammer.parse(Hammer.sequence(Hammer.ch((byte)'i'), Hammer.uInt8(), Hammer.int8()), i3, i3.length)); + out("permutation"); + byte ch3[] = {(byte) 'a', (byte) 'b', (byte) 'c'}; + handle(Hammer.parse(Hammer.permutation(Hammer.ch((byte)'a'), Hammer.ch((byte)'b'), Hammer.ch((byte)'c')), ch3, ch3.length)); + handle(Hammer.parse(Hammer.permutation(Hammer.ch((byte)'b'), Hammer.ch((byte)'a'), Hammer.ch((byte)'c')), ch3, ch3.length)); + + out("skip"); + byte ch6[] = {(byte) 'a', (byte) 'b', (byte) 'c', (byte) 'd', (byte) 'e', (byte) 'f'}; + handle(Hammer.parse(Hammer.sequence(Hammer.ch((byte)'a'), Hammer.skip((int)32), Hammer.ch((byte)'f')), ch6, ch6.length)); + + out("seek"); + final int SEEK_SET = 0; /* Seek from beginning of file. */ + //final int SEEK_CUR = 1; /* Seek from current position. */ + //final int SEEK_END = 2; /* Seek from end of file. */ + handle(Hammer.parse(Hammer.sequence(Hammer.ch((byte)'a'), Hammer.seek((int)40, (int)SEEK_SET), Hammer.ch((byte)'f')), ch6, ch6.length)); } diff --git a/src/bindings/jni/com/upstandinghackers/hammer/Hammer.java b/src/bindings/jni/com/upstandinghackers/hammer/Hammer.java index 3e06a91e..66ec1b5f 100644 --- a/src/bindings/jni/com/upstandinghackers/hammer/Hammer.java +++ b/src/bindings/jni/com/upstandinghackers/hammer/Hammer.java @@ -53,10 +53,12 @@ public class Hammer public static native Parser middle(Parser p, Parser x, Parser q); // public static native Parser action(Parser p, Action a); public static native Parser in(byte[] charset, int length); + public static native Parser notIn(byte[] charset, int length); public static native Parser endP(); public static native Parser nothingP(); public static native Parser sequence(Parser... parsers); public static native Parser choice(Parser... parsers); + public static native Parser permutation(Parser... parsers); public static native Parser butNot(Parser p1, Parser p2); public static native Parser difference(Parser p1, Parser p2); public static native Parser xor(Parser p1, Parser p2); @@ -73,4 +75,11 @@ public class Hammer public static native Parser and(Parser p); public static native Parser not(Parser p); public static native Parser indirect(); +// public static native Parser bindIndirect(Parser indirect, Parser inner); + public static native Parser withEndianess(byte endianess, Parser p); +// public static native Parser bind(Parser p, HContinuation k, void *env); //would need to work out mappings + public static native Parser skip(int n); + public static native Parser seek(int n, int whence); //TODO double check mapping for int whence + public static native Parser tell(); + } diff --git a/src/bindings/jni/com_upstandinghackers_hammer_Hammer.c b/src/bindings/jni/com_upstandinghackers_hammer_Hammer.c index f83414bc..b42a0dfa 100644 --- a/src/bindings/jni/com_upstandinghackers_hammer_Hammer.c +++ b/src/bindings/jni/com_upstandinghackers_hammer_Hammer.c @@ -149,6 +149,13 @@ JNIEXPORT jobject JNICALL Java_com_upstandinghackers_hammer_Hammer_middle RETURNWRAP(env, h_middle(UNWRAP(env, p), UNWRAP(env, x), UNWRAP(env, q))); } +/** + * Given another parser, p, and a function f, returns a parser that + * applies p, then applies f to everything in the AST of p's result. + * + * Result token type: any + */ +//HAMMER_FN_DECL(HParser*, h_action, const HParser* p, const HAction a, void* user_data); JNIEXPORT jobject JNICALL Java_com_upstandinghackers_hammer_Hammer_in (JNIEnv *env, jclass class, jbyteArray charset, jint length) @@ -157,6 +164,13 @@ JNIEXPORT jobject JNICALL Java_com_upstandinghackers_hammer_Hammer_in } +JNIEXPORT jobject JNICALL Java_com_upstandinghackers_hammer_Hammer_notIn + (JNIEnv *env, jclass class, jbyteArray charset, jint length) +{ + RETURNWRAP(env, h_not_in((uint8_t*) ((*env)->GetByteArrayElements(env, charset, NULL)), (size_t)length)); +} + + JNIEXPORT jobject JNICALL Java_com_upstandinghackers_hammer_Hammer_endP (JNIEnv *env, jclass class) { @@ -226,6 +240,57 @@ JNIEXPORT jobject JNICALL Java_com_upstandinghackers_hammer_Hammer_choice RETURNWRAP(env, result); } +/** + * Given a null-terminated list of parsers, match a permutation phrase of these + * parsers, i.e. match all parsers exactly once in any order. + * + * If multiple orders would match, the lexically smallest permutation is used; + * in other words, at any step the remaining available parsers are tried in + * the order in which they appear in the arguments. + * + * As an exception, 'h_optional' parsers (actually those that return a result + * of token type TT_NONE) are detected and the algorithm will try to match them + * with a non-empty result. Specifically, a result of TT_NONE is treated as a + * non-match as long as any other argument matches. + * + * Other parsers that succeed on any input (e.g. h_many), that match the same + * input as others, or that match input which is a prefix of another match can + * lead to unexpected results and should probably not be used as arguments. + * + * The result is a sequence of the same length as the argument list. + * Each parser's result is placed at that parser's index in the arguments. + * The permutation itself (the order in which the arguments were matched) is + * not returned. + * + * Result token type: TT_SEQUENCE + */ +//HAMMER_FN_DECL_VARARGS_ATTR(H_GCC_ATTRIBUTE((sentinel)), HParser*, h_permutation, HParser* p); +JNIEXPORT jobject JNICALL Java_com_upstandinghackers_hammer_Hammer_permutation + (JNIEnv *env, jclass class, jobjectArray permutation) +{ + jsize length; + void **parsers; + int i; + jobject current; + const HParser *result; + + length = (*env)->GetArrayLength(env, permutation); + parsers = malloc(sizeof(HParser *)*(length+1)); + if(NULL==parsers) + { + return NULL; + } + + for(i=0; i<length; i++) + { + current = (*env)->GetObjectArrayElement(env, permutation, (jsize)i); + parsers[i] = UNWRAP(env, current); + } + parsers[length] = NULL; + + result = h_permutation__a(parsers); + RETURNWRAP(env, result); +} JNIEXPORT jobject JNICALL Java_com_upstandinghackers_hammer_Hammer_butNot (JNIEnv *env, jclass class, jobject p, jobject q) @@ -310,6 +375,21 @@ JNIEXPORT jobject JNICALL Java_com_upstandinghackers_hammer_Hammer_lengthValue RETURNWRAP(env, h_length_value(UNWRAP(env, length), UNWRAP(env, value))); } +/** + * This parser attaches a predicate function, which returns true or + * false, to a parser. The function is evaluated over the parser's + * result. + * + * The parse only succeeds if the attribute function returns true. + * + * attr_bool will check whether p's result exists and whether p's + * result AST exists; you do not need to check for this in your + * predicate function. + * + * Result token type: p's result type if pred succeeded, NULL otherwise. + */ +//HAMMER_FN_DECL(HParser*, h_attr_bool, const HParser* p, HPredicate pred, void* user_data); + JNIEXPORT jobject JNICALL Java_com_upstandinghackers_hammer_Hammer_and (JNIEnv *env, jclass class, jobject p) @@ -332,4 +412,107 @@ JNIEXPORT jobject JNICALL Java_com_upstandinghackers_hammer_Hammer_indirect } - +/** + * Set the inner parser of an indirect. See comments on indirect for + * details. + */ +//HAMMER_FN_DECL(void, h_bind_indirect, HParser* indirect, const HParser* inner); +//JNIEXPORT jobject JNICALL Java_com_upstandinghackers_hammer_Hammer_bind_indirect +// (JNIEnv *env, jclass class, jobject indirect, jobject inner) +//{ +// RETURNWRAP(env, h_bind_indirect(UNWRAP(env, indirect), UNWRAP(env, inner))); +//} + + +/** + * This parser runs its argument parser with the given endianness setting. + * + * The value of 'endianness' should be a bit-wise or of the constants + * BYTE_BIG_ENDIAN/BYTE_LITTLE_ENDIAN and BIT_BIG_ENDIAN/BIT_LITTLE_ENDIAN. + * + * Result token type: p's result type. + */ +//HAMMER_FN_DECL(HParser*, h_with_endianness, char endianness, const HParser* p); +JNIEXPORT jobject JNICALL Java_com_upstandinghackers_hammer_Hammer_with_endianness + (JNIEnv *env, jclass class, jbyte endianess, jobject p) +{ + RETURNWRAP(env, h_with_endianness((char) endianess, UNWRAP(env, p))); +} + + +/** + * The 'h_put_value' combinator stashes the result of the parser + * it wraps in a symbol table in the parse state, so that non- + * local actions and predicates can access this value. + * + * Try not to use this combinator if you can avoid it. + * + * Result token type: p's token type if name was not already in + * the symbol table. It is an error, and thus a NULL result (and + * parse failure), to attempt to rename a symbol. + */ +//HAMMER_FN_DECL(HParser*, h_put_value, const HParser *p, const char* name); + +/** + * The 'h_get_value' combinator retrieves a named HParseResult that + * was previously stashed in the parse state. + * + * Try not to use this combinator if you can avoid it. + * + * Result token type: whatever the stashed HParseResult is, if + * present. If absent, NULL (and thus parse failure). + */ +//HAMMER_FN_DECL(HParser*, h_get_value, const char* name); + +/** + * Monadic bind for HParsers, i.e.: + * Sequencing where later parsers may depend on the result(s) of earlier ones. + * + * Run p and call the result x. Then run k(env,x). Fail if p fails or if + * k(env,x) fails or if k(env,x) is NULL. + * + * Result: the result of k(x,env). + */ +//HAMMER_FN_DECL(HParser*, h_bind, const HParser *p, HContinuation k, void *env); + +/** + * This parser skips 'n' bits of input. + * + * Result: None. The HParseResult exists but its AST is NULL. + */ +//HAMMER_FN_DECL(HParser*, h_skip, size_t n); +JNIEXPORT jobject JNICALL Java_com_upstandinghackers_hammer_Hammer_skip + (JNIEnv *env, jclass class, jint n) +{ + RETURNWRAP(env, h_skip((size_t) n)); +} + +/** + * The HParser equivalent of fseek(), 'h_seek' modifies the parser's input + * position. Note that contrary to 'fseek', offsets are in bits, not bytes. + * The 'whence' argument uses the same values and semantics: SEEK_SET, + * SEEK_CUR, SEEK_END. + * + * Fails if the new input position would be negative or past the end of input. + * + * Result: TT_UINT. The new input position. + */ +//HAMMER_FN_DECL(HParser*, h_seek, ssize_t offset, int whence); +//TODO double check mapping for int +JNIEXPORT jobject JNICALL Java_com_upstandinghackers_hammer_Hammer_seek + (JNIEnv *env, jclass class, jint offset, jint whence) +{ + RETURNWRAP(env, h_seek((ssize_t) offset, (int) whence)); +} + +/** + * Report the current position in bits. Consumes no input. + * + * Result: TT_UINT. The current input position. + */ +//HAMMER_FN_DECL_NOARG(HParser*, h_tell); +JNIEXPORT jobject JNICALL Java_com_upstandinghackers_hammer_Hammer_tell + (JNIEnv *env, jclass class) +{ + RETURNWRAP(env, h_tell()); +} -- GitLab