Răsfoiți Sursa

Merged conflicts.

Jayke Meijer 14 ani în urmă
părinte
comite
43f769abe8
14 a modificat fișierele cu 400 adăugiri și 105 ștergeri
  1. 0 6
      .gitignore
  2. 1 3
      QUESTIONS
  3. 3 0
      README
  4. 9 0
      src/.gitignore
  5. 13 10
      src/Makefile
  6. 44 0
      src/basic_block.py
  7. 0 21
      src/lex.l
  8. 0 65
      src/lex_out.y
  9. 32 0
      src/optimize.py
  10. 105 0
      src/parser.py
  11. 24 0
      src/peephole.l
  12. 135 0
      src/peephole.y
  13. 1 0
      src/todo.txt
  14. 33 0
      src/writer.py

+ 0 - 6
.gitignore

@@ -1,9 +1,3 @@
 *.swp
 *.pdf
-*.pyc
 *~
-*.o
-lex.yy.c
-y.tab.c
-y.tab.h
-parser

+ 1 - 3
QUESTIONS

@@ -1,3 +1 @@
-* Mag je voor een label er van uit gaan dat deze bestaat uit óf woord, óf 
-    $L[int] ?
-* Beter instructies matchen in Lex of in YACC?
+

+ 3 - 0
README

@@ -0,0 +1,3 @@
+Dependencies:
+The PLY parser requires the 'python-ply' package:
+sudo apt-get install python-ply

+ 9 - 0
src/.gitignore

@@ -0,0 +1,9 @@
+*.o
+*.s
+*.pyc
+lex.yy.c
+y.tab.c
+y.tab.h
+peephole
+parser.out
+parsetab.py

+ 13 - 10
src/Makefile

@@ -1,16 +1,19 @@
 CC=gcc
 LEX=lex
 YACC=yacc
-CFLAGS=-ll
 
-parser: yacc lex
-	$(CC) -c lex.yy.c y.tab.c
-	$(CC) -o $@ lex.yy.o y.tab.o $(CFLAGS)
+CFLAGS = -std=c99 -pedantic -Wall -D_POSIX_SOURCE -D_GNU_SOURCE $(PIC) -pipe
 
-lex: lex.l
-	$(LEX) lex.l
-	
-yacc: lex_out.y
-	$(YACC) -d lex_out.y
+all: peephole
 
-all: parser
+peephole: y.tab.o lex.yy.o
+	$(CC) -o $@ $^ -lm
+
+y.tab.c y.tab.h: peephole.y
+	$(YACC) -d $^
+
+lex.yy.c: peephole.l
+	$(LEX) $^
+
+clean:
+	rm -f lex.yy.* y.tab.* *.o peephole parser.out parsetab.py

+ 44 - 0
src/basic_block.py

@@ -0,0 +1,44 @@
+# TODO: Get all jump commands
+JUMP_COMMANDS = ['j', 'jal']
+
+def is_jump(statement):
+    '''Check if a statement is a jump command.'''
+    return statement[0] == 'command' and statement[1] in JUMP_COMMANDS
+
+def find_leaders(statements):
+    '''Determine the leaders, which are:
+       1. The first statement.
+       2. Any statement that is the target of a jump.
+       3. Any statement that follows directly follows a jump.'''
+    leaders = [0]
+    jump_target_labels = []
+
+    # Append statements following jumps and save jump target labels
+    for i, statement in enumerate(statements[1:]):
+        if is_jump(statement):
+            leaders.append(i + 2)
+            jump_target_labels.append(statement[2]['args'][0])
+            #print 'found jump:', i, statement
+
+    #print 'target labels:', jump_target_labels
+
+    # Append jump targets
+    for i, statement in enumerate(statements[1:]):
+        if i + 1 not in leaders \
+                and statement[0] == 'label' \
+                and statement[1] in jump_target_labels:
+            leaders.append(i + 1)
+            #print 'target:', i + 1, statements[i + 1]
+
+    return leaders
+
+def find_basic_blocks(statements):
+    '''Divide a statement list into basic blocks. Returns a list of basic
+    blocks, which are also statement lists.'''
+    leaders = find_leaders(statements)
+    blocks = []
+
+    for i in range(len(leaders) - 1):
+        blocks.append(statements[leaders[i]:leaders[i + 1]])
+
+    return blocks

+ 0 - 21
src/lex.l

@@ -1,21 +0,0 @@
-%{
-#include <stdio.h>
-#include "y.tab.h"
-%}
-reg     \$[a-zA-Z0-9]+
-label   [a-zA-Z0-9_\.]+
-int     [0-9]+
-%%
-
-[\n]                { return NL; }                              /* Newline */
-#.*                 { yylval.sval = yytext; return COMMENT; }   /* Comment */
-\..*                { yylval.sval = yytext; return DIRECTIVE; } /* Assembly directive */
-{label}:            { yylval.sval = yytext; return LABEL; }     /* Label */
-{reg}               { yylval.sval = yytext; return REG; }       /* Registry address */
-{int}               { yylval.ival = atoi(yytext); return INT; } /* Integer */
-{int}(\({reg}\))?   { yylval.sval = yytext; return OFFSET; }    /* Registry offset */
-[a-z0-9\.]+         { yylval.sval = yytext; return INSTR; }     /* Instruction */
-{label}             { yylval.sval = yytext; return REF; }       /* Label reference */
-[,]                 { return COMMA; }                           /* Comma */
-
-[ \t]+              ;                                           /* Ignore whitespace */

+ 0 - 65
src/lex_out.y

@@ -1,65 +0,0 @@
-%{
-#include <stdio.h>
-#include <stdlib.h>
-void yyerror(char*);
-%}
-
-%union {
-    int ival;
-    char *sval;
-}
-
-%token NL COMMA
-%token <ival> INT
-%token <sval> COMMENT DIRECTIVE REG LABEL OFFSET INSTR REF
-
-%%
-
-symb:
-    symb symb
-    | COMMENT {printf("Found a comment: %s\n", $1);}
-    | DIRECTIVE {printf("Found a directive: %s\n", $1);}
-    | REG {printf("Found a registry address: %s\n", $1);}
-    | LABEL {printf("Found a label: %s\n", $1);}
-    | REF {printf("Found a label reference: %s\n", $1);}
-    | INT {printf("Found an integer: %d\n", $1);}
-    | OFFSET {printf("Found an offset registry address: %s\n", $1);}
-    | INSTR {printf("Found an instruction: %s\n", $1);}
-    | COMMA {printf("Found a comma\n");}
-    | NL {printf("Found a newline\n");}
-    ;
-%%
-
-extern int yylex();
-extern int yyparse();
-extern FILE *yyin;
-
-main(int argc, const char* argv[])
-{
-    if (argc < 2)
-    {
-        printf("No file specified");
-        exit(-1);
-    }
-
-    // open a file handle to a particular file:
-	FILE *myfile = fopen(argv[1], "r");
-	// make sure it is valid:
-	if (!myfile) {
-		printf("Cannot open %s\n", argv[1]);
-		return -1;
-	}
-	// set lex to read from it instead of defaulting to STDIN:
-	yyin = myfile;
-
-	// parse through the input until there is no more:
-	do {
-		yyparse();
-	} while (!feof(yyin));
-}
-
-void yyerror(char *s)
-{
-    printf("Found error: %s\n", s);
-    exit(-1);
-}

+ 32 - 0
src/optimize.py

@@ -0,0 +1,32 @@
+#!/usr/bin/python
+from parser import parse_file
+from basic_block import find_basic_blocks
+from writer import write_statements
+
+if __name__ == '__main__':
+    from sys import argv, exit
+
+    if len(argv) < 2:
+        print 'Usage: python %s FILE' % argv[0]
+        exit(1)
+
+    statements = parse_file(argv[1])
+    blocks = find_basic_blocks(statements)
+    out = write_statements(statements)
+
+    statement_no = 1
+
+    for i, block in enumerate(blocks):
+        print 'basic block %d:' % i
+
+        for statement in block:
+            print statement_no, statement
+            statement_no += 1
+
+    print '\nOut:'
+    print out
+
+    if len(argv) > 2:
+        f = open(argv[2], 'w+')
+        f.write(out)
+        f.close()

+ 105 - 0
src/parser.py

@@ -0,0 +1,105 @@
+import ply.lex as lex
+import ply.yacc as yacc
+
+# Global statements administration
+statements = []
+
+tokens = ('NEWLINE', 'WORD', 'COMMENT', 'DIRECTIVE', 'COMMA', 'COLON')
+
+# Tokens
+def t_NEWLINE(t):
+    r'\n+'
+    t.lexer.lineno += t.value.count('\n')
+    return t
+
+def t_COLON(t):
+    r':'
+    return t
+
+def t_COMMA(t):
+    r','
+    return t
+
+def t_COMMENT(t):
+    r'\#.*'
+    t.value = t.value[1:]
+    return t
+
+def t_DIRECTIVE(t):
+    r'\..*'
+    return t
+
+def t_offset_address(t):
+    r'[0-9]+(\([a-zA-Z0-9$_.]+\))?'
+    t.type = 'WORD'
+    return t
+
+def t_WORD(t):
+    r'[a-zA-Z0-9$_.]+'
+    return t
+
+# Ignore whitespaces
+t_ignore = ' \t'
+
+def t_error(t):
+    print('Illegal character "%s"' % t.value[0])
+    t.lexer.skip(1)
+
+# Build the lexer
+lexer = lex.lex()
+
+# Parsing rules
+start = 'input'
+
+def p_input(p):
+    '''input :
+             | input line'''
+    pass
+
+def p_line_instruction(p):
+    'line : instruction NEWLINE'
+    pass
+
+def p_line_comment(p):
+    'line : COMMENT NEWLINE'
+    statements.append(('comment', p[1], {'inline': False}))
+
+def p_line_inline_comment(p):
+    'line : instruction COMMENT NEWLINE'
+    statements.append(('comment', p[2], {'inline': True}))
+
+def p_instruction_command(p):
+    'instruction : command'
+    pass
+
+def p_instruction_directive(p):
+    'instruction : DIRECTIVE'
+    statements.append(('directive', p[1], None))
+
+def p_instruction_label(p):
+    'instruction : WORD COLON'
+    statements.append(('label', p[1], None))
+
+def p_command(p):
+    '''command : WORD WORD COMMA WORD COMMA WORD
+               | WORD WORD COMMA WORD
+               | WORD WORD'''
+    statements.append(('command', p[1], {'args': list(p)[2::2]}))
+
+def p_error(p):
+    print 'Syntax error at "%s" on line %d' % (p.value, lexer.lineno)
+
+yacc.yacc()
+
+def parse_file(filename):
+    global statements
+
+    statements = []
+
+    try:
+        content = open(filename).read()
+        yacc.parse(content)
+    except IOError:
+        print 'File "%s" could not be opened' % filename
+
+    return statements

+ 24 - 0
src/peephole.l

@@ -0,0 +1,24 @@
+%{
+#include <stdio.h>
+#include <string.h>
+#include "y.tab.h"
+
+extern int lineno;
+%}
+
+%option noyywrap
+
+word    [a-zA-Z0-9$_.]+
+int     [0-9]+
+
+%%
+
+\n                  { lineno++; printf("ikmatchhemwel!"); return NEWLINE; }
+:                   { return COLON; }
+,                   { return COMMA; }
+#.*                 { yylval.sval = strdup(yytext); return COMMENT; }
+\..*                { yylval.sval = strdup(yytext); return DIRECTIVE; }
+{word}              { yylval.sval = strdup(yytext); return WORD; }
+{int}(\({word}\))?  { yylval.sval = strdup(yytext); return WORD; }
+
+[ \t]+              ;

+ 135 - 0
src/peephole.y

@@ -0,0 +1,135 @@
+%{
+#include <stdio.h>
+#include <stdlib.h>
+
+// Instruction types
+#define TYPE_COMMENT 0
+#define TYPE_INLINE_COMMENT 1
+#define TYPE_DIRECTIVE 2
+#define TYPE_LABEL 3
+#define TYPE_CMD 4
+
+typedef struct line {
+    // Type:
+    int type;
+    char *name;
+    int argc;
+    char **argv;
+
+    struct line *next;
+} line;
+
+void yyerror(char *error);
+extern int yylex(void);
+void add_line(int type, char *name, int argc, char **argv);
+char **malloc_args(int argc);
+
+line *first_line, *last_line;
+int lineno = 0;
+
+%}
+
+%union {
+    char *sval;
+}
+
+%token <sval> COMMENT DIRECTIVE WORD
+%token NEWLINE COMMA COLON
+
+%%
+
+input:
+    /* Empty */
+    | input line
+    ;
+
+line:
+    NEWLINE
+    | COMMENT NEWLINE               { add_line(TYPE_COMMENT, $1, 0, NULL); }
+    | instruction NEWLINE
+    | instruction COMMENT NEWLINE   { add_line(TYPE_INLINE_COMMENT, $2, 0, NULL); }
+    ;
+
+instruction:
+    command
+    | DIRECTIVE                     { add_line(TYPE_DIRECTIVE, $1, 0, NULL); }
+    | WORD COLON                    { add_line(TYPE_LABEL, $1, 0, NULL); }
+    | error
+    ;
+
+command:
+    WORD WORD COMMA WORD COMMA WORD {
+            char **argv = malloc_args(3);
+            argv[0] = $2;
+            argv[1] = $4;
+            argv[2] = $6;
+            add_line(TYPE_CMD, $1, 3, argv);
+        }
+    | WORD WORD COMMA WORD {
+            char **argv = malloc_args(2);
+            argv[0] = $2;
+            argv[1] = $4;
+            add_line(TYPE_CMD, $1, 2, argv);
+        }
+    | WORD WORD {
+            char **argv = malloc_args(1);
+            argv[0] = $2;
+            add_line(TYPE_CMD, $1, 1, argv);
+        }
+    ;
+
+%%
+
+extern int yylex();
+extern int yyparse();
+extern FILE *yyin;
+
+/*int main(void) {
+    return yyparse();
+}*/
+
+int main(int argc, const char *argv[]) {
+    if( argc < 2 ) {
+        printf("No file specified");
+        exit(-1);
+    }
+
+    // open a file handle to a particular file:
+	FILE *myfile = fopen(argv[1], "r");
+	// make sure it is valid:
+	if( !myfile ) {
+		printf("Cannot open %s\n", argv[1]);
+		return -1;
+	}
+	// set lex to read from it instead of defaulting to STDIN:
+	yyin = myfile;
+
+	// parse through the input until there is no more:
+	do {
+		yyparse();
+	} while( !feof(yyin) );
+}
+
+void yyerror(char *error) {
+    fprintf(stderr, "Error at line %d: %s\n", lineno, error);
+}
+
+void add_line(int type, char *name, int argc, char **argv) {
+    line *l = (line*)malloc(sizeof(line));
+    printf("%d: %s\n", lineno, name);
+
+    l->argc = argc;
+    l->argv = argv;
+
+    if( last_line == NULL ) {
+        // First line
+        first_line = last_line = l;
+    } else {
+        // Add line to linked list
+        last_line = last_line->next = l;
+    }
+}
+
+char **malloc_args(int argc) {
+    return (char **)malloc(3 * sizeof(char *));
+}

+ 1 - 0
src/todo.txt

@@ -0,0 +1 @@
+* Apart python script maken die de generator genereert dmv config file

+ 33 - 0
src/writer.py

@@ -0,0 +1,33 @@
+def write_statements(statements):
+    '''Write a list of statements to valid assembly code.'''
+    s = '';
+
+    for i, statement in enumerate(statements):
+        statement_type, name, args = statement
+        newline = '\n' if i else ''
+
+        if statement_type == 'label':
+            line = name + ':'
+        elif statement_type == 'comment':
+            line = '#' + name
+
+            if args['inline']:
+                newline = '  '
+        elif statement_type == 'directive':
+            line = '\t' + name
+        elif statement_type == 'command':
+            line = '\t' + name + '\t' + ','.join(args['args'])
+        else:
+            raise Exception('Unsupported statement type "%s"' % statement_type)
+
+        s += newline + line
+
+    return s
+
+def write_to_file(filename, statements):
+    '''Convert a list of statements to valid assembly code and write it to a
+    file.'''
+    s = write_statements(statements)
+    f = open(filename, 'w+')
+    f.write(s)
+    f.close()