ANTLR grammar for scheme R5RS - scheme

I'm beginner in ANTLR and I'm learning it by an example. I use C as my target language.
The example is a Scheme R5RS grammar file taken from this question, with a little modification(rename the grammar name and add some options with the grammar specification untouched).
antlr generated the lexer and parser, and I compile it with a test main() in which I just do some initialization and simply call the parser. When runing the test program with a piece of scheme code, the parser detect some syntax error(which should not happen!)
main function in test.c
#include <stdio.h>
#include "r5rsLexer.h"
#include "r5rsParser.h"
int main(int argc, char *argv[])
{
pANTLR3_UINT8 fname;
pANTLR3_INPUT_STREAM input;
pr5rsLexer lexer;
pANTLR3_COMMON_TOKEN_STREAM tstream;
pr5rsParser parser;
r5rsParser_parse_return parse_return;
if (argc != 2)
{
ANTLR3_FPRINTF(stderr, "usage: %s file\n", argv[0]);
exit(1);
}
fname = (pANTLR3_UINT8)argv[1];
input = antlr3FileStreamNew(fname, ANTLR3_ENC_8BIT);
if (!input)
{
ANTLR3_FPRINTF(stderr, "open file stream failed\n");
exit(1);
}
lexer = r5rsLexerNew(input);
if (!lexer)
{
ANTLR3_FPRINTF(stderr, "new lexer failed\n");
exit(1);
}
tstream =
antlr3CommonTokenStreamSourceNew(ANTLR3_SIZE_HINT, TOKENSOURCE(lexer));
if (!tstream)
{
ANTLR3_FPRINTF(stderr, "open token stream failed\n");
exit(1);
}
parser = r5rsParserNew(tstream);
if (!parser)
{
ANTLR3_FPRINTF(stderr, "new parser failed\n");
exit(1);
}
parse_return = parser->parse(parser);
printf("succeed!\n");
return 0;
}
scheme code in test.scm:
(define-syntax should-be
(syntax-rules ()
((_ test-id value expression)
(let ((return-value expression))
(if (not (equal? return-value value))
(for-each (lambda (v) (display v))
`("Failure: " test-id ", expected '"
value "', got '" ,return-value "'." #\newline))
(for-each (lambda (v) (display v))
'("Passed: " test-id #\newline)))))))
(should-be 1.1 0
(let ((cont #f))
(letrec ((x (call-with-current-continuation (lambda (c) (set! cont c) 0)))
(y (call-with-current-continuation (lambda (c) (set! cont c) 0))))
(if cont
(let ((c cont))
(set! cont #f)
(set! x 1)
(set! y 1)
(c 0))
(+ x y)))))
the terminal output:
$> ls
r5rs.g test.c test.scm
$> antlr3 r5rs.g
$> ls
r5rs.g r5rs.tokens r5rsLexer.c r5rsLexer.h r5rsParser.c r5rsParser.h test.c test.scm
$> gcc -o test test.c r5rsLexer.c r5rsParser.c -lantlr3c
$> ./test test.scm
test.scm(1) : error 4 : Unexpected token, at offset 0
near [Index: 1 (Start: 154513905-Stop: 154513917) ='define-syntax', type<5> Line:1
LinePos:0]
: unexpected input...
expected one of : <EOR>
test.scm(2) : error 4 : Unexpected token, at offset 3
near [Index: 8 (Start: 154513932-Stop: 154513943) ='syntax-rules', type<7> Line: 2
LinePos:3]
: unexpected input...
expected one of : <EOR>
test.scm(2) : error 4 : Unexpected token, at offset 17
near [Index: 11 (Start: 154513946-Stop: 154513946) =')', type<82> Line: 2 LinePos:17]
: unexpected input...
expected one of : <EOR>
test.scm(2) : error 4 : Unexpected token, at offset 17
near [Index: 11 (Start: 154513946-Stop: 154513946) =')', type<82> Line: 2 LinePos:17]
: unexpected input...
expected one of : <EOR>
I've read through the grammar specification and it is correct. I can't figure out where the problem lies ... can someone help? thanks!
===================== reply =========================
Following the grammar rule of pattern and template, I went down to the code fragment below. I think the parse is going to match template with it and failed because template doesn't have an quasiquote alternative.
`("Failure: " test-id ", expected '" value "', got '" ,return-value "'." #\newline)
I believe the grammar rule for template follows the R5RS specification correctly, and the code is accepted by other R5Rs scheme implementation(I tested it in scheme48 and guile). How can this happen?
I think there must be something wrong in my analyse ...

It is a back-tick in
`("Failure: " test-id ", expected '"
that trips the parser.
If you follow grammar rules for pattern and template, you'll see that they don't reach quasiquotation rule that match both QUASIQUOTE and back-tick. They do however reach expressionKeyword that contains QUASIQUOTE.
You should fix grammar to include abbreviated forms in template or fix your input not to use them.

Related

How to work with javascript promises in clojurescript?

I have a problem with js promises:
I'm trying to convert this js code:
stripe.createToken(card).then(function(result) {
if (result.error) {
// Inform the customer that there was an error.
var errorElement = document.getElementById('card-errors');
errorElement.textContent = result.error.message;
} else {
// Send the token to your server.
stripeTokenHandler(result.token);
}
And I have the following:
(go
(let [result (<!
(.createToken stripe #(subscribe [:card-element]))
)]
(prn "result is" result)
;; (if (.-error result)
;; (.textContent (js/document.getElementById "card-errors") (.-message .-error result))
;; (prn "response is" (js/stripeTokenHandler (.-token result)))
;; )
)
)
But I get "No protocol method ReadPort.take! defined for type object: [object Promise]"
How do I do the js .then() part in cljs?
It seems you are a little bit confused with JavaScript interop. You can take a look at the Cheatsheet under the JavaScript Interop section.
Here are some quick examples:
JS CLJS
object.method(arg1, arg2) <=> (.method object arg1 arg2)
object.field <=> (.-field object)
object.field = "foo" <=> (set! (.-field object) "foo")
object.nested.field <=> (.-field (.-nested object))
To improve readability, you can use the -> arrow macro:
object.nested.field <=> (-> object .-nested .-field)
You can then rewrite your example as:
(-> (.createToken stripe card)
(.then (fn [result]
(if-let [error (.-error result)]
(-> (.getElementById js/document "card-errors")
(.-textContent)
(set! (.-message error)))
(js/stripeTokenHandler (.-token result)))))
;; if there is a `catch` branch
(.catch (fn […] …)))

Getting the output of a process

I am trying to create a function which takes as input a path and returns the output of the ls terminal command as a string. I'm using a process and sentinel since I'll eventually want to create other functions which will take some time to execute, and I want them to run asynchronously.
(defun ls-to-string (path)
(let (ls-proc
ls-output)
(progn (setq ls-proc (start-process "" "ls-buffer" "ls" path))
(set-process-sentinel ls-proc (lambda (p e)
(if (string= e "finished\n")
(progn (set-buffer "ls-buffer")
(setq ls-output (buffer-string))
(kill-buffer "ls-buffer")
(message ls-output))))) <---- (1)
ls-output))) <---- (2)
(ls-to-string "/home")
I have (temporarily) added (message ls-output) just to show that ls-output does contain the string (1). However the return value is nil (2).

Elisp function to replace underscores for white spaces in the current line

I'm trying to write a very simple function to replace all the underscores in the current line for whites paces.
This is what I have so far
(select-current-line)
(exit-minibuffer)
(query-replace "_" " " nil (if (and transient-mark-mode mark-active) (region-beginning)) (if (and transient-mark-mode mark-active) (region-end)))
But I get the following message:
No catch for tag: exit, nil
I'm not very convinced that using query-replace in an active selection is the best way, but I am not a elisp programmer at all.
Any ideas?
Thanks
UPDATE:
Based in the answers below, this is the piece code that I ended using:
(let ((end (copy-marker (line-end-position))))
(while (re-search-forward "_" end t)
(replace-match " " nil nil)))
C-h f query-replace RET doesn't say what I wanted to quote, but C-h f perform-replace RET does:
Don't use this in your own program unless you want to query and set the mark
just as `query-replace' does. Instead, write a simple loop like this:
(while (re-search-forward \"foo[ \\t]+bar\" nil t)
(replace-match \"foobar\" nil nil))
As for limiting it to the current line, the best way to do it is to use the second arg of re-search-forward:
(let ((end (copy-marker (line-end-position))))
(while (re-search-forward \"foo[ \\t]+bar\" end t)
(replace-match \"foobar\" nil nil)))
Notice the use of copy-marker because the position of the end-of-line will keep changing as you modify the line, so you don't want to keep the position as a plain integer but as a marker (which is tied to a place in the text).
A common alternative is to go backwards (since insertion/deletions only affect positions after the change):
(end-of-line)
(let ((beg (line-beginning-position)))
(while (re-search-backward \"foo[ \\t]+bar\" beg t)
(replace-match \"foobar\" nil nil)))

lambda captures; c++ vs elisp

Reading the answer from Capturing a reference by reference in a C++11 lambda makes me think that the following code generates undefined behavior because of the ended lifetime of i in the lambda-capture. Is that right for C++1y? I am asking because g++ 4.8.2 translates the code just fine.
#include <iostream>
auto captureFct( ) {
int i=0;
auto set = [&i](int _i){ i=_i; };
auto get = [&i](){ return i; };
return std::pair<decltype(set),decltype(get)>(set,get);
}
int main() {
auto myPair = captureFct();
auto set1 = myPair.first;
auto get1 = myPair.second;
auto myPair1 = captureFct();
auto set2 = myPair1.first;
auto get2 = myPair1.second;
std::cout << "\nget1:" << get1() << " get2:" << get2() << '\n';
set1(1); set2(2);
std::cout << "\nget1:" << get1() << " get2:" << get2();
}
/*
Local Variables:
compile-command: "g++ -std=c++1y lambda.cc -o a.exe && ./a.exe"
End:
*/
The output is interesting:
get1:0 get2:0
get1:2 get2:2
It seems that the same reference is used for all lambdas.
This behavior differs from the behavior of the following elisp code (as close to the c++ code as possible):
(defun captureFct ()
(lexical-let ((i 0))
(list :set (lambda (_i) (setq i _i))
:get (lambda () i))))
(setq myPair (captureFct))
(setq myPair1 (captureFct))
(message "\nget1: %d get2: %d"
(funcall (plist-get myPair :get))
(funcall (plist-get myPair1 :get)))
(funcall (plist-get myPair :set) 1)
(funcall (plist-get myPair1 :set) 2)
(message "\nget1: %d get2: %d"
(funcall (plist-get myPair :get))
(funcall (plist-get myPair1 :get)))
The output of the elisp code is:
get1: 0 get2: 0
get1: 1 get2: 2
I think I know already the answer. But, I post this question anyway since it is interesting for folks that do both elisp and c++.
Last but not least a C++ version that works like the elisp version:
#include <iostream>
#include <memory>
auto captureFct( ) {
std::shared_ptr<int> pi(new int(0));
auto set = [pi](int _i){ *pi=_i; };
auto get = [pi](){ return *pi; };
return std::pair<decltype(set),decltype(get)>(set,get);
}
int main() {
auto myPair = captureFct();
auto set1 = myPair.first;
auto get1 = myPair.second;
auto myPair1 = captureFct();
auto set2 = myPair1.first;
auto get2 = myPair1.second;
std::cout << "\nget1:" << get1() << " get2:" << get2() << '\n';
set1(1); set2(2);
std::cout << "\nget1:" << get1() << " get2:" << get2();
}
/*
Local Variables:
compile-command: "g++ -std=c++1y lambda.cc -o a.exe && ./a.exe"
End:
*/
Yes, it's undefined behaviour, since the references inside the lambdas become dangling as soon as captureFunc() exits (*).
What's probably happening in your case is that the references (which are just pointers under the hood) still point to the space on the stack where i was on the first invocation of captureFunc(), and it ends up in exactly the same location on the second invocation of captureFunc(); so the net effect is that all of get1, get2, set1, set2 have their internal i reference pointed to the same (currently unused) location in memory, so they modify it for each other.
Of course, the above is just speculation, and could change next time you (or run) the program, since Undefined Behaviour is Undefined.
(*) Quoting C++11, [expr.prim.lambda]§22:
[ Note: If an entity is implicitly or explicitly captured by reference, invoking the function call operator of
the corresponding lambda-expression after the lifetime of the entity has ended is likely to result in undefined
behavior. —end note ]

Using syntax-table information in elisp for tokenization

I would like to use elisp to tokenize the following:
variable := "The symbol \" delimits strings"; (* Comments go here *)
as:
<variable> <:=> <The symbol \" delimits strings> <;>
based on the information from the buffer's syntax-table.
I have the symbol-table setup appropriately and am currently using the following function which operates correctly except for the string constant (either returns token or nil if point is not at an identifier or one of the operators in the regex).
(defun forward-token ()
(forward-comment (point-max))
(cond
((looking-at (regexp-opt '("=" ":=" "," ";")))
(goto-char (match-end 0))
(match-string-no-properties 0))
(t (buffer-substring-no-properties
(point)
(progn (skip-syntax-forward "w_")
(point))))))
I am an elisp novice, so any pointers are appreciated.
I don't think your skip-syntax-forward use is correct for strings.
I think you need to add a cond clause like this:
((looking-at "\"")
(let* ((here (point)) (there (scan-sexps here 1)))
(goto-char there)
(buffer-substring-no-properties
(1+ here) (1- there))))
to handle string literals.

Resources