# New Ticket Created by  Jürgen Bömmels 
# Please include the string:  [perl #21277]
# in the subject line of all future correspondence about this issue. 
# <URL: http://rt.perl.org/rt2/Ticket/Display.html?id=21277 >


Hello,

Here is an extension to my first macro support patch (#21033 already
applied).

This replaces the calls to yyerror wiht calls to fataly as suggested
by leo, and removes some dead code which creaped through in the first
patch.

Further more it implements ".constant"; now only the two buggy string
tests fail when run with imcc.

And last there is a start of documentation docs/macros.pod, which is a
slightly edited version of perldoc -u assemble.pl.

bye boe


-- attachment  1 ------------------------------------------------------
url: http://rt.perl.org/rt2/attach/52351/39659/cb0334/imcc2.diff

Index: MANIFEST
===================================================================
RCS file: /cvs/public/parrot/MANIFEST,v
retrieving revision 1.314
diff -u -r1.314 MANIFEST
--- MANIFEST	14 Feb 2003 22:33:42 -0000	1.314
+++ MANIFEST	18 Feb 2003 01:22:09 -0000
@@ -1364,6 +1364,7 @@
 languages/imcc/debug.c
 languages/imcc/debug.h
 languages/imcc/docs/imcc.pod
+languages/imcc/docs/macros.pod
 languages/imcc/docs/operation.pod
 languages/imcc/docs/parsing.pod
 languages/imcc/docs/running.pod
Index: languages/imcc/imcc.l
===================================================================
RCS file: /cvs/public/parrot/languages/imcc/imcc.l,v
retrieving revision 1.27
diff -u -r1.27 imcc.l
--- languages/imcc/imcc.l	17 Feb 2003 13:56:36 -0000	1.27
+++ languages/imcc/imcc.l	18 Feb 2003 01:22:09 -0000
@@ -47,7 +47,6 @@
 
 /* static function declariations */
 static struct macro_frame_t *new_frame (void);
-/*static void add_param_to_frame (const char *param, const char *expansion); */
 static void scan_string (struct macro_frame_t *frame, const char *expansion);
 static void scan_file (struct macro_frame_t *frame, FILE *);
 static void destroy_frame (struct macro_frame_t *frame);
@@ -129,7 +128,7 @@
 	return EOM;
     }
 
-<emit,INITIAL>[ISNP]{DIGIT}{DIGIT}? {
+<*>[ISNP]{DIGIT}{DIGIT}? {
 	valp->s = str_dup(yytext);
 	return REG;
 	}
@@ -182,6 +181,37 @@
         return read_macro(valp, interp);
     }
 
+<INITIAL>".macro" {
+        fataly (EX_SOFTWARE, "", line, "Macros only allowed in assembly mode");
+    }
+
+<emit>".constant" {
+        int c;
+	char *name;
+	struct macro_t *m;
+
+	BEGIN(macro);
+	c = yylex_skip(valp, interp, " ");
+	if (c != IDENTIFIER)
+	    fataly(EX_SOFTWARE, ".constant", line,
+		   "Constant names must be identifiers");
+
+	name = str_dup(valp->s);
+
+	c = yylex_skip(valp, interp, " ");
+        if (c != INTC && c != FLOATC && c != STRINGC && c != REG)
+        fataly(EX_SOFTWARE, name, line, "Constant value must be a number, "
+            "stringliteral or register");
+
+	m = macros + num_macros++;
+	m->name = name;
+	m->expansion = str_dup (valp->s);
+	m->params.num_param = 0;
+
+	BEGIN (emit);
+	return MACRO;
+    }
+
 <emit>".include" {
         int c;
 
@@ -303,7 +333,8 @@
         char *label;
 	char *name = macros[num_macros].name;
 
-	if (yylex(valp, interp) != LABEL) yyerror("LABEL expected");
+	if (yylex(valp, interp) != LABEL) 
+	    fataly(EX_SOFTWARE, "", line, "LABEL expected");
 
 	if (valp) {
 	    YYCHOP();
@@ -408,7 +439,7 @@
     const char *p;
 
     do {
-        c = yylex(NULL, interp);
+        c = yylex(valp, interp);
         p = skip;
 	while (*p && c != *p) p++;
     } while (*p != '\0');
@@ -418,7 +449,7 @@
 
 static int
 read_params (YYSTYPE *valp, void *interp, struct params_t *params,
-	     int need_id)
+	     const char *macro_name, int need_id)
 {
     int c;
     YYSTYPE val;
@@ -429,7 +460,9 @@
     c = yylex_skip(&val, interp, " \n");
 
     while(c != ')') {
-	if (c == 0) yyerror ("Unexpected end of file");
+	if (c == 0) 
+	    fataly(EX_SOFTWARE, macro_name, line, 
+		   "End of file reached while reading arguments");
 	else if (c == ',') {
 	    params->name[params->num_param++] = current;
 	    current = strdup("");
@@ -437,7 +470,8 @@
 	    c = yylex_skip(&val, interp, " \n");
 	}
 	else if (need_id && (*current || c != IDENTIFIER) && c != ' ') {
-	    yyerror("macro parameter error");
+	    fataly(EX_SOFTWARE, macro_name, line,
+		   "Parameter definition must be IDENTIFIER");
 	}
 	else {
 	    if (!need_id || c != ' ') {
@@ -469,11 +503,9 @@
     start_cond = YY_START;
     BEGIN(macro);
 
-    c = yylex(NULL, interp);
-    if (c != ' ') yyerror("macro error");
-
-    c = yylex(valp, interp);
-    if (c != IDENTIFIER) yyerror("macro error");
+    c = yylex_skip(valp, interp, " ");
+    if (c != IDENTIFIER)
+	fataly(EX_SOFTWARE, ".macro", line, "Macro names must be identifiers");
 
     m->name = valp->s;
 
@@ -483,14 +515,15 @@
     if (c == '(') {
 	free(valp->s);
 
-	c = read_params(NULL, interp, &m->params, 1);
-	if (c != ')') yyerror("macro parameter: \")\" expected");
+	c = read_params(NULL, interp, &m->params, m->name, 1);
 
 	c = yylex(valp, interp);
     }
 
     while (c != ENDM) {
-	if (c == 0) yyerror("file ended before macro complete");
+	if (c == 0)
+	    fataly (EX_SOFTWARE, m->name, line,
+		    "File ended before macro was complete");
 
 	strcat(temp_buffer, valp->s);
 	free(valp->s);
@@ -559,13 +592,15 @@
     frame->params = &m->params;
     if (m) {
 	/* whitespace can be savely ignored */
-	do {
+	do { 
 	    c = input();
 	} while (c == ' ' || c == '\t');
 
 	if (c != '(') {
 	    unput(c);
-	    if (m->params.num_param != 0) yyerror ("Missing macro parameter");
+	    if (m->params.num_param != 0)
+		fataly (EX_SOFTWARE, m->name, line,
+			"macro needs %d parameters", m->params.num_param);
 	    scan_string(frame, m->expansion);
 	    return 1;
 	}
@@ -573,7 +608,7 @@
 	start_cond = YY_START;
 	BEGIN(macro);
 
-	read_params (NULL, interp, &frame->expansion, 0);
+	read_params (NULL, interp, &frame->expansion, m->name, 0);
 
 	BEGIN(start_cond);
 
@@ -583,7 +618,9 @@
 	}
 
 	if (frame->expansion.num_param != m->params.num_param) {
-	    yyerror ("Wrong number of macro arguments");
+	    fataly(EX_SOFTWARE, m->name, line, 
+		   "Macro requires %d arguments, but %d given",
+		   frame->expansion.num_param, m->params.num_param);
 	}
 
 	scan_string(frame, m->expansion);
@@ -602,7 +639,8 @@
     frame = new_frame();
 
     file = fopen(file_name, "r");
-    if (!file) yyerror ("file not found");
+    if (!file) 
+	fataly(EX_SOFTWARE, file_name, line, strerror(errno));
 
     scan_file (frame, file);
 }
Index: languages/imcc/imcc.y
===================================================================
RCS file: /cvs/public/parrot/languages/imcc/imcc.y,v
retrieving revision 1.45
diff -u -r1.45 imcc.y
--- languages/imcc/imcc.y	17 Feb 2003 13:56:36 -0000	1.45
+++ languages/imcc/imcc.y	18 Feb 2003 01:22:10 -0000
@@ -169,31 +169,6 @@
     return 0;
 }
 
-#if 0
-/* return the index of a PMC class */
-static int
-get_pmc_num(struct Parrot_Interp *interpreter, char *pmc_type)
-{
-    STRING * s = string_make(interpreter, pmc_type,
-            (UINTVAL) strlen(pmc_type), NULL, 0, NULL);
-    PMC * key = key_new_string(interpreter, s);
-    return interpreter->Parrot_base_classname_hash->vtable->get_integer_keyed(
-            interpreter, interpreter->Parrot_base_classname_hash, key);
-}
-
-/* only .PmcType */
-SymReg *
-macro(struct Parrot_Interp *interp, char *name)
-{
-    SymReg * r;
-    char buf[16];
-    int type = get_pmc_num(interp, name);
-    sprintf(buf, "%d", type);
-    r =  mk_const(str_dup(buf), 'I');
-    return r;
-}
-#endif
-
 static Instruction *
 multi_keyed(struct Parrot_Interp *interpreter,char *name,
 SymReg ** r, int nr, int emit)
@@ -410,7 +385,7 @@
 
 %token <t> CALL GOTO ARG IF UNLESS NEW END SAVEALL RESTOREALL
 %token <t> SUB NAMESPACE ENDNAMESPACE CLASS ENDCLASS SYM LOCAL CONST PARAM
-%token <t> CONSTANT INC DEC
+%token <t> INC DEC
 %token <t> SHIFT_LEFT SHIFT_RIGHT INTV FLOATV STRINGV DEFINED LOG_XOR
 %token <t> RELOP_EQ RELOP_NE RELOP_GT RELOP_GTE RELOP_LT RELOP_LTE
 %token <t> GLOBAL ADDR CLONE RESULT RETURN POW SHIFT_RIGHT_U LOG_AND LOG_OR
@@ -427,7 +402,7 @@
 %type <sr> target reg const var rc string
 %type <sr> key keylist _keylist newtype
 %type <sr> vars _vars var_or_i _var_or_i
-%type <i> pasmcode pasmline pasm_inst constant_def
+%type <i> pasmcode pasmline pasm_inst
 %type <sr> pasm_args lhs
 %token <sr> VAR
 
@@ -451,7 +426,6 @@
 
 pasmline: labels  pasm_inst '\n'  { $$ = 0; }
     | MACRO '\n'                  { $$ = 0; }
-    | constant_def
     ;
 
 pasm_inst: {clear_state();}
@@ -460,9 +434,6 @@
     ;
 pasm_args:
     vars
-    ;
-
-constant_def: CONSTANT IDENTIFIER const { /* printf ("%s\n", $1); */ }
     ;
 
 emit:
Index: languages/imcc/docs/macros.pod
===================================================================
RCS file: languages/imcc/docs/macros.pod
diff -N languages/imcc/docs/macros.pod
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ languages/imcc/docs/macros.pod	18 Feb 2003 01:22:10 -0000
@@ -0,0 +1,128 @@
+=head1 NAME
+
+IMCC - Macros
+
+=head1 OVERVIEW
+
+This document describes the macro layer of imcc
+
+=head1 DESCRIPTION
+
+The macro support for IMCC was designed to be a drop in replacement
+for the original F<assemble.pl> macro layer. There for the the macro
+expansion at the moment only works in assembly mode. Furthermore this
+documentation is in large parts copied literally from there.
+
+The addition of the '.' preface will hopefully make things easier to
+parse, inasmuch as everything within an assembler file that needs to
+be expanded or processed by the macro engine will have a period ('.')
+prepended to it.
+
+The macro layer implements constants, macros, local labels and
+including of files.
+
+A macro definition starts with a line consisting of ".macro", the
+name for the newly created macro and an optional list of parameters.
+Thereafter follows the definition of the macro which can span several
+lines. The definition is ended by ".endm". In the macro definition the 
+formal parameters, preceeded by a '.', are valid macros.
+
+  .macro swap (A,B,TEMP) # . marks the directive
+    set .TEMP,.A         # . marks the special variable.
+    set .A,.B
+    set .B,.TEMP
+  .endm                  # And . marks the end of the macro.
+
+Macros support labels that are local to a given macro expansion, and the syntax
+looks something like this:
+
+  .macro SpinForever (Count)
+    .local $LOOP: dec .COUNT # ".local $LOOP" defines a local label.
+                  branch .$LOOP # Jump to said label.
+  .endm
+
+Include this macro as many times as you like, and the branch statement should
+do the right thing every time. To use a global label, just as you usually do.
+
+Constants are new, and the syntax looks like:
+
+  .constant PerlHash 6 # Again, . marks the directive
+
+  new P0, .PerlHash # . marks the special variable for expansion.
+
+Several constants are predefined, namely the PMC-Classes.
+
+  .constant Array 0
+  .constant PerlUndef 1
+  ...
+
+The ".include" statement is followed by a string literal. The file of
+this name is include literally in the assembly.
+
+=head2 Expansion
+
+Constant definitions have the form
+
+  .constant name {register}
+  .constant name {signed_integer}
+  .constant name {signed_float}
+  .constant name {"string constant"}
+  .constant name {'string constant'}
+
+They don't generate any code, but create a new macro directive .name
+
+Given the line:
+
+  '.constant HelloWorld "Hello, World!"'
+
+one can expand HelloWorld via:
+
+  'print .HelloWorld' # Note the period to indicate a thing to expand.
+
+Some predefined constants exist for your convenience, namely:
+
+  .Array
+  .PerlHash
+  .PerlArray
+
+and the other PMC types.
+
+The contents of external files can be included by use of the C<.include>
+macro:
+
+  .include "{filename}"
+
+The contents of the included file are inserted at the point where the
+C<.include> macro occurs. This means that code like this:
+
+  print "Hello "
+  .include "foo.pasm"
+  end
+
+where F<foo.pasm> contains:
+
+  print "World \n"
+
+becomes:
+
+  print "Hello "
+  print "World \n"
+  end
+
+Attempting to include a non-existent file is a non-fatal error.
+
+  .macro name ({arguments?})
+  ...
+  .endm
+
+Optional arguments are simply identifiers separated by commas. These
+arguments are matched to instances inside the macro named '.foo'. A
+simple example follows:
+
+  .macro inc3 (A)
+    inc .A # Mark the argument to expand with a '.'.
+    inc .A
+    inc .A
+  .endm
+
+  .inc3(I0) # Expands to the obvious ('inc I0\n') x 3

Reply via email to