Author: kjs
Date: Sat Apr 7 02:34:20 2007
New Revision: 18024
Modified:
trunk/compilers/pirc/doc/design.pod
trunk/compilers/pirc/src/pirparser.c
trunk/compilers/pirc/t/sub.t
Log:
compilers/pirc:
* changed the test file, testing is not working right now, and it failed.
* added more to design.pod about design of pirc.exe
* minor changes to the parser.
Modified: trunk/compilers/pirc/doc/design.pod
==============================================================================
--- trunk/compilers/pirc/doc/design.pod (original)
+++ trunk/compilers/pirc/doc/design.pod Sat Apr 7 02:34:20 2007
@@ -14,8 +14,9 @@
Documentation of the lexer and the parser can be generated by running:
- pod2html src/pirlexer.c > doc/pirlexer.html
- pod2html src/pirparser.c > doc/pirparser.html
+ make docs
+
+which will generate html files in the C<doc> directory.
This document will only provide a high-level overview.
@@ -30,7 +31,6 @@
for each character, as I/O is relatively slow.
-
=head1 THE PARSER
The parser is defined in C<pirparser.c>. The header file only predeclares the
@@ -50,13 +50,192 @@
The parser calls at a number of places C<emit> functions. These are I<hooks> to
which a function can be hooked, that will be called when the parser calls that
-function. This is implemented using vtables.
+function. This is implemented using vtables. Of course, not all hooks need to
be
+used. If a hook is not assigned a function by the user, the default empty
function
+is invoked. This is done to prevent NULL checks; let's just hope the optimizer
+sees the invoked function is empty, so the overhead of calling it is removed.
+
+=head2 Example Vtable methods
+
+This section gives a simple example to show how things are used.
+Let's consider a simplified version of a C<long_invocation>. Syntactically, it
+looks like this (this is the simplified version):
+
+ long-invocation -> '.pcc_begin' '\n'
+ arguments
+ '.pcc_call' invokable '\n'
+ results
+ '.pcc_end' '\n'
+
+ invocant -> IDENTIFIER | PREG
+
+The parsing routine for long-invocation (again, its simplified version) looks
+as follows:
+
+ static void
+ long_invocation(parser_state *p) {
+ emit_invocation_start(p); /* indicate start of invocation */
+ match(p, T_PCC_BEGIN);
+ match(p, T_NEWLINE);
+ arguments(p);
+
+ match(p, T_PCC_CALL); /* check for token '.pcc_call' */
+ match(p, T_NEWLINE); /* check for a newline */
+
+ /* get current token from lexer and store it as the invokable object */
+ emit_invokable(p, get_current_token(p->lexer));
+
+ /* check whether it was an invokable object and get next token */
+ switch (p->curtoken) {
+ case T_IDENTIFIER:
+ case T_PREG:
+ emit_invokable(p, get_current_token(p->lexer));
+ break;
+ default:
+ syntax_error(p, 1, "invokable object expected");
+ break;
+ }
+
+ results(p);
+
+ match(p, T_PCC_END); /* accept token '.pcc_end' */
+ match(p, T_NEWLINE); /* accept the newline token */
+ emit_invocation_end(p); /* close down invocation sequence */
+
+ }
+
+ static void
+ arguments(parser_state *p) {
+ emit_args_start(p); /* start sequence of arguments */
+ /* handle arguments */
+ emit_args_end(p); /* stop sequence of arguments */
+ }
+
+ static void
+ results(p) {
+ emit_results_start(p); /* start sequence of results */
+ /* handle results */
+ emit_results_end(p); /* stop sequence of results */
+ }
+
+To each of the emit_* function calls, the writer of the back-end can
+hook a custom function, that does the Appropiate Thing. What is
+appropiate, depends on the back-end. Some back-ends need to construct
+a data structure (AST) (for example the PBC backend would need this),
+others can just spit out what they get (like the PIR back-end).
-Currently, there are two back-end targets: Parrot Abstract Syntax Tree (PAST),
-and simply PIR.
+
+=head2 Supported back-ends
+
+Currently, there are the following back-end targets:
+
+=over 4
+
+=item *
+
+PAST - textual form of PAST using Data::Dumper format.
+
+=item *
+
+PIR - PIR output, which I<may> change PIR syntax into PASM syntax.
+
+=item *
+
+JSON - JSON is extremely simple, and adding this back-end was pretty easy.
+
+=item *
+
+PBC - but this one is not implemented at all. Just a stub file.
+
+=back
See src/pirvtable.{c,h} for details.
+Please note that none of the back-ends is complete.
+
+
+=head2 VTable Methods
+
+Now, you might ask yourself, who or what decides where these hooks, or vtable
method calls
+are done. "Why is there a hook over I<here>?" Well, that's done by figuring
out at what
+moment a back-end might need to get some information of the parser. As the
parser continues,
+the tokens being read are lost, if they're not stored anywhere. So, every once
and a while
+the back-end needs to be able to store stuff, so it can do its job properly.
+
+The vtable is not complete yet. There are a number of parsing routines that do
not have
+associated vtable methods (invocations). Of course, we don't want the parser
to do too
+much vtable invocations. On the other hand, if the parser does too few,
constructing a
+back-end might be impossible. It's a bit of a trade-off.
+
+
+=head1 OVERVIEW
+
+This section gives an overview of what functionality is in what file:
+
+=over 4
+
+=item *
+
+src/pirlexer.{c,h} - implementation of the lexer
+
+=item *
+
+src/pirparser.{c,h} - implementation of the parser
+
+=item *
+
+src/pirvtable.{c,h} - constructor of an empty vtable
+
+=item *
+
+src/pirout.{c,h} - back-end that implements the vtable methods to output PIR
+
+=item *
+
+src/pastout.{c,h} - back-end that implements the vtable methods to output PAST
(in Data::Dumper format)
+
+=item *
+
+src/pbcout.{c,h} - dummy back-end for PBC. This file only creates a vtable,
but no implementation yet.
+
+=item *
+
+src/jsonout.{c,h} - back-end that implements the vtable methods to output JSON.
+
+=item *
+
+src/pirmain.c - main file for C<pirc>. Execution starts here.
+
+=back
+
+=head1 WHAT NEEDS TO BE DONE
+
+There are some major TODOs:
+
+=over 4
+
+=item *
+
+Check whether an identifier is actually a Parrot op. In IMCC, this is done by
calling
+Parrot_is_builtin(). However, for that, we need a Parrot_Interp. Currently I
have problems
+getting things to link correctly.
+
+=item *
+
+Complete at least 1 back-end, to see what more vtable entries we need. And of
course,
+to generate PBC in the end.
+
+=item *
+
+Complete the vtable structure with all needed vtable methods.
+
+=item *
+
+Memory management; not all memory is freed at this moment. Does it need to be
done
+by the back-end, or by the parser?
+
+=back
+
=head1 AUTHOR
Klaas-Jan Stol <parrotcode at gmail dot com>
Modified: trunk/compilers/pirc/src/pirparser.c
==============================================================================
--- trunk/compilers/pirc/src/pirparser.c (original)
+++ trunk/compilers/pirc/src/pirparser.c Sat Apr 7 02:34:20 2007
@@ -60,6 +60,7 @@
#include <stdarg.h>
#include <string.h>
+
/*
=head1 PARSER INTERNALS
@@ -69,7 +70,7 @@
typedef struct parser_state {
struct lexer_state *lexer; -- the lexer
token curtoken; -- the current token as returned by the
lexer
- char *heredoc_ids[10]; -- array for holding heredoc arguments.
XXX Limited to 10 currently XXX
+ char **heredoc_ids; -- array for holding heredoc arguments.
XXX Limited to 10 currently XXX
unsigned heredoc_index; -- index to keep track of heredoc ids
in the array
unsigned parse_errors; -- counter for parse_errors
pirvtable *vtable; -- vtable holding pointers for output
routines
@@ -88,6 +89,8 @@
unsigned parse_errors;
pirvtable *vtable;
+ /* Parrot_Interp interp; */
+
} parser_state;
@@ -1318,7 +1321,7 @@
*/
static void
-invocant(parser_state *p) {
+invokable(parser_state *p) {
switch (p->curtoken) {
case T_IDENTIFIER:
case T_PREG:
@@ -1338,7 +1341,7 @@
long-invocation -> '.pcc_begin' '\n'
{ '.arg' expression arg_flags }
- ( '.pcc_call'|'.nci_call') invocant '\n'
+ ( '.pcc_call'|'.nci_call') invokable '\n'
| '.invocant' invocant '\n'
'.meth_call' method '\n'
)
@@ -1369,15 +1372,15 @@
/* the invocant and/or sub to be called */
switch (p->curtoken) {
- case T_PCC_CALL: /* '.pcc_call' invocant '\n' */
- case T_NCI_CALL: /* '.nci_call' invocant '\n' */
+ case T_PCC_CALL: /* '.pcc_call' invokable '\n' */
+ case T_NCI_CALL: /* '.nci_call' invokable '\n' */
next(p);
- invocant(p);
+ invokable(p);
match(p, T_NEWLINE);
break;
case T_INVOCANT: /* '.invocant' invocant '\n' */
next(p);
- invocant(p);
+ invokable(p);
match(p, T_NEWLINE);
match(p, T_METH_CALL); /* .meth_call method '\n' */
method(p);
Modified: trunk/compilers/pirc/t/sub.t
==============================================================================
--- trunk/compilers/pirc/t/sub.t (original)
+++ trunk/compilers/pirc/t/sub.t Sat Apr 7 02:34:20 2007
@@ -23,8 +23,6 @@
.sub test :main, :load, :init
.end
-.sub myAdd :vtable('add')
-.end
.sub X :anon
.end
@@ -34,6 +32,9 @@
pir_output_is( <<'CODE', <<'OUTPUT', "parameters" );
+.sub main
+.end
+
.sub test
.param int i
.param num n
@@ -44,6 +45,8 @@
OUTPUT
pir_output_is( <<'CODE', <<'OUTPUT', "parameters and flags" );
+.sub main
+.end
.sub test
.param int i :optional
.param int o :opt_flag