├── images
├── class.png
├── label.png
├── type.png
├── unit.png
├── category.png
├── constant.png
├── folder.png
├── function.png
├── include.png
├── source.png
├── variable.png
├── assembler.png
├── interface.png
├── procedure.png
├── implementation.png
└── copyright.txt
├── fonts
├── NotoSans.ttf
├── DejaVuSansMono.ttf
├── Noto.license
└── DejaVu.license
├── asm
├── run_coco
├── LisaAsm.keywords
├── LisaAsm.ebnf
└── Parser.frame
├── syntax
├── run_coco
├── LisaPascal.keywords
├── Parser.frame
└── LisaPascal.ebnf
├── LisaAsm.pro
├── LisaPascal.pro
├── CodeNavigator.qrc
├── AsmSynTree.h
├── AsmSynTree.cpp
├── LisaToken.cpp
├── CodeNavigator.pro
├── Converter.h
├── BUSY
├── LisaRowCol.h
├── LisaToken.h
├── LisaLexer.h
├── LisaHighlighter.h
├── AsmToken.h
├── LisaTokenType.h
├── AsmLexer.h
├── LisaFileSystem.h
├── AsmTokenType.h
├── LisaCodeNavigator.h
├── LisaSynTree.h
├── LisaPpLexer.h
├── AsmPpLexer.h
├── LisaParser.h
├── AsmParser.h
├── LisaAsm.cpp
├── LisaSynTree.cpp
├── Converter.cpp
├── AsmPpLexer.cpp
├── LICENSE.LGPLv3
├── Readme.md
├── LisaCodeModel.h
├── LisaHighlighter.cpp
├── LisaLexer.cpp
└── main.cpp
/images/class.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rochus-keller/LisaPascal/HEAD/images/class.png
--------------------------------------------------------------------------------
/images/label.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rochus-keller/LisaPascal/HEAD/images/label.png
--------------------------------------------------------------------------------
/images/type.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rochus-keller/LisaPascal/HEAD/images/type.png
--------------------------------------------------------------------------------
/images/unit.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rochus-keller/LisaPascal/HEAD/images/unit.png
--------------------------------------------------------------------------------
/fonts/NotoSans.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rochus-keller/LisaPascal/HEAD/fonts/NotoSans.ttf
--------------------------------------------------------------------------------
/images/category.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rochus-keller/LisaPascal/HEAD/images/category.png
--------------------------------------------------------------------------------
/images/constant.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rochus-keller/LisaPascal/HEAD/images/constant.png
--------------------------------------------------------------------------------
/images/folder.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rochus-keller/LisaPascal/HEAD/images/folder.png
--------------------------------------------------------------------------------
/images/function.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rochus-keller/LisaPascal/HEAD/images/function.png
--------------------------------------------------------------------------------
/images/include.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rochus-keller/LisaPascal/HEAD/images/include.png
--------------------------------------------------------------------------------
/images/source.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rochus-keller/LisaPascal/HEAD/images/source.png
--------------------------------------------------------------------------------
/images/variable.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rochus-keller/LisaPascal/HEAD/images/variable.png
--------------------------------------------------------------------------------
/images/assembler.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rochus-keller/LisaPascal/HEAD/images/assembler.png
--------------------------------------------------------------------------------
/images/interface.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rochus-keller/LisaPascal/HEAD/images/interface.png
--------------------------------------------------------------------------------
/images/procedure.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rochus-keller/LisaPascal/HEAD/images/procedure.png
--------------------------------------------------------------------------------
/fonts/DejaVuSansMono.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rochus-keller/LisaPascal/HEAD/fonts/DejaVuSansMono.ttf
--------------------------------------------------------------------------------
/images/implementation.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rochus-keller/LisaPascal/HEAD/images/implementation.png
--------------------------------------------------------------------------------
/asm/run_coco:
--------------------------------------------------------------------------------
1 | ../../Coco/Coco ./LisaAsm.atg -o . -namespace Asm
2 |
3 | mv ./Parser.h ../AsmParser.h
4 | mv ./Parser.cpp ../AsmParser.cpp
5 |
6 | mv ./AsmSynTree.h ..
7 | mv ./AsmSynTree.cpp ..
8 |
9 | mv ./AsmTokenType.h ..
10 | mv ./AsmTokenType.cpp ..
11 |
12 | rm ./LisaAsm.atg
13 |
--------------------------------------------------------------------------------
/syntax/run_coco:
--------------------------------------------------------------------------------
1 | ../../Coco/Coco ./LisaPascal.atg -trace FP -o . -namespace Lisa > ./coco_out.txt
2 |
3 | mv ./Parser.h ../LisaParser.h
4 | mv ./Parser.cpp ../LisaParser.cpp
5 |
6 | mv ./LisaSynTree.h ..
7 | mv ./LisaSynTree.cpp ..
8 |
9 | mv ./LisaTokenType.h ..
10 | mv ./LisaTokenType.cpp ..
11 |
--------------------------------------------------------------------------------
/syntax/LisaPascal.keywords:
--------------------------------------------------------------------------------
1 | and
2 | array
3 | begin
4 | case
5 | const
6 | creation
7 | div
8 | do
9 | downto
10 | else
11 | end
12 | file
13 | for
14 | function
15 | goto
16 | if
17 | implementation
18 | in
19 | interface
20 | intrinsic
21 | label
22 | mod
23 | nil
24 | not
25 | of
26 | or
27 | otherwise
28 | packed
29 | procedure
30 | program
31 | record
32 | repeat
33 | set
34 | string
35 | then
36 | to
37 | type
38 | unit
39 | until
40 | uses
41 | var
42 | while
43 | with
44 | subclass
45 | methods
46 | creation
47 | intrinsic
48 | shared
49 |
--------------------------------------------------------------------------------
/LisaAsm.pro:
--------------------------------------------------------------------------------
1 | QT += core
2 | QT -= gui
3 |
4 | TARGET = LisaAsm
5 | CONFIG += console
6 | CONFIG -= app_bundle
7 |
8 | TEMPLATE = app
9 |
10 | INCLUDEPATH += ..
11 | DEFINES += _DEBUG
12 |
13 | SOURCES += \
14 | LisaAsm.cpp \
15 | AsmTokenType.cpp \
16 | AsmLexer.cpp \
17 | AsmPpLexer.cpp \
18 | AsmSynTree.cpp \
19 | AsmParser.cpp \
20 | LisaFileSystem.cpp \
21 | LisaLexer.cpp \
22 | LisaTokenType.cpp \
23 | LisaToken.cpp
24 |
25 | HEADERS += \
26 | AsmToken.h \
27 | AsmTokenType.h \
28 | AsmLexer.h \
29 | AsmPpLexer.h \
30 | AsmSynTree.h \
31 | AsmParser.h \
32 | LisaFileSystem.h \
33 | LisaLexer.h \
34 | LisaTokenType.h \
35 | LisaToken.h
36 |
37 |
38 |
--------------------------------------------------------------------------------
/LisaPascal.pro:
--------------------------------------------------------------------------------
1 | QT += core
2 | QT -= gui
3 |
4 | TARGET = LisaPascal
5 | CONFIG += console
6 | CONFIG -= app_bundle
7 |
8 | TEMPLATE = app
9 |
10 | INCLUDEPATH += ..
11 | DEFINES += _DEBUG
12 |
13 | SOURCES += main.cpp \
14 | LisaLexer.cpp \
15 | LisaParser.cpp \
16 | LisaSynTree.cpp \
17 | LisaTokenType.cpp \
18 | Converter.cpp \
19 | LisaFileSystem.cpp \
20 | LisaPpLexer.cpp \
21 | LisaToken.cpp \
22 | AsmLexer.cpp \
23 | AsmTokenType.cpp
24 |
25 | HEADERS += \
26 | LisaLexer.h \
27 | LisaParser.h \
28 | LisaSynTree.h \
29 | LisaToken.h \
30 | LisaTokenType.h \
31 | Converter.h \
32 | LisaFileSystem.h \
33 | LisaPpLexer.h \
34 | AsmLexer.h \
35 | AsmTokenType.h
36 |
--------------------------------------------------------------------------------
/CodeNavigator.qrc:
--------------------------------------------------------------------------------
1 |
2 |
3 | images/folder.png
4 | images/unit.png
5 | images/include.png
6 | fonts/DejaVuSansMono.ttf
7 | fonts/NotoSans.ttf
8 | images/constant.png
9 | images/function.png
10 | images/implementation.png
11 | images/interface.png
12 | images/label.png
13 | images/procedure.png
14 | images/type.png
15 | images/variable.png
16 | images/category.png
17 | images/class.png
18 | images/source.png
19 | images/assembler.png
20 |
21 |
22 |
--------------------------------------------------------------------------------
/AsmSynTree.h:
--------------------------------------------------------------------------------
1 | #ifndef __ASM_SYNTREE__
2 | #define __ASM_SYNTREE__
3 | // This file was automatically generated by EbnfStudio; don't modify it!
4 |
5 | #include
6 | #include
7 | #include
8 |
9 | namespace Asm {
10 |
11 | struct SynTree {
12 | enum ParserRule {
13 | R_First = TT_Max + 1,
14 | R_addrop,
15 | R_argument,
16 | R_comment_,
17 | R_directive,
18 | R_expression,
19 | R_factor,
20 | R_filename,
21 | R_line,
22 | R_macrodef,
23 | R_mnemonic,
24 | R_op,
25 | R_program,
26 | R_reg,
27 | R_size,
28 | R_statement,
29 | R_term,
30 | R_Last
31 | };
32 | SynTree(quint16 r = Tok_Invalid, const Token& = Token() );
33 | SynTree(const Token& t ):d_tok(t){}
34 | ~SynTree() { foreach(SynTree* n, d_children) delete n; }
35 |
36 | static const char* rToStr( quint16 r );
37 |
38 | Asm::Token d_tok;
39 | QList d_children;
40 | };
41 |
42 | }
43 | #endif // __ASM_SYNTREE__
44 |
--------------------------------------------------------------------------------
/AsmSynTree.cpp:
--------------------------------------------------------------------------------
1 | // This file was automatically generated by EbnfStudio; don't modify it!
2 | #include "AsmSynTree.h"
3 | using namespace Asm;
4 |
5 | SynTree::SynTree(quint16 r, const Token& t ):d_tok(r){
6 | d_tok.d_lineNr = t.d_lineNr;
7 | d_tok.d_colNr = t.d_colNr;
8 | d_tok.d_sourcePath = t.d_sourcePath;
9 | }
10 |
11 | const char* SynTree::rToStr( quint16 r ) {
12 | switch(r) {
13 | case R_addrop: return "addrop";
14 | case R_argument: return "argument";
15 | case R_comment_: return "comment";
16 | case R_directive: return "directive";
17 | case R_expression: return "expression";
18 | case R_factor: return "factor";
19 | case R_filename: return "filename";
20 | case R_line: return "line";
21 | case R_macrodef: return "macrodef";
22 | case R_mnemonic: return "mnemonic";
23 | case R_op: return "op";
24 | case R_program: return "program";
25 | case R_reg: return "reg";
26 | case R_size: return "size";
27 | case R_statement: return "statement";
28 | case R_term: return "term";
29 | default: if(r
20 | #include
21 |
22 | static QHash d_symbols;
23 |
24 |
25 | const char* Lisa::Token::toId(const QByteArray& ident)
26 | {
27 | if( ident.isEmpty() )
28 | return "";
29 | const QByteArray lc = ident.toLower();
30 | QByteArray& sym = d_symbols[lc];
31 | if( sym.isEmpty() )
32 | sym = lc;
33 | return sym.constData();
34 | }
35 |
--------------------------------------------------------------------------------
/CodeNavigator.pro:
--------------------------------------------------------------------------------
1 | QT += core gui widgets
2 |
3 | TARGET = LisaCodeNavigator
4 | TEMPLATE = app
5 |
6 | INCLUDEPATH += ..
7 |
8 | CONFIG(debug, debug|release) {
9 | DEFINES += _DEBUG
10 | }
11 |
12 | !win32{
13 | QMAKE_CXXFLAGS += -Wno-reorder -Wno-unused-parameter -Wno-unused-function -Wno-unused-variable
14 | }
15 |
16 | HEADERS += \
17 | LisaLexer.h \
18 | LisaSynTree.h \
19 | LisaToken.h \
20 | LisaTokenType.h \
21 | LisaHighlighter.h \
22 | LisaCodeNavigator.h \
23 | LisaCodeModel.h \
24 | LisaParser.h \
25 | LisaRowCol.h \
26 | LisaFileSystem.h \
27 | LisaPpLexer.h \
28 | AsmLexer.h \
29 | AsmTokenType.h \
30 | AsmToken.h \
31 | AsmParser.h \
32 | AsmPpLexer.h \
33 | AsmSynTree.h
34 |
35 | SOURCES += \
36 | LisaLexer.cpp \
37 | LisaSynTree.cpp \
38 | LisaTokenType.cpp \
39 | LisaHighlighter.cpp \
40 | LisaCodeNavigator.cpp \
41 | LisaCodeModel.cpp \
42 | LisaParser.cpp \
43 | LisaToken.cpp \
44 | LisaFileSystem.cpp \
45 | LisaPpLexer.cpp \
46 | AsmLexer.cpp \
47 | AsmTokenType.cpp \
48 | AsmParser.cpp \
49 | AsmPpLexer.cpp \
50 | AsmSynTree.cpp
51 |
52 | RESOURCES += \
53 | CodeNavigator.qrc
54 |
55 |
56 |
57 |
58 |
--------------------------------------------------------------------------------
/Converter.h:
--------------------------------------------------------------------------------
1 | #ifndef CONVERTER_H
2 | #define CONVERTER_H
3 |
4 | /*
5 | ** Copyright (C) 2023 Rochus Keller (me@rochus-keller.ch)
6 | **
7 | ** This file is part of the LisaPascal project.
8 | **
9 | ** $QT_BEGIN_LICENSE:LGPL21$
10 | ** GNU Lesser General Public License Usage
11 | ** This file may be used under the terms of the GNU Lesser
12 | ** General Public License version 2.1 or version 3 as published by the Free
13 | ** Software Foundation and appearing in the file LICENSE.LGPLv21 and
14 | ** LICENSE.LGPLv3 included in the packaging of this file. Please review the
15 | ** following information to ensure the GNU Lesser General Public License
16 | ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
17 | ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 | */
19 |
20 | #include
21 | #include
22 |
23 | namespace Lisa
24 | {
25 | class Converter
26 | {
27 | public:
28 | Converter();
29 | static QStringList collectFiles(const QDir& dir , const QStringList& suffix);
30 | static bool convert( const QDir& fromDir, const QDir& toDir );
31 |
32 | enum { Unknown, FullUnit, PartialUnit, AnyPascal };
33 | static int detectPascal( QIODevice* in );
34 | static bool detectAsm( QIODevice* in );
35 | static bool detectScript(QIODevice* in );
36 | private:
37 |
38 | };
39 | }
40 |
41 | #endif // CONVERTER_H
42 |
--------------------------------------------------------------------------------
/BUSY:
--------------------------------------------------------------------------------
1 | # author: Rochus Keller (me@rochus-keller.ch)
2 | # License: GPL
3 | # See https://github.com/rochus-keller/LisaPascal#how-to-build-the-parser-and-code-navigator and
4 | # https://github.com/rochus-keller/BUSY/blob/main/README.md on how to use this file
5 |
6 | if busy_version < "2023-01-15" {
7 | error("this version of BUSY is not compatible with this build")
8 | }
9 |
10 | submod qt = ../LeanQt (HAVE_ITEMVIEWS)
11 |
12 | let run_moc : Moc {
13 | .sources += [
14 | ./LisaCodeNavigator.h
15 | ./LisaCodeModel.h
16 | ]
17 | }
18 |
19 | let run_rcc : Rcc {
20 | .deps += qt.copy_rcc;
21 | .tool_dir = root_build_dir + relpath(qt);
22 | .sources += ./CodeNavigator.qrc
23 | }
24 |
25 | let exe ! : Executable {
26 | .configs += [ qt.qt_client_config ]
27 | .sources = [
28 | ./LisaLexer.cpp
29 | ./LisaSynTree.cpp
30 | ./LisaTokenType.cpp
31 | ./LisaHighlighter.cpp
32 | ./LisaCodeNavigator.cpp
33 | ./LisaCodeModel.cpp
34 | ./LisaParser.cpp
35 | ./LisaToken.cpp
36 | ./LisaFileSystem.cpp
37 | ./LisaPpLexer.cpp
38 | ./AsmLexer.cpp
39 | ./AsmTokenType.cpp
40 | ./AsmParser.cpp
41 | ./AsmPpLexer.cpp
42 | ./AsmSynTree.cpp
43 | ]
44 | .include_dirs += [ . .. ]
45 | .deps += [ qt.copy_rcc qt.libqt run_rcc run_moc ]
46 | if target_os == `win32 {
47 | .deps += qt.libqtwinmain
48 | }
49 | .name = "LisaCodeNavigator"
50 | }
51 |
52 |
53 |
--------------------------------------------------------------------------------
/LisaRowCol.h:
--------------------------------------------------------------------------------
1 | #ifndef LISAROWCOL
2 | #define LISAROWCOL
3 |
4 | /*
5 | ** Copyright (C) 2023 Rochus Keller (me@rochus-keller.ch)
6 | **
7 | ** This file is part of the LisaPascal project.
8 | **
9 | ** $QT_BEGIN_LICENSE:LGPL21$
10 | ** GNU Lesser General Public License Usage
11 | ** This file may be used under the terms of the GNU Lesser
12 | ** General Public License version 2.1 or version 3 as published by the Free
13 | ** Software Foundation and appearing in the file LICENSE.LGPLv21 and
14 | ** LICENSE.LGPLv3 included in the packaging of this file. Please review the
15 | ** following information to ensure the GNU Lesser General Public License
16 | ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
17 | ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 |
19 | */
20 |
21 | #include
22 | #include
23 |
24 | namespace Lisa
25 | {
26 | struct RowCol
27 | {
28 | enum { ROW_BIT_LEN = 19, COL_BIT_LEN = 32 - ROW_BIT_LEN };
29 | quint32 d_row : ROW_BIT_LEN;
30 | quint32 d_col : COL_BIT_LEN;
31 | RowCol(int row = 0, int col = 0):d_row(row),d_col(col){}
32 | quint32 packed() const { return ( d_row << COL_BIT_LEN ) | d_col; }
33 | bool operator==(const RowCol& rhs) const {
34 | return d_row == rhs.d_row && d_col == rhs.d_col;
35 | }
36 | bool operator<(const RowCol& rhs) const {
37 | return packed() < rhs.packed();
38 | }
39 | };
40 | typedef QPair Range;
41 | typedef QList Ranges;
42 | struct FilePos
43 | {
44 | RowCol d_pos;
45 | QString d_filePath;
46 | FilePos(RowCol pos = RowCol(), const QString& path = QString()):d_pos(pos),d_filePath(path){}
47 | };
48 | }
49 |
50 | #endif // LISAROWCOL
51 |
52 |
--------------------------------------------------------------------------------
/LisaToken.h:
--------------------------------------------------------------------------------
1 | #ifndef LISATOKEN_H
2 | #define LISATOKEN_H
3 |
4 | /*
5 | ** Copyright (C) 2023 Rochus Keller (me@rochus-keller.ch)
6 | **
7 | ** This file is part of the LisaPascal project.
8 | **
9 | ** $QT_BEGIN_LICENSE:LGPL21$
10 | ** GNU Lesser General Public License Usage
11 | ** This file may be used under the terms of the GNU Lesser
12 | ** General Public License version 2.1 or version 3 as published by the Free
13 | ** Software Foundation and appearing in the file LICENSE.LGPLv21 and
14 | ** LICENSE.LGPLv3 included in the packaging of this file. Please review the
15 | ** following information to ensure the GNU Lesser General Public License
16 | ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
17 | ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 |
19 | */
20 |
21 | #include
22 | #include
23 | #include "LisaRowCol.h"
24 |
25 | namespace Lisa
26 | {
27 | struct Token
28 | {
29 | #ifdef _DEBUG
30 | union
31 | {
32 | int d_type; // TokenType
33 | TokenType d_tokenType;
34 | };
35 | #else
36 | quint8 d_type; // TokenType
37 | #endif
38 | quint8 d_len;
39 | quint32 d_lineNr : RowCol::ROW_BIT_LEN;
40 | quint32 d_colNr : RowCol::COL_BIT_LEN;
41 | QString d_sourcePath;
42 |
43 | QByteArray d_val;
44 | const char* d_id; // lower-case internalized version of d_val
45 | Token(quint16 t = Tok_Invalid, quint32 line = 0, quint16 col = 0, const QByteArray& val = QByteArray()):
46 | d_type(t), d_lineNr(line),d_colNr(col),d_val(val),d_len(0),d_id(0){}
47 | bool isValid() const { return d_type != Tok_Eof && d_type != Tok_Invalid; }
48 | RowCol toLoc() const { return RowCol(d_lineNr,d_colNr); }
49 |
50 | static const char* toId(const QByteArray& ident);
51 | };
52 | }
53 |
54 | #endif // LISATOKEN_H
55 |
--------------------------------------------------------------------------------
/LisaLexer.h:
--------------------------------------------------------------------------------
1 | #ifndef _LISA_LEXER
2 | #define _LISA_LEXER
3 |
4 | /*
5 | ** Copyright (C) 2023 Rochus Keller (me@rochus-keller.ch)
6 | **
7 | ** This file is part of the LisaPascal project.
8 | **
9 | ** $QT_BEGIN_LICENSE:LGPL21$
10 | ** GNU Lesser General Public License Usage
11 | ** This file may be used under the terms of the GNU Lesser
12 | ** General Public License version 2.1 or version 3 as published by the Free
13 | ** Software Foundation and appearing in the file LICENSE.LGPLv21 and
14 | ** LICENSE.LGPLv3 included in the packaging of this file. Please review the
15 | ** following information to ensure the GNU Lesser General Public License
16 | ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
17 | ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 | */
19 |
20 | #include
21 | #include
22 | #include
23 |
24 | namespace Lisa
25 | {
26 |
27 | class Lexer
28 | {
29 | public:
30 | Lexer();
31 | ~Lexer();
32 |
33 | void setStream(QIODevice*, const QString& filePath = QString());
34 | QIODevice* getDevice() const { return d_in; }
35 | void setIgnoreComments( bool b ) { d_ignoreComments = b; }
36 | void setPackComments( bool b ) { d_packComments = b; }
37 |
38 | Token nextToken();
39 | Token peekToken(quint8 lookAhead = 1);
40 | QList tokens( const QString& code );
41 | quint32 getSloc() const { return d_sloc; }
42 | protected:
43 | Token nextTokenImp();
44 | int skipWhiteSpace();
45 | void nextLine();
46 | int lookAhead(int off = 1) const;
47 | Token token(TokenType tt, int len = 1, const QByteArray &val = QByteArray());
48 | Token ident();
49 | Token number();
50 | Token hexnumber();
51 | Token comment(bool brace = false);
52 | Token string();
53 | void countLine();
54 | private:
55 | QIODevice* d_in;
56 | quint32 d_lineNr;
57 | quint16 d_colNr;
58 | QByteArray d_line;
59 | QList d_buffer;
60 | Token d_lastToken;
61 | quint32 d_sloc; // number of lines of code without empty or comment lines
62 | QString d_filePath;
63 | bool d_ignoreComments; // don't deliver comment tokens
64 | bool d_packComments; // Only deliver one Tok_Comment for /**/ instead of Tok_Lcmt and Tok_Rcmt
65 | bool d_lineCounted;
66 | };
67 |
68 | }
69 |
70 | #endif
71 |
--------------------------------------------------------------------------------
/LisaHighlighter.h:
--------------------------------------------------------------------------------
1 | #ifndef LISAHIGHLIGHTER_H
2 | #define LISAHIGHLIGHTER_H
3 |
4 | /*
5 | * Copyright 2023 Rochus Keller
6 | *
7 | * This file is part of the Lisa Pascal Navigator application.
8 | *
9 | * The following is the license that applies to this copy of the
10 | * application. For a license to use the library under conditions
11 | * other than those described here, please email to me@rochus-keller.ch.
12 | *
13 | * GNU General Public License Usage
14 | * This file may be used under the terms of the GNU General Public
15 | * License (GPL) versions 2.0 or 3.0 as published by the Free Software
16 | * Foundation and appearing in the file LICENSE.GPL included in
17 | * the packaging of this file. Please review the following information
18 | * to ensure GNU General Public Licensing requirements will be met:
19 | * http://www.fsf.org/licensing/licenses/info/GPLv2.html and
20 | * http://www.gnu.org/copyleft/gpl.html.
21 | */
22 |
23 | #include
24 | #include
25 |
26 | namespace Lisa
27 | {
28 | class PascalPainter : public QSyntaxHighlighter
29 | {
30 | public:
31 | enum { TokenProp = QTextFormat::UserProperty };
32 | explicit PascalPainter(QObject *parent = 0);
33 | void addBuiltIn(const QByteArray& bi);
34 | void addKeyword(const QByteArray& kw);
35 |
36 | protected:
37 | QTextCharFormat formatForCategory(int) const;
38 |
39 | // overrides
40 | void highlightBlock(const QString &text);
41 |
42 | private:
43 | enum Category { C_Num, C_Str, C_Kw, C_Type, C_Ident, C_Op, C_Pp, C_Cmt, C_Label, C_Max };
44 | QTextCharFormat d_format[C_Max];
45 | QSet d_builtins, d_keywords;
46 | };
47 |
48 | class AsmPainter : public QSyntaxHighlighter
49 | {
50 | public:
51 | AsmPainter(QObject* parent);
52 |
53 | // overrides
54 | void highlightBlock(const QString &text);
55 | private:
56 | enum Category { C_Num, C_Str, C_Kw, C_Ident, C_Op, C_Pp, C_Cmt, C_Label, C_Max };
57 | QTextCharFormat d_format[C_Max];
58 | };
59 |
60 | class LogPainter : public QSyntaxHighlighter
61 | {
62 | public:
63 | explicit LogPainter(QTextDocument *parent = 0);
64 | protected:
65 | // overrides
66 | void highlightBlock(const QString &text);
67 | };
68 | }
69 |
70 | #endif // LISAHIGHLIGHTER_H
71 |
--------------------------------------------------------------------------------
/AsmToken.h:
--------------------------------------------------------------------------------
1 | #ifndef LISAASMTOKEN
2 | #define LISAASMTOKEN
3 |
4 | /*
5 | ** Copyright (C) 2023 Rochus Keller (me@rochus-keller.ch)
6 | **
7 | ** This file is part of the LisaPascal project.
8 | **
9 | ** $QT_BEGIN_LICENSE:LGPL21$
10 | ** GNU Lesser General Public License Usage
11 | ** This file may be used under the terms of the GNU Lesser
12 | ** General Public License version 2.1 or version 3 as published by the Free
13 | ** Software Foundation and appearing in the file LICENSE.LGPLv21 and
14 | ** LICENSE.LGPLv3 included in the packaging of this file. Please review the
15 | ** following information to ensure the GNU Lesser General Public License
16 | ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
17 | ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 | */
19 |
20 | #include "AsmTokenType.h"
21 | #include "LisaRowCol.h"
22 |
23 | namespace Asm
24 | {
25 | using namespace Lisa;
26 |
27 | struct Token
28 | {
29 | #ifdef _DEBUG
30 | union
31 | {
32 | int d_type; // TokenType
33 | TokenType d_tokenType;
34 | };
35 | #else
36 | quint8 d_type; // TokenType
37 | #endif
38 | quint32 d_lineNr : RowCol::ROW_BIT_LEN;
39 | quint32 d_colNr : RowCol::COL_BIT_LEN -1;
40 | quint32 d_dotPrefix : 1;
41 | QString d_sourcePath;
42 |
43 | QByteArray d_val;
44 | Token(quint16 t = 0, quint32 line = 0, quint16 col = 0, const QByteArray& val = QByteArray()):
45 | d_type(t), d_lineNr(line),d_colNr(col),d_val(val),d_dotPrefix(0){}
46 | bool isValid() const { return d_type != Tok_Eof && d_type != Tok_Invalid; }
47 | RowCol toLoc() const { return RowCol(d_lineNr,d_colNr); }
48 | static bool isDirective(int t) {
49 | switch( t )
50 | {
51 | case Tok_PROC: case Tok_FUNC: case Tok_DEF: case Tok_REF: case Tok_SEG: case Tok_ASCII:
52 | case Tok_TITLE: case Tok_END: case Tok_ENDM: case Tok_ELSE: case Tok_ENDC: case Tok_LIST:
53 | case Tok_NOLIST: case Tok_MACROLIST: case Tok_NOMACROLIST: case Tok_PATCHLIST: case Tok_NOPATCHLIST:
54 | case Tok_BYTE: case Tok_WORD: case Tok_ORG: case Tok_RORG: case Tok_IF: case Tok_EQU:
55 | case Tok_INCLUDE: case Tok_MACRO: case Tok_LONG: case Tok_PAGE:
56 | return true;
57 | default:
58 | return false;
59 | }
60 | }
61 | bool isDirective() const { return isDirective(d_type); }
62 | };
63 | }
64 |
65 | #endif // LISAASMTOKEN
66 |
67 |
--------------------------------------------------------------------------------
/LisaTokenType.h:
--------------------------------------------------------------------------------
1 | #ifndef __LISA_TOKENTYPE__
2 | #define __LISA_TOKENTYPE__
3 | // This file was automatically generated by EbnfStudio; don't modify it!
4 |
5 |
6 | #include
7 |
8 | #define LISA_CLASCAL
9 |
10 | namespace Lisa {
11 | enum TokenType {
12 | Tok_Invalid = 0,
13 |
14 | TT_Literals,
15 | Tok_Lpar,
16 | Tok_Latt,
17 | Tok_Rpar,
18 | Tok_Star,
19 | Tok_Ratt,
20 | Tok_Plus,
21 | Tok_Comma,
22 | Tok_Minus,
23 | Tok_Dot,
24 | Tok_2Dot,
25 | Tok_Slash,
26 | Tok_Colon,
27 | Tok_ColonEq,
28 | Tok_Semi,
29 | Tok_Lt,
30 | Tok_Leq,
31 | Tok_LtGt,
32 | Tok_Eq,
33 | Tok_Gt,
34 | Tok_Geq,
35 | Tok_At,
36 | Tok_Lbrack,
37 | Tok_Rbrack,
38 | Tok_Hat,
39 | Tok_Lbrace,
40 | Tok_Rbrace,
41 |
42 | TT_Keywords,
43 | Tok_and,
44 | Tok_array,
45 | Tok_begin,
46 | Tok_case,
47 | Tok_const,
48 | Tok_div,
49 | Tok_do,
50 | Tok_downto,
51 | Tok_else,
52 | Tok_end,
53 | Tok_external,
54 | Tok_file,
55 | Tok_for,
56 | Tok_forward,
57 | Tok_function,
58 | Tok_goto,
59 | Tok_if,
60 | Tok_implementation,
61 | Tok_in,
62 | Tok_inline,
63 | Tok_interface,
64 | Tok_intrinsic,
65 | Tok_label,
66 | Tok_methods,
67 | Tok_mod,
68 | Tok_nil,
69 | Tok_not,
70 | Tok_of,
71 | Tok_or,
72 | Tok_otherwise,
73 | Tok_packed,
74 | Tok_procedure,
75 | Tok_program,
76 | Tok_record,
77 | Tok_repeat,
78 | Tok_set,
79 | Tok_shared,
80 | Tok_string,
81 | Tok_subclass,
82 | Tok_then,
83 | Tok_to,
84 | Tok_type,
85 | Tok_unit,
86 | Tok_until,
87 | Tok_uses,
88 | Tok_var,
89 | Tok_while,
90 | Tok_with,
91 |
92 | TT_Specials,
93 | Tok_identifier,
94 | Tok_unsigned_real,
95 | Tok_digit_sequence,
96 | Tok_hex_digit_sequence,
97 | Tok_string_literal,
98 | Tok_Comment,
99 | Tok_Directive,
100 | Tok_Eof,
101 |
102 | TT_MaxToken,
103 |
104 | TT_Max
105 | };
106 |
107 | const char* tokenTypeString( int ); // Pretty with punctuation chars
108 | const char* tokenTypeName( int ); // Just the names without punctuation chars
109 | bool tokenTypeIsLiteral( int );
110 | bool tokenTypeIsKeyword( int );
111 | bool tokenTypeIsSpecial( int );
112 | TokenType tokenTypeFromString( const QByteArray& str, int* pos = 0 );
113 | TokenType tokenTypeFromString( const char* str, quint32 len, int* pos = 0 );
114 | }
115 | #endif // __LISA_TOKENTYPE__
116 |
--------------------------------------------------------------------------------
/AsmLexer.h:
--------------------------------------------------------------------------------
1 | #ifndef LISAASMLEXER_H
2 | #define LISAASMLEXER_H
3 |
4 | /*
5 | ** Copyright (C) 2023 Rochus Keller (me@rochus-keller.ch)
6 | **
7 | ** This file is part of the LisaPascal project.
8 | **
9 | ** $QT_BEGIN_LICENSE:LGPL21$
10 | ** GNU Lesser General Public License Usage
11 | ** This file may be used under the terms of the GNU Lesser
12 | ** General Public License version 2.1 or version 3 as published by the Free
13 | ** Software Foundation and appearing in the file LICENSE.LGPLv21 and
14 | ** LICENSE.LGPLv3 included in the packaging of this file. Please review the
15 | ** following information to ensure the GNU Lesser General Public License
16 | ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
17 | ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 | */
19 |
20 | #include "AsmToken.h"
21 |
22 | #include
23 | #include
24 |
25 | class QIODevice;
26 |
27 | namespace Asm
28 | {
29 | struct Macro
30 | {
31 | QByteArray d_name;
32 | QByteArray d_code;
33 | Macro( const QByteArray& n, const QByteArray& c ):d_name(n),d_code(c){}
34 | Macro(){}
35 | };
36 |
37 | class Macros : public QHash // name (lower case) -> code
38 | {
39 | public:
40 |
41 | };
42 |
43 | class Lexer
44 | {
45 | public:
46 | Lexer();
47 | void setStream(QIODevice*, const QString& filePath = QString());
48 | QIODevice* getDevice() const { return d_in; }
49 | void setIgnoreComments( bool b ) { d_ignoreComments = b; }
50 | void setPackComments( bool b ) { d_packComments = b; }
51 | void setMacros( Macros* m ) { d_macros = m; }
52 | const QString& getFilePath() const { return d_filePath; }
53 |
54 | Token nextToken();
55 | Token peekToken(quint8 lookAhead = 1);
56 | QList tokens( const QString& code );
57 | quint32 getSloc() const { return d_sloc; }
58 | protected:
59 | Token nextTokenImp();
60 | int skipWhiteSpace();
61 | void nextLine();
62 | int lookAhead(int off = 1) const;
63 | Token token(TokenType tt, int len = 1, const QByteArray &val = QByteArray(), bool = false);
64 | Token ident(bool dotPrefix = false);
65 | Token number();
66 | Token hexnumber();
67 | Token string1();
68 | Token string2();
69 | Token label();
70 | void countLine();
71 | Token readMacro();
72 | bool findMacro(const QByteArray&) const;
73 | private:
74 | QIODevice* d_in;
75 | QString d_filePath;
76 | quint32 d_lineNr;
77 | quint16 d_colNr;
78 | QByteArray d_line;
79 | QList d_buffer;
80 | Token d_lastToken;
81 | quint32 d_sloc;
82 | Macros* d_macros;
83 | bool d_ignoreComments;
84 | bool d_packComments;
85 | bool d_lineCounted;
86 | };
87 | }
88 |
89 | #endif // LISAASMLEXER_H
90 |
--------------------------------------------------------------------------------
/LisaFileSystem.h:
--------------------------------------------------------------------------------
1 | #ifndef FILESYSTEM_H
2 | #define FILESYSTEM_H
3 |
4 | /*
5 | ** Copyright (C) 2023 Rochus Keller (me@rochus-keller.ch)
6 | **
7 | ** This file is part of the LisaPascal project.
8 | **
9 | ** $QT_BEGIN_LICENSE:LGPL21$
10 | ** GNU Lesser General Public License Usage
11 | ** This file may be used under the terms of the GNU Lesser
12 | ** General Public License version 2.1 or version 3 as published by the Free
13 | ** Software Foundation and appearing in the file LICENSE.LGPLv21 and
14 | ** LICENSE.LGPLv3 included in the packaging of this file. Please review the
15 | ** following information to ensure the GNU Lesser General Public License
16 | ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
17 | ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 | */
19 |
20 | #include
21 | #include
22 |
23 | class QIODevice;
24 |
25 | namespace Lisa
26 | {
27 | class FileSystem : public QObject
28 | {
29 | public:
30 | struct File;
31 |
32 | struct Dir
33 | {
34 | QList d_subdirs;
35 | QList d_files;
36 | QString d_name;
37 | Dir* d_dir;
38 |
39 | void clear();
40 | void dump(int level = 0) const;
41 | Dir* subdir(const QString& name) const;
42 | const File* file(const QString& name) const;
43 | const File* module(const QByteArray& nameLc) const;
44 | Dir():d_dir(0) {}
45 | ~Dir() { clear(); }
46 | };
47 |
48 | enum FileType { UnknownFile, PascalProgram, PascalUnit, PascalFragment, AsmUnit, AsmFragment };
49 | struct File
50 | {
51 | quint8 d_type;
52 | bool d_doublette;
53 | bool d_forceParse;
54 | bool d_parsed;
55 | QString d_realPath;
56 | QString d_name; // fileName
57 | QString d_moduleName;
58 | QByteArray d_moduleLc; // lower-case version
59 | Dir* d_dir;
60 | QString getVirtualPath(bool suffix = true) const;
61 | int level() const;
62 |
63 | File():d_doublette(false),d_type(UnknownFile),d_dir(0),d_forceParse(false),d_parsed(false){}
64 | };
65 |
66 | explicit FileSystem(QObject *parent = 0);
67 | bool load( const QString& rootDir );
68 | bool addToRoot( const QStringList& files );
69 | const QString& getError() const { return d_error; }
70 | const Dir& getRoot() const { return d_root; }
71 | const QString& getRootPath() const { return d_rootDir; }
72 | QList getAllPas() const;
73 | QList getAllAsm() const;
74 | const File* findFile(const QString& realPath) const;
75 | const File* findFile(const Dir* startFrom, const QString& dir, const QString& name) const;
76 | const File* findModule(const Dir* startFrom, const QByteArray& nameLc) const;
77 |
78 | static FileType detectType(QIODevice* in, QByteArray* = 0);
79 | static FileType detectType2(QIODevice* in, QByteArray* = 0);
80 | protected:
81 | bool error( const QString& );
82 | Dir* getDir( const QString& relPath );
83 |
84 | private:
85 | QString d_rootDir;
86 | QString d_error;
87 | Dir d_root;
88 | QHash d_fileMap;
89 | QHash d_moduleMap; // module to File* is ambig, but besides "prmgr" (nearly) identical
90 | };
91 | }
92 |
93 | #endif // FILESYSTEM_H
94 |
--------------------------------------------------------------------------------
/AsmTokenType.h:
--------------------------------------------------------------------------------
1 | #ifndef __ASM_TOKENTYPE__
2 | #define __ASM_TOKENTYPE__
3 | // This file was automatically generated by EbnfStudio; don't modify it!
4 |
5 |
6 | #include
7 |
8 | #define ASM_ASSUME_UNKNOWN_MACROS
9 |
10 | namespace Asm {
11 | enum TokenType {
12 | Tok_Invalid = 0,
13 |
14 | TT_Literals,
15 | Tok_Hash,
16 | Tok_Amp,
17 | Tok_Lpar,
18 | Tok_Rpar,
19 | Tok_Star,
20 | Tok_Plus,
21 | Tok_Comma,
22 | Tok_Minus,
23 | Tok_Slash,
24 | Tok_Colon,
25 | Tok_Semi,
26 | Tok_Lt,
27 | Tok_LtGt,
28 | Tok_Eq,
29 | Tok_Gt,
30 | Tok_Hat,
31 | Tok_Bar,
32 | Tok_Tilde,
33 |
34 | TT_Keywords,
35 | Tok_ABCD,
36 | Tok_ADD,
37 | Tok_ADDA,
38 | Tok_ADDI,
39 | Tok_ADDQ,
40 | Tok_ADDX,
41 | Tok_ALIGN,
42 | Tok_AND,
43 | Tok_ANDI,
44 | Tok_ASCII,
45 | Tok_ASL,
46 | Tok_ASR,
47 | Tok_BCC,
48 | Tok_BCHG,
49 | Tok_BCLR,
50 | Tok_BCS,
51 | Tok_BEQ,
52 | Tok_BGE,
53 | Tok_BGT,
54 | Tok_BHI,
55 | Tok_BHS,
56 | Tok_BLE,
57 | Tok_BLO,
58 | Tok_BLS,
59 | Tok_BLT,
60 | Tok_BMI,
61 | Tok_BNE,
62 | Tok_BPL,
63 | Tok_BRA,
64 | Tok_BSET,
65 | Tok_BSR,
66 | Tok_BTST,
67 | Tok_BVC,
68 | Tok_BYTE,
69 | Tok_CHK,
70 | Tok_CLR,
71 | Tok_CMP,
72 | Tok_CMPA,
73 | Tok_CMPI,
74 | Tok_CMPM,
75 | Tok_DBEQ,
76 | Tok_DBF,
77 | Tok_DBRA,
78 | Tok_DEF,
79 | Tok_DIVS,
80 | Tok_DIVU,
81 | Tok_ELSE,
82 | Tok_END,
83 | Tok_ENDC,
84 | Tok_ENDM,
85 | Tok_EOR,
86 | Tok_EORI,
87 | Tok_EQU,
88 | Tok_EXG,
89 | Tok_EXT,
90 | Tok_FUNC,
91 | Tok_IF,
92 | Tok_ILLEGAL,
93 | Tok_INCLUDE,
94 | Tok_JMP,
95 | Tok_JSR,
96 | Tok_LEA,
97 | Tok_LINK,
98 | Tok_LIST,
99 | Tok_LONG,
100 | Tok_LSL,
101 | Tok_LSR,
102 | Tok_MACRO,
103 | Tok_MACROLIST,
104 | Tok_MOVE,
105 | Tok_MOVEA,
106 | Tok_MOVEM,
107 | Tok_MOVEP,
108 | Tok_MOVEQ,
109 | Tok_MULS,
110 | Tok_MULU,
111 | Tok_NBCD,
112 | Tok_NEG,
113 | Tok_NEGX,
114 | Tok_NOLIST,
115 | Tok_NOMACROLIST,
116 | Tok_NOP,
117 | Tok_NOPATCHLIST,
118 | Tok_NOT,
119 | Tok_OR,
120 | Tok_ORG,
121 | Tok_ORI,
122 | Tok_PAGE,
123 | Tok_PATCHLIST,
124 | Tok_PEA,
125 | Tok_PROC,
126 | Tok_REF,
127 | Tok_RESET,
128 | Tok_ROL,
129 | Tok_ROR,
130 | Tok_RORG,
131 | Tok_ROXL,
132 | Tok_ROXR,
133 | Tok_RTE,
134 | Tok_RTR,
135 | Tok_RTS,
136 | Tok_SBCD,
137 | Tok_SEG,
138 | Tok_SNE,
139 | Tok_STOP,
140 | Tok_SUB,
141 | Tok_SUBA,
142 | Tok_SUBI,
143 | Tok_SUBQ,
144 | Tok_SUBX,
145 | Tok_SWAP,
146 | Tok_TAS,
147 | Tok_TITLE,
148 | Tok_TRAP,
149 | Tok_TRAPV,
150 | Tok_TST,
151 | Tok_UNLK,
152 | Tok_WORD,
153 |
154 | TT_Specials,
155 | Tok_macrocall,
156 | Tok_number,
157 | Tok_string,
158 | Tok_ident,
159 | Tok_substitute,
160 | Tok_label,
161 | Tok_Comment,
162 | Tok_eol,
163 | Tok_dotW,
164 | Tok_dotL,
165 | Tok_dotB,
166 | Tok_dotS,
167 | Tok_Eof,
168 |
169 | TT_MaxToken,
170 |
171 | TT_Max
172 | };
173 |
174 | const char* tokenTypeString( int ); // Pretty with punctuation chars
175 | const char* tokenTypeName( int ); // Just the names without punctuation chars
176 | bool tokenTypeIsLiteral( int );
177 | bool tokenTypeIsKeyword( int );
178 | bool tokenTypeIsSpecial( int );
179 | TokenType tokenTypeFromString( const QByteArray& str, int* pos = 0 );
180 | }
181 | #endif // __ASM_TOKENTYPE__
182 |
--------------------------------------------------------------------------------
/LisaCodeNavigator.h:
--------------------------------------------------------------------------------
1 | #ifndef LISACODENAVIGATOR_H
2 | #define LISACODENAVIGATOR_H
3 |
4 | /*
5 | * Copyright 2023 Rochus Keller
6 | *
7 | * This file is part of the Lisa Pascal Navigator application.
8 | *
9 | * The following is the license that applies to this copy of the
10 | * application. For a license to use the library under conditions
11 | * other than those described here, please email to me@rochus-keller.ch.
12 | *
13 | * GNU General Public License Usage
14 | * This file may be used under the terms of the GNU General Public
15 | * License (GPL) versions 2.0 or 3.0 as published by the Free Software
16 | * Foundation and appearing in the file LICENSE.GPL included in
17 | * the packaging of this file. Please review the following information
18 | * to ensure GNU General Public Licensing requirements will be met:
19 | * http://www.fsf.org/licensing/licenses/info/GPLv2.html and
20 | * http://www.gnu.org/copyleft/gpl.html.
21 | */
22 |
23 | #include
24 | #include "LisaRowCol.h"
25 | #include "LisaFileSystem.h"
26 |
27 | class QLabel;
28 | class QPlainTextEdit;
29 | class QTreeView;
30 | class QTreeWidget;
31 | class QModelIndex;
32 |
33 | namespace Lisa
34 | {
35 | class CodeModel;
36 | class ModuleDetailMdl;
37 | class Symbol;
38 | class Declaration;
39 |
40 | class CodeNavigator : public QMainWindow
41 | {
42 | Q_OBJECT
43 | public:
44 | explicit CodeNavigator(QWidget *parent = 0);
45 | ~CodeNavigator();
46 |
47 | void open( const QString& sourceTreePath);
48 | void logMessage(const QString&);
49 |
50 | protected:
51 | struct Place
52 | {
53 | FilePos d_loc;
54 | quint16 d_yoff;
55 | bool operator==( const Place& rhs ) { return d_loc.d_pos.d_row == rhs.d_loc.d_pos.d_row &&
56 | d_loc.d_pos.d_col == rhs.d_loc.d_pos.d_col && d_loc.d_filePath == rhs.d_loc.d_filePath; }
57 | Place(const FilePos& loc, quint16 y ):d_loc(loc),d_yoff(y){}
58 | Place():d_yoff(0) {}
59 | };
60 |
61 | void createModuleList();
62 | void createDetails();
63 | void createUsedBy();
64 | void createLog();
65 | void pushLocation( const Place& );
66 | void showViewer( const Place& );
67 | void fillUsedBy(Symbol* id, Declaration*);
68 | void setPathTitle(const FileSystem::File* f, int row, int col);
69 | void syncModuleList();
70 |
71 | // overrides
72 | void closeEvent(QCloseEvent* event);
73 |
74 | protected slots:
75 | void onCursorPositionChanged();
76 | void onModuleDblClick(const QModelIndex&);
77 | void onItemDblClick(const QModelIndex&);
78 | void onUsedByDblClicked();
79 | void onGoBack();
80 | void onGoForward();
81 | void onGotoLine();
82 | void onFindInFile();
83 | void onFindAgain();
84 | void onGotoDefinition();
85 | void onOpen();
86 | void onRunReload();
87 | void onIncreaseSize();
88 | void onDecreaseSize();
89 |
90 | private:
91 | class Viewer;
92 | Viewer* d_view;
93 | QLabel* d_pathTitle;
94 | QPlainTextEdit* d_msgLog;
95 | QTreeView* d_modules;
96 | QTreeView* d_module;
97 | QLabel* d_usedByTitle;
98 | QTreeWidget* d_usedBy;
99 | CodeModel* d_mdl;
100 | ModuleDetailMdl* d_mdl2;
101 | QString d_dir;
102 |
103 | QList d_backHisto; // d_backHisto.last() is current place
104 | QList d_forwardHisto;
105 | bool d_pushBackLock;
106 | };
107 | }
108 |
109 | #endif // LISACODENAVIGATOR_H
110 |
--------------------------------------------------------------------------------
/LisaSynTree.h:
--------------------------------------------------------------------------------
1 | #ifndef __LISA_SYNTREE__
2 | #define __LISA_SYNTREE__
3 | // This file was automatically generated by EbnfStudio; don't modify it!
4 |
5 | #include
6 | #include
7 | #include
8 |
9 | namespace Lisa {
10 |
11 | struct SynTree {
12 | enum ParserRule {
13 | R_First = TT_Max + 1,
14 | R_LisaPascal,
15 | R_actual_parameter,
16 | R_actual_parameter_list,
17 | R_addition_operator,
18 | R_array_type,
19 | R_assigOrCall,
20 | R_assignment_statement_,
21 | R_block,
22 | R_body_,
23 | R_case_label_list,
24 | R_case_limb,
25 | R_case_statement,
26 | R_class_type,
27 | R_comment_,
28 | R_compound_statement,
29 | R_conditional_statement,
30 | R_constant,
31 | R_constant_declaration,
32 | R_constant_declaration_part,
33 | R_constant_identifier_,
34 | R_dereferencer,
35 | R_enumerated_type,
36 | R_expression,
37 | R_expression_list,
38 | R_factor,
39 | R_field_declaration,
40 | R_field_designator,
41 | R_field_identifier,
42 | R_field_list,
43 | R_file_type,
44 | R_final_value,
45 | R_fixed_part,
46 | R_for_statement,
47 | R_formal_parameter_list,
48 | R_formal_parameter_section,
49 | R_function_declaration,
50 | R_function_heading,
51 | R_function_identifier_,
52 | R_goto_statement,
53 | R_identifier_list,
54 | R_identifier_list2,
55 | R_if_statement,
56 | R_implementation_part,
57 | R_index,
58 | R_index_type,
59 | R_initial_value,
60 | R_interface_part,
61 | R_label_,
62 | R_label_declaration_part,
63 | R_member_group,
64 | R_method_block,
65 | R_method_interface,
66 | R_multiplication_operator,
67 | R_non_regular_unit,
68 | R_ordinal_type,
69 | R_otherwise_clause,
70 | R_parameter_declaration,
71 | R_pointer_type,
72 | R_procedure_and_function_declaration_part,
73 | R_procedure_and_function_interface_part,
74 | R_procedure_declaration,
75 | R_procedure_heading,
76 | R_procedure_identifier_,
77 | R_procedure_statement_,
78 | R_program_,
79 | R_program_heading,
80 | R_program_parameters,
81 | R_qualifier,
82 | R_record_type,
83 | R_regular_unit,
84 | R_relational_operator,
85 | R_repeat_statement,
86 | R_repetitive_statement,
87 | R_result_type,
88 | R_set_literal,
89 | R_set_type,
90 | R_sign,
91 | R_simple_expression,
92 | R_simple_statement,
93 | R_simple_type,
94 | R_size_attribute,
95 | R_statement,
96 | R_statement_part,
97 | R_statement_sequence,
98 | R_string_type,
99 | R_structured_statement,
100 | R_structured_type,
101 | R_subrange_type,
102 | R_subroutine_part,
103 | R_tag_field,
104 | R_term,
105 | R_type_,
106 | R_type_declaration,
107 | R_type_declaration_part,
108 | R_type_identifier,
109 | R_unit_heading,
110 | R_unsigned_integer,
111 | R_unsigned_number,
112 | R_uses_clause,
113 | R_variable_declaration,
114 | R_variable_declaration_part,
115 | R_variable_identifier,
116 | R_variable_reference,
117 | R_variant,
118 | R_variant_part,
119 | R_while_statement,
120 | R_with_statement,
121 | R_Last
122 | };
123 | SynTree(quint16 r = Tok_Invalid, const Token& = Token() );
124 | SynTree(const Token& t ):d_tok(t){}
125 | ~SynTree() { foreach(SynTree* n, d_children) delete n; }
126 |
127 | static const char* rToStr( quint16 r );
128 |
129 | Lisa::Token d_tok;
130 | QList d_children;
131 | };
132 |
133 | }
134 | #endif // __LISA_SYNTREE__
135 |
--------------------------------------------------------------------------------
/LisaPpLexer.h:
--------------------------------------------------------------------------------
1 | #ifndef PPLEXER_H
2 | #define PPLEXER_H
3 |
4 | /*
5 | ** Copyright (C) 2023 Rochus Keller (me@rochus-keller.ch)
6 | **
7 | ** This file is part of the LisaPascal project.
8 | **
9 | ** $QT_BEGIN_LICENSE:LGPL21$
10 | ** GNU Lesser General Public License Usage
11 | ** This file may be used under the terms of the GNU Lesser
12 | ** General Public License version 2.1 or version 3 as published by the Free
13 | ** Software Foundation and appearing in the file LICENSE.LGPLv21 and
14 | ** LICENSE.LGPLv3 included in the packaging of this file. Please review the
15 | ** following information to ensure the GNU Lesser General Public License
16 | ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
17 | ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 | */
19 |
20 | #include "LisaFileSystem.h"
21 | #include "LisaLexer.h"
22 | #include "LisaRowCol.h"
23 |
24 | class QIODevice;
25 |
26 | namespace Lisa
27 | {
28 | class FileSystem;
29 |
30 | class PpLexer
31 | {
32 | public:
33 | enum PpSym { PpNone, PpIncl, PpSetc, PpIfc, PpElsec, PpEndc };
34 | typedef QHash PpVars;
35 | struct Include
36 | {
37 | const FileSystem::File* d_inc; // the file to include
38 | QString d_sourcePath; // the file where the include lives
39 | RowCol d_loc; // the pos of the include directive in sourcePath
40 | quint16 d_len; // the len of the include directive
41 | };
42 |
43 | PpLexer(FileSystem*);
44 | ~PpLexer();
45 |
46 | bool reset(const QString& filePath);
47 |
48 | Token nextToken();
49 | Token peekToken(quint8 lookAhead = 1);
50 | quint32 getSloc() const { return d_sloc; }
51 | const QList& getIncludes() const { return d_includes; }
52 | const QHash& getMutes() const { return d_mutes; }
53 | protected:
54 | Token nextTokenImp();
55 | static PpSym checkPp(QByteArray&);
56 | bool handleInclude(const QByteArray& data, const Token& t);
57 | bool handleSetc(const QByteArray& data);
58 | bool handleIfc(const QByteArray& data);
59 | bool handleElsec();
60 | bool handleEndc();
61 | bool error( const QString& msg);
62 |
63 | struct ppstatus
64 | {
65 | bool open; // this is the open condition which renders tokens
66 | bool openSeen; // at least one true condition seen
67 | bool elseSeen; // there was already an else part
68 | ppstatus(bool o = true):open(o),openSeen(false),elseSeen(false){}
69 | };
70 |
71 | ppstatus ppouter()
72 | {
73 | ppstatus res;
74 | if( d_conditionStack.size() >= 2 )
75 | res = d_conditionStack[d_conditionStack.size()-2];
76 | return res;
77 | }
78 | ppstatus ppthis()
79 | {
80 | ppstatus res;
81 | if( !d_conditionStack.isEmpty() )
82 | res = d_conditionStack.back();
83 | return res;
84 | }
85 | void ppsetthis(bool open, bool thisIsElse = false)
86 | {
87 | if( !d_conditionStack.isEmpty() )
88 | {
89 | ppstatus& stat = d_conditionStack.back();
90 | stat.open = open;
91 | if( thisIsElse )
92 | stat.elseSeen = true;
93 | if( open )
94 | stat.openSeen = true;
95 | }
96 | }
97 | private:
98 | struct Level
99 | {
100 | Lexer d_lex;
101 | Ranges d_mutes;
102 | };
103 |
104 | FileSystem* d_fs;
105 | QList d_stack;
106 | QList d_files;
107 | QList d_buffer;
108 | QString d_err;
109 | quint32 d_sloc; // number of lines of code without empty or comment lines
110 | PpVars d_ppVars;
111 | QList d_conditionStack;
112 | QList d_includes;
113 | QHash d_mutes;
114 | RowCol d_startMute;
115 | };
116 | }
117 |
118 | #endif // PPLEXER_H
119 |
--------------------------------------------------------------------------------
/AsmPpLexer.h:
--------------------------------------------------------------------------------
1 | #ifndef ASMPPLEXER_H
2 | #define ASMPPLEXER_H
3 |
4 | /*
5 | ** Copyright (C) 2023 Rochus Keller (me@rochus-keller.ch)
6 | **
7 | ** This file is part of the LisaPascal project.
8 | **
9 | ** $QT_BEGIN_LICENSE:LGPL21$
10 | ** GNU Lesser General Public License Usage
11 | ** This file may be used under the terms of the GNU Lesser
12 | ** General Public License version 2.1 or version 3 as published by the Free
13 | ** Software Foundation and appearing in the file LICENSE.LGPLv21 and
14 | ** LICENSE.LGPLv3 included in the packaging of this file. Please review the
15 | ** following information to ensure the GNU Lesser General Public License
16 | ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
17 | ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 | */
19 |
20 | #include "LisaFileSystem.h"
21 | #include "AsmLexer.h"
22 | #include "LisaRowCol.h"
23 |
24 | class QIODevice;
25 |
26 | namespace Lisa
27 | {
28 | class FileSystem;
29 |
30 | }
31 | namespace Asm
32 | {
33 | class PpLexer
34 | {
35 | public:
36 | enum PpSym { PpNone, PpIncl, PpSetc, PpIfc, PpElsec, PpEndc };
37 | typedef QHash PpVars;
38 | struct Include
39 | {
40 | const FileSystem::File* d_inc; // the file to include
41 | QString d_sourcePath; // the file where the include lives
42 | RowCol d_loc; // the pos of the include directive in sourcePath
43 | quint16 d_len; // the len of the include directive
44 | };
45 |
46 | PpLexer(FileSystem*);
47 | ~PpLexer();
48 |
49 | bool reset(const QString& filePath);
50 |
51 | Token nextToken();
52 | Token peekToken(quint8 lookAhead = 1);
53 | quint32 getSloc() const { return d_sloc; }
54 | const QList& getIncludes() const { return d_includes; }
55 | const QHash& getMutes() const { return d_mutes; }
56 | protected:
57 | Token nextTokenImp();
58 |
59 | bool handleInclude(Token t);
60 | bool handleSetc(const QByteArray& data);
61 | bool handleIfc(const QByteArray& data);
62 | bool handleElsec();
63 | bool handleEndc();
64 | bool error( const QString& msg);
65 |
66 | struct ppstatus
67 | {
68 | bool open; // this is the open condition which renders tokens
69 | bool openSeen; // at least one true condition seen
70 | bool elseSeen; // there was already an else part
71 | ppstatus(bool o = true):open(o),openSeen(false),elseSeen(false){}
72 | };
73 |
74 | ppstatus ppouter()
75 | {
76 | ppstatus res;
77 | if( d_conditionStack.size() >= 2 )
78 | res = d_conditionStack[d_conditionStack.size()-2];
79 | return res;
80 | }
81 | ppstatus ppthis()
82 | {
83 | ppstatus res;
84 | if( !d_conditionStack.isEmpty() )
85 | res = d_conditionStack.back();
86 | return res;
87 | }
88 | void ppsetthis(bool open, bool thisIsElse = false)
89 | {
90 | if( !d_conditionStack.isEmpty() )
91 | {
92 | ppstatus& stat = d_conditionStack.back();
93 | stat.open = open;
94 | if( thisIsElse )
95 | stat.elseSeen = true;
96 | if( open )
97 | stat.openSeen = true;
98 | }
99 | }
100 | private:
101 | struct Level
102 | {
103 | Lexer d_lex;
104 | Ranges d_mutes;
105 | };
106 |
107 | FileSystem* d_fs;
108 | QList d_stack;
109 | QList d_files;
110 | QList d_buffer;
111 | QString d_err;
112 | quint32 d_sloc; // number of lines of code without empty or comment lines
113 | PpVars d_ppVars;
114 | QList d_conditionStack;
115 | QList d_includes;
116 | QHash d_mutes;
117 | RowCol d_startMute;
118 | Macros d_macros;
119 | };
120 | }
121 |
122 | #endif // ASMPPLEXER_H
123 |
--------------------------------------------------------------------------------
/asm/LisaAsm.ebnf:
--------------------------------------------------------------------------------
1 | // Copyright 2023 Rochus Keller
2 |
3 | // This grammar was synthesized from the "Lisa Workshop 3.0 Users Guide" (1984), the
4 | // "MC 68000 Programmer Reference Manual" (1991) and
5 | // "Programming the 68000 - Macintosh Assembly Language" (1986), and then modified
6 | // until all assembler source files of the Lisa Source Code published by the CHM parsed without error
7 |
8 | #define ASSUME_UNKNOWN_MACROS
9 |
10 | program ::= { line }
11 |
12 | line ::=
13 | #ifdef ASSUME_UNKNOWN_MACROS
14 | { term [size] [addrop] [':'] // term instead of ident to disambiguate with original macrocall
15 | // size because ident "E.TOP.S" in libpl-passet 403
16 | | label [':']
17 | | '#' expression // also this to simulate macrocall
18 | | '-' addrop // dito
19 | }
20 | #else
21 | { ident [':'] | label [':'] }
22 | #endif
23 | [ directive
24 | | statement
25 | | ',' argument { ',' argument } // instead of macrocall
26 | ] eol
27 |
28 | directive ::= ( // the lexer eats the dot prefix; the parser only sees the token
29 | ( PROC | FUNC ) ident [ ',' number ]
30 | | ( DEF | REF ) ident { ',' ident }
31 | | ( SEG | ASCII | TITLE ) ( string | substitute )
32 | | ( END | ENDM | ELSE | ENDC | LIST | NOLIST | MACROLIST | NOMACROLIST
33 | | PATCHLIST | NOPATCHLIST | PAGE )
34 | | ( BYTE | WORD | LONG ) expression { ',' expression }
35 | | ( ORG | RORG | IF | EQU | ALIGN ) expression
36 | | INCLUDE filename
37 | | macrodef
38 | )
39 |
40 | statement ::=
41 | mnemonic [ size ] [ argument { ',' argument } ]
42 | | macrocall
43 |
44 | mnemonic ::=
45 | BEQ | LSR | BNE | LSL | BGE | 'BLE' | 'DBF' | 'BMI' | 'ROR' | 'ASL' | 'ASR' | 'DBRA'
46 | | 'BVC' | 'BPL' | 'BGT' | 'BLS' | 'BHI' | 'BLT' | 'DBEQ' | 'SNE' | 'ROL' | 'ROXR' | 'ROXL'
47 | | BHS | BLO | BCC | BCS | ORI | ANDI | SUBI | ADDI | EORI | CMPI
48 | | BTST | BCHG | BCLR | BSET | MOVEP | MOVEA | MOVE
49 | | NEGX | CLR | NEG | NOT | EXT | NBCD | SWAP | PEA | ILLEGAL | TAS | TST
50 | | TRAP | LINK | UNLK | RESET | NOP | STOP | RTE | RTS | TRAPV | RTR | JSR
51 | | JMP | MOVEM | LEA | CHK | ADDQ | SUBQ | BRA | BSR | MOVEQ | DIVU | DIVS
52 | | SBCD | OR | SUB | SUBX | SUBA | EOR | CMPM | CMP | CMPA | MULU | MULS
53 | | ABCD | EXG | AND | ADD | ADDX | ADDA
54 |
55 | size ::= dotW | dotL | dotB | dotS
56 |
57 | macrodef ::= MACRO ident
58 |
59 | // macrocall- ::= ident [ expression { ',' expression } ]
60 | // creates ambiguity with preceding idents, therefore simulated in line production
61 | macrocall ::= // just an empty symbol
62 |
63 | argument ::=
64 | \LA: 1:'-'&2:'('\ '-' addrop
65 | | expression [size] [ addrop ]
66 | // size because ident "E.TOP.S" in libpl-passet 394
67 | | '#' expression
68 | | addrop
69 | | label
70 |
71 | addrop ::= '(' expression [ size ] [ ',' reg ] ')' [ '+' | size ]
72 |
73 | reg ::= ident [ size ] | substitute
74 |
75 | expression ::= ['-'] term
76 |
77 | term ::= factor { \LL:2\ op factor }
78 |
79 | factor ::= ident | string | number | '<' expression '>' | substitute | '*'
80 |
81 | filename ::= ident { '/' ident }
82 |
83 | op ::= '+' | '-' | '~' | '^' | '*' | '/' | '|' | '&' | '=' | '<>'
84 | // backslash part of syntax but never used and EbnfStudio has issue
85 |
86 | number ::= // digit { digit } | '$' hexdigit { hexdigit } | hexdigit { hexdigit } 'H' |
87 | // octaldigit { octaldigit } 'O' | bindigit { bindigit } 'B'
88 |
89 | string ::= // '"' any printable char '"' | '\'' any printable char '\''
90 |
91 | ident ::= // alpha { alpha | digit | '%' | '_' | '.' }
92 |
93 | substitute ::= // '%' digit
94 |
95 | label ::= // '@' digit { digit }
96 |
97 | comment- ::= ';'
98 | Comment ::=
99 |
100 | eol ::= // \n
101 |
102 | dotW ::= // '.W'
103 | dotL ::= // '.L'
104 | dotB ::= // '.B'
105 | dotS ::= // '.S'
106 |
107 |
108 |
109 | // Pragmas
110 | %module ::= 'LisaPascal'
111 | %namespace ::= 'Asm'
112 |
--------------------------------------------------------------------------------
/fonts/Noto.license:
--------------------------------------------------------------------------------
1 | SIL Open Font License
2 |
3 | Copyright 2012 Google Inc. All Rights Reserved.
4 |
5 | This Font Software is licensed under the SIL Open Font License, Version 1.1.
6 | This license is copied below, and is also available with a FAQ at: http://scripts.sil.org/OFL
7 |
8 | —————————————————————————————-
9 | SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
10 | —————————————————————————————-
11 |
12 | PREAMBLE
13 | The goals of the Open Font License (OFL) are to stimulate worldwide development of collaborative font projects, to support the font creation efforts of academic and linguistic communities, and to provide a free and open framework in which fonts may be shared and improved in partnership with others.
14 |
15 | The OFL allows the licensed fonts to be used, studied, modified and redistributed freely as long as they are not sold by themselves. The fonts, including any derivative works, can be bundled, embedded, redistributed and/or sold with any software provided that any reserved names are not used by derivative works. The fonts and derivatives, however, cannot be released under any other type of license. The requirement for fonts to remain under this license does not apply to any document created using the fonts or their derivatives.
16 |
17 | DEFINITIONS
18 | “Font Software” refers to the set of files released by the Copyright Holder(s) under this license and clearly marked as such. This may include source files, build scripts and documentation.
19 |
20 | “Reserved Font Name” refers to any names specified as such after the copyright statement(s).
21 |
22 | “Original Version” refers to the collection of Font Software components as distributed by the Copyright Holder(s).
23 |
24 | “Modified Version” refers to any derivative made by adding to, deleting, or substituting—in part or in whole—any of the components of the Original Version, by changing formats or by porting the Font Software to a new environment.
25 |
26 | “Author” refers to any designer, engineer, programmer, technical writer or other person who contributed to the Font Software.
27 |
28 | PERMISSION & CONDITIONS
29 | Permission is hereby granted, free of charge, to any person obtaining a copy of the Font Software, to use, study, copy, merge, embed, modify, redistribute, and sell modified and unmodified copies of the Font Software, subject to the following conditions:
30 |
31 | 1) Neither the Font Software nor any of its individual components, in Original or Modified Versions, may be sold by itself.
32 |
33 | 2) Original or Modified Versions of the Font Software may be bundled, redistributed and/or sold with any software, provided that each copy contains the above copyright notice and this license. These can be included either as stand-alone text files, human-readable headers or in the appropriate machine-readable metadata fields within text or binary files as long as those fields can be easily viewed by the user.
34 |
35 | 3) No Modified Version of the Font Software may use the Reserved Font Name(s) unless explicit written permission is granted by the corresponding Copyright Holder. This restriction only applies to the primary font name as presented to the users.
36 |
37 | 4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font Software shall not be used to promote, endorse or advertise any Modified Version, except to acknowledge the contribution(s) of the Copyright Holder(s) and the Author(s) or with their explicit written permission.
38 |
39 | 5) The Font Software, modified or unmodified, in part or in whole, must be distributed entirely under this license, and must not be distributed under any other license. The requirement for fonts to remain under this license does not apply to any document created using the Font Software.
40 |
41 | TERMINATION
42 | This license becomes null and void if any of the above conditions are not met.
43 |
44 | DISCLAIMER
45 | THE FONT SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE.
46 |
--------------------------------------------------------------------------------
/LisaParser.h:
--------------------------------------------------------------------------------
1 | #ifndef __LISA_PARSER__
2 | #define __LISA_PARSER__
3 | // This file was automatically generated by EbnfStudio; don't modify it!
4 |
5 | #include
6 |
7 | namespace Lisa {
8 |
9 | class Scanner {
10 | public:
11 | virtual Token next() = 0;
12 | virtual Token peek(int offset) = 0;
13 | };
14 |
15 | class Parser {
16 | public:
17 | Parser(Scanner* s):scanner(s) {}
18 | void RunParser();
19 | SynTree root;
20 | struct Error {
21 | QString msg;
22 | int row, col;
23 | QString path;
24 | Error( const QString& m, int r, int c, const QString& p):msg(m),row(r),col(c),path(p){}
25 | };
26 | QList errors;
27 | protected:
28 | void LisaPascal(SynTree*);
29 | void program_(SynTree*);
30 | void program_heading(SynTree*);
31 | void program_parameters(SynTree*);
32 | void uses_clause(SynTree*);
33 | void identifier_list2(SynTree*);
34 | void regular_unit(SynTree*);
35 | void unit_heading(SynTree*);
36 | void interface_part(SynTree*);
37 | void implementation_part(SynTree*);
38 | void non_regular_unit(SynTree*);
39 | void block(SynTree*);
40 | void label_declaration_part(SynTree*);
41 | void label_(SynTree*);
42 | void constant_declaration_part(SynTree*);
43 | void constant_declaration(SynTree*);
44 | void constant(SynTree*);
45 | void type_declaration_part(SynTree*);
46 | void type_declaration(SynTree*);
47 | void variable_declaration_part(SynTree*);
48 | void variable_declaration(SynTree*);
49 | void procedure_and_function_interface_part(SynTree*);
50 | void procedure_and_function_declaration_part(SynTree*);
51 | void subroutine_part(SynTree*);
52 | void method_block(SynTree*);
53 | void procedure_declaration(SynTree*);
54 | void body_(SynTree*);
55 | void function_declaration(SynTree*);
56 | void statement_part(SynTree*);
57 | void procedure_heading(SynTree*);
58 | void function_heading(SynTree*);
59 | void result_type(SynTree*);
60 | void formal_parameter_list(SynTree*);
61 | void formal_parameter_section(SynTree*);
62 | void parameter_declaration(SynTree*);
63 | void statement_sequence(SynTree*);
64 | void statement(SynTree*);
65 | void simple_statement(SynTree*);
66 | void assigOrCall(SynTree*);
67 | void goto_statement(SynTree*);
68 | void structured_statement(SynTree*);
69 | void compound_statement(SynTree*);
70 | void repetitive_statement(SynTree*);
71 | void while_statement(SynTree*);
72 | void repeat_statement(SynTree*);
73 | void for_statement(SynTree*);
74 | void initial_value(SynTree*);
75 | void final_value(SynTree*);
76 | void conditional_statement(SynTree*);
77 | void if_statement(SynTree*);
78 | void case_statement(SynTree*);
79 | void case_limb(SynTree*);
80 | void case_label_list(SynTree*);
81 | void otherwise_clause(SynTree*);
82 | void with_statement(SynTree*);
83 | void actual_parameter_list(SynTree*);
84 | void actual_parameter(SynTree*);
85 | void expression(SynTree*);
86 | void simple_expression(SynTree*);
87 | void term(SynTree*);
88 | void factor(SynTree*);
89 | void relational_operator(SynTree*);
90 | void addition_operator(SynTree*);
91 | void multiplication_operator(SynTree*);
92 | void variable_reference(SynTree*);
93 | void qualifier(SynTree*);
94 | void index(SynTree*);
95 | void field_designator(SynTree*);
96 | void dereferencer(SynTree*);
97 | void set_literal(SynTree*);
98 | void member_group(SynTree*);
99 | void type_(SynTree*);
100 | void simple_type(SynTree*);
101 | void ordinal_type(SynTree*);
102 | void string_type(SynTree*);
103 | void size_attribute(SynTree*);
104 | void enumerated_type(SynTree*);
105 | void subrange_type(SynTree*);
106 | void structured_type(SynTree*);
107 | void array_type(SynTree*);
108 | void index_type(SynTree*);
109 | void set_type(SynTree*);
110 | void file_type(SynTree*);
111 | void pointer_type(SynTree*);
112 | void class_type(SynTree*);
113 | void method_interface(SynTree*);
114 | void record_type(SynTree*);
115 | void field_list(SynTree*);
116 | void fixed_part(SynTree*);
117 | void field_declaration(SynTree*);
118 | void variant_part(SynTree*);
119 | void tag_field(SynTree*);
120 | void variant(SynTree*);
121 | void field_identifier(SynTree*);
122 | void variable_identifier(SynTree*);
123 | void type_identifier(SynTree*);
124 | void identifier_list(SynTree*);
125 | void expression_list(SynTree*);
126 | void unsigned_integer(SynTree*);
127 | void unsigned_number(SynTree*);
128 | void sign(SynTree*);
129 | protected:
130 | Token cur;
131 | Token la;
132 | Scanner* scanner;
133 | void next();
134 | Token peek(int off);
135 | void invalid(const char* what);
136 | bool expect(int tt, bool pkw, const char* where);
137 | void addTerminal(SynTree* st);
138 | };
139 | }
140 | #endif // include
141 |
--------------------------------------------------------------------------------
/fonts/DejaVu.license:
--------------------------------------------------------------------------------
1 | DejaVu Fonts License
2 |
3 | Fonts are (c) Bitstream (see below). DejaVu changes are in public domain.
4 | Glyphs imported from Arev fonts are (c) Tavmjong Bah (see below)
5 |
6 | Bitstream Vera Fonts Copyright
7 | ———————————————
8 |
9 | Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Bitstream Vera is
10 | a trademark of Bitstream, Inc.
11 |
12 | Permission is hereby granted, free of charge, to any person obtaining a copy
13 | of the fonts accompanying this license (“Fonts”) and associated
14 | documentation files (the “Font Software”), to reproduce and distribute the
15 | Font Software, including without limitation the rights to use, copy, merge,
16 | publish, distribute, and/or sell copies of the Font Software, and to permit
17 | persons to whom the Font Software is furnished to do so, subject to the
18 | following conditions:
19 |
20 | The above copyright and trademark notices and this permission notice shall
21 | be included in all copies of one or more of the Font Software typefaces.
22 |
23 | The Font Software may be modified, altered, or added to, and in particular
24 | the designs of glyphs or characters in the Fonts may be modified and
25 | additional glyphs or characters may be added to the Fonts, only if the fonts
26 | are renamed to names not containing either the words “Bitstream” or the word
27 | “Vera”.
28 |
29 | This License becomes null and void to the extent applicable to Fonts or Font
30 | Software that has been modified and is distributed under the “Bitstream
31 | Vera” names.
32 |
33 | The Font Software may be sold as part of a larger software package but no
34 | copy of one or more of the Font Software typefaces may be sold by itself.
35 |
36 | THE FONT SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS
37 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY,
38 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT,
39 | TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL BITSTREAM OR THE GNOME
40 | FOUNDATION BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING
41 | ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES,
42 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
43 | THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE
44 | FONT SOFTWARE.
45 |
46 | Except as contained in this notice, the names of Gnome, the Gnome
47 | Foundation, and Bitstream Inc., shall not be used in advertising or
48 | otherwise to promote the sale, use or other dealings in this Font Software
49 | without prior written authorization from the Gnome Foundation or Bitstream
50 | Inc., respectively. For further information, contact: fonts at gnome dot
51 | org.
52 |
53 | Arev Fonts Copyright
54 | ———————————————
55 |
56 | Copyright (c) 2006 by Tavmjong Bah. All Rights Reserved.
57 |
58 | Permission is hereby granted, free of charge, to any person obtaining
59 | a copy of the fonts accompanying this license (“Fonts”) and
60 | associated documentation files (the “Font Software”), to reproduce
61 | and distribute the modifications to the Bitstream Vera Font Software,
62 | including without limitation the rights to use, copy, merge, publish,
63 | distribute, and/or sell copies of the Font Software, and to permit
64 | persons to whom the Font Software is furnished to do so, subject to
65 | the following conditions:
66 |
67 | The above copyright and trademark notices and this permission notice
68 | shall be included in all copies of one or more of the Font Software
69 | typefaces.
70 |
71 | The Font Software may be modified, altered, or added to, and in
72 | particular the designs of glyphs or characters in the Fonts may be
73 | modified and additional glyphs or characters may be added to the
74 | Fonts, only if the fonts are renamed to names not containing either
75 | the words “Tavmjong Bah” or the word “Arev”.
76 |
77 | This License becomes null and void to the extent applicable to Fonts
78 | or Font Software that has been modified and is distributed under the
79 | “Tavmjong Bah Arev” names.
80 |
81 | The Font Software may be sold as part of a larger software package but
82 | no copy of one or more of the Font Software typefaces may be sold by
83 | itself.
84 |
85 | THE FONT SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND,
86 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
87 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
88 | OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL
89 | TAVMJONG BAH BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
90 | INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
91 | DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
92 | FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
93 | OTHER DEALINGS IN THE FONT SOFTWARE.
94 |
95 | Except as contained in this notice, the name of Tavmjong Bah shall not
96 | be used in advertising or otherwise to promote the sale, use or other
97 | dealings in this Font Software without prior written authorization
98 | from Tavmjong Bah. For further information, contact: tavmjong @ free
99 | . fr.
100 |
--------------------------------------------------------------------------------
/AsmParser.h:
--------------------------------------------------------------------------------
1 |
2 |
3 | // This file was automatically generated by Coco/R; don't modify it.
4 | #if !defined(Asm_COCO_PARSER_H__)
5 | #define Asm_COCO_PARSER_H__
6 |
7 | #include
8 | #include
9 |
10 |
11 | namespace Asm {
12 |
13 |
14 | class PpLexer;
15 | class Parser {
16 | private:
17 | enum {
18 | _EOF=0,
19 | _T_Literals_=1,
20 | _T_Hash=2,
21 | _T_Amp=3,
22 | _T_Lpar=4,
23 | _T_Rpar=5,
24 | _T_Star=6,
25 | _T_Plus=7,
26 | _T_Comma=8,
27 | _T_Minus=9,
28 | _T_Slash=10,
29 | _T_Colon=11,
30 | _T_Semi=12,
31 | _T_Lt=13,
32 | _T_LtGt=14,
33 | _T_Eq=15,
34 | _T_Gt=16,
35 | _T_Hat=17,
36 | _T_Bar=18,
37 | _T_Tilde=19,
38 | _T_Keywords_=20,
39 | _T_ABCD=21,
40 | _T_ADD=22,
41 | _T_ADDA=23,
42 | _T_ADDI=24,
43 | _T_ADDQ=25,
44 | _T_ADDX=26,
45 | _T_ALIGN=27,
46 | _T_AND=28,
47 | _T_ANDI=29,
48 | _T_ASCII=30,
49 | _T_ASL=31,
50 | _T_ASR=32,
51 | _T_BCC=33,
52 | _T_BCHG=34,
53 | _T_BCLR=35,
54 | _T_BCS=36,
55 | _T_BEQ=37,
56 | _T_BGE=38,
57 | _T_BGT=39,
58 | _T_BHI=40,
59 | _T_BHS=41,
60 | _T_BLE=42,
61 | _T_BLO=43,
62 | _T_BLS=44,
63 | _T_BLT=45,
64 | _T_BMI=46,
65 | _T_BNE=47,
66 | _T_BPL=48,
67 | _T_BRA=49,
68 | _T_BSET=50,
69 | _T_BSR=51,
70 | _T_BTST=52,
71 | _T_BVC=53,
72 | _T_BYTE=54,
73 | _T_CHK=55,
74 | _T_CLR=56,
75 | _T_CMP=57,
76 | _T_CMPA=58,
77 | _T_CMPI=59,
78 | _T_CMPM=60,
79 | _T_DBEQ=61,
80 | _T_DBF=62,
81 | _T_DBRA=63,
82 | _T_DEF=64,
83 | _T_DIVS=65,
84 | _T_DIVU=66,
85 | _T_ELSE=67,
86 | _T_END=68,
87 | _T_ENDC=69,
88 | _T_ENDM=70,
89 | _T_EOR=71,
90 | _T_EORI=72,
91 | _T_EQU=73,
92 | _T_EXG=74,
93 | _T_EXT=75,
94 | _T_FUNC=76,
95 | _T_IF=77,
96 | _T_ILLEGAL=78,
97 | _T_INCLUDE=79,
98 | _T_JMP=80,
99 | _T_JSR=81,
100 | _T_LEA=82,
101 | _T_LINK=83,
102 | _T_LIST=84,
103 | _T_LONG=85,
104 | _T_LSL=86,
105 | _T_LSR=87,
106 | _T_MACRO=88,
107 | _T_MACROLIST=89,
108 | _T_MOVE=90,
109 | _T_MOVEA=91,
110 | _T_MOVEM=92,
111 | _T_MOVEP=93,
112 | _T_MOVEQ=94,
113 | _T_MULS=95,
114 | _T_MULU=96,
115 | _T_NBCD=97,
116 | _T_NEG=98,
117 | _T_NEGX=99,
118 | _T_NOLIST=100,
119 | _T_NOMACROLIST=101,
120 | _T_NOP=102,
121 | _T_NOPATCHLIST=103,
122 | _T_NOT=104,
123 | _T_OR=105,
124 | _T_ORG=106,
125 | _T_ORI=107,
126 | _T_PAGE=108,
127 | _T_PATCHLIST=109,
128 | _T_PEA=110,
129 | _T_PROC=111,
130 | _T_REF=112,
131 | _T_RESET=113,
132 | _T_ROL=114,
133 | _T_ROR=115,
134 | _T_RORG=116,
135 | _T_ROXL=117,
136 | _T_ROXR=118,
137 | _T_RTE=119,
138 | _T_RTR=120,
139 | _T_RTS=121,
140 | _T_SBCD=122,
141 | _T_SEG=123,
142 | _T_SNE=124,
143 | _T_STOP=125,
144 | _T_SUB=126,
145 | _T_SUBA=127,
146 | _T_SUBI=128,
147 | _T_SUBQ=129,
148 | _T_SUBX=130,
149 | _T_SWAP=131,
150 | _T_TAS=132,
151 | _T_TITLE=133,
152 | _T_TRAP=134,
153 | _T_TRAPV=135,
154 | _T_TST=136,
155 | _T_UNLK=137,
156 | _T_WORD=138,
157 | _T_Specials_=139,
158 | _T_macrocall=140,
159 | _T_number=141,
160 | _T_string=142,
161 | _T_ident=143,
162 | _T_substitute=144,
163 | _T_label=145,
164 | _T_Comment=146,
165 | _T_eol=147,
166 | _T_dotW=148,
167 | _T_dotL=149,
168 | _T_dotB=150,
169 | _T_dotS=151,
170 | _T_Eof=152,
171 | _T_MaxToken_=153
172 | };
173 | int maxT;
174 |
175 | int errDist;
176 | int minErrDist;
177 |
178 | void SynErr(int n, const char* ctx = 0);
179 | void Get();
180 | void Expect(int n, const char* ctx = 0);
181 | bool StartOf(int s);
182 | void ExpectWeak(int n, int follow);
183 | bool WeakSeparator(int n, int syFol, int repFol);
184 | void SynErr(int line, int col, int n, const char* ctx, const QString&, const QString& path );
185 |
186 | public:
187 | PpLexer *scanner;
188 | struct Error
189 | {
190 | QString msg;
191 | int row, col;
192 | QString path;
193 | };
194 | QList errors;
195 |
196 | void error(int row, int col, const QString& msg, const QString& path)
197 | {
198 | Error e;
199 | e.row = row;
200 | e.col = col;
201 | e.msg = msg;
202 | e.path = path;
203 | errors.append(e);
204 | }
205 |
206 | Token d_cur;
207 | Token d_next;
208 | QList d_comments;
209 | struct TokDummy
210 | {
211 | int kind;
212 | };
213 | TokDummy d_dummy;
214 | TokDummy *la; // lookahead token
215 |
216 | int peek( quint8 la = 1 );
217 |
218 | void RunParser();
219 |
220 |
221 | Asm::SynTree d_root;
222 | QStack d_stack;
223 | void addTerminal() {
224 | Asm::SynTree* n = new Asm::SynTree( d_cur ); d_stack.top()->d_children.append(n);
225 | }
226 |
227 |
228 |
229 | Parser(PpLexer *scanner);
230 | ~Parser();
231 | void SemErr(const char* msg);
232 |
233 | void program();
234 | void line();
235 | void term();
236 | void size();
237 | void addrop();
238 | void expression();
239 | void directive();
240 | void statement();
241 | void argument();
242 | void filename();
243 | void macrodef();
244 | void mnemonic();
245 | void reg();
246 | void factor();
247 | void op();
248 |
249 | void Parse();
250 |
251 | }; // end Parser
252 |
253 | } // namespace
254 |
255 |
256 | #endif
257 |
258 |
--------------------------------------------------------------------------------
/LisaAsm.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | ** Copyright (C) 2023 Rochus Keller (me@rochus-keller.ch)
3 | **
4 | ** This file is part of the LisaPascal project.
5 | **
6 | ** $QT_BEGIN_LICENSE:LGPL21$
7 | ** GNU Lesser General Public License Usage
8 | ** This file may be used under the terms of the GNU Lesser
9 | ** General Public License version 2.1 or version 3 as published by the Free
10 | ** Software Foundation and appearing in the file LICENSE.LGPLv21 and
11 | ** LICENSE.LGPLv3 included in the packaging of this file. Please review the
12 | ** following information to ensure the GNU Lesser General Public License
13 | ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
14 | ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
15 | */
16 |
17 | #include "AsmPpLexer.h"
18 | #include "AsmParser.h"
19 | #include
20 | #include
21 | #include
22 | #include
23 |
24 | static void dump(QTextStream& out, const Asm::SynTree* node, int level)
25 | {
26 | QByteArray str;
27 | if( node->d_tok.d_type == Asm::Tok_Invalid )
28 | level--;
29 | else if( node->d_tok.d_type < Asm::SynTree::R_First )
30 | {
31 | if( Asm::tokenTypeIsKeyword( node->d_tok.d_type ) )
32 | str = Asm::tokenTypeString(node->d_tok.d_type);
33 | else if( node->d_tok.d_type > Asm::TT_Specials )
34 | str = QByteArray("\"") + node->d_tok.d_val + QByteArray("\"");
35 | else
36 | str = QByteArray("\"") + Asm::tokenTypeString(node->d_tok.d_type) + QByteArray("\"");
37 |
38 | }else
39 | str = Asm::SynTree::rToStr( node->d_tok.d_type );
40 | if( !str.isEmpty() )
41 | {
42 | str += QByteArray("\t") + QFileInfo(node->d_tok.d_sourcePath).baseName().toUtf8() +
43 | ":" + QByteArray::number(node->d_tok.d_lineNr) +
44 | ":" + QByteArray::number(node->d_tok.d_colNr);
45 | QByteArray ws;
46 | for( int i = 0; i < level; i++ )
47 | ws += "| ";
48 | str = ws + str;
49 | out << str.data() << endl;
50 | }
51 | foreach( Asm::SynTree* sub, node->d_children )
52 | dump( out, sub, level + 1 );
53 | }
54 |
55 | QStringList collectFiles( const QDir& dir, const QStringList& suffix )
56 | {
57 | QStringList res;
58 | QStringList files = dir.entryList( QDir::Dirs | QDir::NoDotAndDotDot, QDir::Name );
59 |
60 | foreach( const QString& f, files )
61 | res += collectFiles( QDir( dir.absoluteFilePath(f) ), suffix );
62 |
63 | files = dir.entryList( suffix, QDir::Files, QDir::Name );
64 | foreach( const QString& f, files )
65 | {
66 | res.append(dir.absoluteFilePath(f));
67 | }
68 | return res;
69 | }
70 |
71 | int main(int argc, char *argv[])
72 | {
73 | QCoreApplication a(argc, argv);
74 |
75 | if( a.arguments().size() <= 1 )
76 | return -1;
77 |
78 | #if 0
79 | QStringList files;
80 |
81 | if( QFileInfo(a.arguments()[1]).isDir() )
82 | files = collectFiles(a.arguments()[1],QStringList() << "*.asm");
83 | else
84 | files << a.arguments()[1];
85 |
86 | int ok = 0;
87 | foreach( const QString& file, files )
88 | {
89 | qDebug() << "***** lexing" << file;
90 | Asm::Lexer lex;
91 | //lex.setIgnoreComments(false);
92 | QFile in(file);
93 | if( !in.open(QIODevice::ReadOnly) )
94 | return -1;
95 | lex.setStream(&in);
96 | Asm::Token t = lex.nextToken();
97 | int n = 0, count = 0;
98 | while( t.isValid() )
99 | {
100 | #if 0
101 | count++;
102 | if( t.isDirective() && t.d_dotPrefix )
103 | n++;
104 | if( count == 10 && n == 0 )
105 | qDebug() << "file has no .DIRECTIVE in the first ten tokens" << QFileInfo(file).baseName();
106 | // there are 30 files to which this applies, e.g. libhw-cursor, machine, mouse, or libfp-elems68k2
107 | #endif
108 | //if( t.d_type == Asm::Tok_5c )
109 | qDebug() << t.d_lineNr << t.d_colNr << Asm::tokenTypeName(t.d_type) << t.d_val;
110 | t = lex.nextToken();
111 | }
112 | if( t.d_type == Asm::Tok_Invalid )
113 | {
114 | qCritical() << t.d_sourcePath << t.d_lineNr << t.d_colNr << t.d_val;
115 | return -1;
116 | }
117 | }
118 | #else
119 | Lisa::FileSystem fs;
120 | fs.load(a.arguments()[1]);
121 | QList files = fs.getAllAsm();
122 | int ok = 0;
123 | foreach( const Lisa::FileSystem::File* f, files )
124 | {
125 | Asm::PpLexer lex(&fs);
126 | lex.reset(f->d_realPath);
127 | Asm::Parser p(&lex);
128 | //qDebug() << "**** parsing" << file;
129 | p.RunParser();
130 | if( !p.errors.isEmpty() )
131 | {
132 | foreach( const Asm::Parser::Error& e, p.errors )
133 | qCritical() << f->getVirtualPath() << e.row << e.col << e.msg;
134 |
135 | }else
136 | {
137 | ok++;
138 | //qDebug() << "ok";
139 | }
140 | #if 0
141 | QFile out(f->d_realPath + ".st");
142 | out.open(QIODevice::WriteOnly);
143 | QTextStream s(&out);
144 | dump(s,&p.d_root,0);
145 | #endif
146 | }
147 | #endif
148 | qDebug() << "#### finished with" << ok << "files ok of total" << files.size() << "files";
149 |
150 | return 0;
151 | }
152 |
--------------------------------------------------------------------------------
/LisaSynTree.cpp:
--------------------------------------------------------------------------------
1 | // This file was automatically generated by EbnfStudio; don't modify it!
2 | #include "LisaSynTree.h"
3 | using namespace Lisa;
4 |
5 | SynTree::SynTree(quint16 r, const Token& t ):d_tok(r){
6 | d_tok.d_lineNr = t.d_lineNr;
7 | d_tok.d_colNr = t.d_colNr;
8 | d_tok.d_sourcePath = t.d_sourcePath;
9 | }
10 |
11 | const char* SynTree::rToStr( quint16 r ) {
12 | switch(r) {
13 | case R_LisaPascal: return "LisaPascal";
14 | case R_actual_parameter: return "actual_parameter";
15 | case R_actual_parameter_list: return "actual_parameter_list";
16 | case R_addition_operator: return "addition_operator";
17 | case R_array_type: return "array_type";
18 | case R_assigOrCall: return "assigOrCall";
19 | case R_assignment_statement_: return "assignment_statement";
20 | case R_block: return "block";
21 | case R_body_: return "body_";
22 | case R_case_label_list: return "case_label_list";
23 | case R_case_limb: return "case_limb";
24 | case R_case_statement: return "case_statement";
25 | case R_class_type: return "class_type";
26 | case R_comment_: return "comment";
27 | case R_compound_statement: return "compound_statement";
28 | case R_conditional_statement: return "conditional_statement";
29 | case R_constant: return "constant";
30 | case R_constant_declaration: return "constant_declaration";
31 | case R_constant_declaration_part: return "constant_declaration_part";
32 | case R_constant_identifier_: return "constant_identifier";
33 | case R_dereferencer: return "dereferencer";
34 | case R_enumerated_type: return "enumerated_type";
35 | case R_expression: return "expression";
36 | case R_expression_list: return "expression_list";
37 | case R_factor: return "factor";
38 | case R_field_declaration: return "field_declaration";
39 | case R_field_designator: return "field_designator";
40 | case R_field_identifier: return "field_identifier";
41 | case R_field_list: return "field_list";
42 | case R_file_type: return "file_type";
43 | case R_final_value: return "final_value";
44 | case R_fixed_part: return "fixed_part";
45 | case R_for_statement: return "for_statement";
46 | case R_formal_parameter_list: return "formal_parameter_list";
47 | case R_formal_parameter_section: return "formal_parameter_section";
48 | case R_function_declaration: return "function_declaration";
49 | case R_function_heading: return "function_heading";
50 | case R_function_identifier_: return "function_identifier";
51 | case R_goto_statement: return "goto_statement";
52 | case R_identifier_list: return "identifier_list";
53 | case R_identifier_list2: return "identifier_list2";
54 | case R_if_statement: return "if_statement";
55 | case R_implementation_part: return "implementation_part";
56 | case R_index: return "index";
57 | case R_index_type: return "index_type";
58 | case R_initial_value: return "initial_value";
59 | case R_interface_part: return "interface_part";
60 | case R_label_: return "label_";
61 | case R_label_declaration_part: return "label_declaration_part";
62 | case R_member_group: return "member_group";
63 | case R_method_block: return "method_block";
64 | case R_method_interface: return "method_interface";
65 | case R_multiplication_operator: return "multiplication_operator";
66 | case R_non_regular_unit: return "non_regular_unit";
67 | case R_ordinal_type: return "ordinal_type";
68 | case R_otherwise_clause: return "otherwise_clause";
69 | case R_parameter_declaration: return "parameter_declaration";
70 | case R_pointer_type: return "pointer_type";
71 | case R_procedure_and_function_declaration_part: return "procedure_and_function_declaration_part";
72 | case R_procedure_and_function_interface_part: return "procedure_and_function_interface_part";
73 | case R_procedure_declaration: return "procedure_declaration";
74 | case R_procedure_heading: return "procedure_heading";
75 | case R_procedure_identifier_: return "procedure_identifier";
76 | case R_procedure_statement_: return "procedure_statement";
77 | case R_program_: return "program_";
78 | case R_program_heading: return "program_heading";
79 | case R_program_parameters: return "program_parameters";
80 | case R_qualifier: return "qualifier";
81 | case R_record_type: return "record_type";
82 | case R_regular_unit: return "regular_unit";
83 | case R_relational_operator: return "relational_operator";
84 | case R_repeat_statement: return "repeat_statement";
85 | case R_repetitive_statement: return "repetitive_statement";
86 | case R_result_type: return "result_type";
87 | case R_set_literal: return "set_literal";
88 | case R_set_type: return "set_type";
89 | case R_sign: return "sign";
90 | case R_simple_expression: return "simple_expression";
91 | case R_simple_statement: return "simple_statement";
92 | case R_simple_type: return "simple_type";
93 | case R_size_attribute: return "size_attribute";
94 | case R_statement: return "statement";
95 | case R_statement_part: return "statement_part";
96 | case R_statement_sequence: return "statement_sequence";
97 | case R_string_type: return "string_type";
98 | case R_structured_statement: return "structured_statement";
99 | case R_structured_type: return "structured_type";
100 | case R_subrange_type: return "subrange_type";
101 | case R_subroutine_part: return "subroutine_part";
102 | case R_tag_field: return "tag_field";
103 | case R_term: return "term";
104 | case R_type_: return "type_";
105 | case R_type_declaration: return "type_declaration";
106 | case R_type_declaration_part: return "type_declaration_part";
107 | case R_type_identifier: return "type_identifier";
108 | case R_unit_heading: return "unit_heading";
109 | case R_unsigned_integer: return "unsigned_integer";
110 | case R_unsigned_number: return "unsigned_number";
111 | case R_uses_clause: return "uses_clause";
112 | case R_variable_declaration: return "variable_declaration";
113 | case R_variable_declaration_part: return "variable_declaration_part";
114 | case R_variable_identifier: return "variable_identifier";
115 | case R_variable_reference: return "variable_reference";
116 | case R_variant: return "variant";
117 | case R_variant_part: return "variant_part";
118 | case R_while_statement: return "while_statement";
119 | case R_with_statement: return "with_statement";
120 | default: if(r
20 | using namespace Lisa;
21 |
22 | // stats: ("F", 57)("OBJ", 8)("TEXT", 109)("text", 9)("txt", 1092)
23 | // *.F -> font
24 | // *.OBJ -> object files; source available unless TK-ALERT, TK-NullChange, TK-WorkDir, libtk-passwd and IconEdit
25 | // *.TEXT, *.text -> looks like different kinds of sources covered in binary format
26 | // *.txt -> Lisa Pascal (614/1092) or assembler source files
27 |
28 | // NOTES:
29 | // both (*$ and {$ are used for directives
30 | // there are no $DECL in files categorized as .inc;
31 | // but there are a lot of $IFC in .inc files (even $I in two cases);
32 | // we can assume that the decls of the including file also apply to included files
33 | // each pascal file has the suffix "text.unix.txt" with no exception
34 |
35 | QStringList Converter::collectFiles( const QDir& dir, const QStringList& suffix )
36 | {
37 | QStringList res;
38 | QStringList files = dir.entryList( QDir::Dirs | QDir::NoDotAndDotDot, QDir::Name );
39 |
40 | foreach( const QString& f, files )
41 | res += collectFiles( QDir( dir.absoluteFilePath(f) ), suffix );
42 |
43 | files = dir.entryList( suffix, QDir::Files, QDir::Name );
44 | foreach( const QString& f, files )
45 | {
46 | res.append(dir.absoluteFilePath(f));
47 | }
48 | return res;
49 | }
50 |
51 | int Converter::detectPascal( QIODevice* in )
52 | {
53 | Q_ASSERT(in->reset());
54 | Lexer lex;
55 | lex.setStream(in);
56 | lex.setIgnoreComments(false);
57 | Token t = lex.nextToken();
58 | int res = Unknown;
59 | while( t.isValid() )
60 | {
61 | switch(t.d_type)
62 | {
63 | case Tok_Comment:
64 | if( t.d_val.startsWith("(*") || t.d_val.startsWith("{$") )
65 | res = AnyPascal;
66 | break;
67 | case Tok_program:
68 | case Tok_unit:
69 | return FullUnit;
70 | case Tok_function:
71 | case Tok_procedure:
72 | case Tok_const:
73 | #ifdef LISA_CLASCAL
74 | case Tok_methods:
75 | #endif
76 | // exceptions: aplw-compflags
77 | return PartialUnit;
78 | default:
79 | return res;
80 | }
81 |
82 | t = lex.nextToken();
83 | }
84 | return res;
85 | }
86 |
87 | bool Converter::detectAsm( QIODevice* in )
88 | {
89 | Q_ASSERT(in->reset());
90 | int lastSemi = -1;
91 | int count = 0;
92 | bool semiStretch = false;
93 | int mnemonic = 0;
94 | for( int i = 0; i < 50; i++ )
95 | {
96 | const QByteArray line = in->readLine().trimmed().toUpper();
97 | if( line.startsWith(';') )
98 | {
99 | if( lastSemi == -1 || lastSemi == (i - 1) )
100 | {
101 | count++;
102 | lastSemi = i;
103 | if( count >= 15 )
104 | semiStretch = true;
105 | }else
106 | {
107 | count = 0;
108 | lastSemi = -1;
109 | }
110 | }else
111 | {
112 | count = 0;
113 | lastSemi = -1;
114 | if( line.startsWith(".SEG") || line.startsWith(".PROC") || line.startsWith(".FUNC")
115 | || line.startsWith(".REF") || line.startsWith(".SEG")
116 | || line.startsWith(".WORD") || line.startsWith(".BYTE")
117 | || line.startsWith("BGE.S") || line.startsWith("BNE.S")
118 | || line.startsWith("MOVE.W") || line.startsWith("TST.W")
119 | || line.startsWith("MOVE.L")
120 | || line.contains(".EQU ")
121 | )
122 | mnemonic++;
123 | }
124 | }
125 | return semiStretch || mnemonic;
126 | }
127 |
128 | bool Converter::detectScript(QIODevice* in )
129 | {
130 | Q_ASSERT(in->reset());
131 | const QByteArray line = in->readLine().trimmed().toUpper();
132 | const bool found = line.startsWith("$EXEC") || line.startsWith("EXEC(");
133 | return found;
134 | }
135 |
136 | // assembler files have asm, 68k in the filename
137 | // exceptions: apll-qicode apll-stgcomp apll-xxfer aplt-convert aplw-fastgen aplw-sp-util appw-xfer
138 | // libhw-cursor libhw-drivers libhw-hwiequ libhw-hwintl libhw-keybd libhw-legends libhw-machine libhw-mouse
139 | // libhw-sprkeybd libhw-timers libam-alertprocs libdb-qsort libfp-bindec1/2/3
140 | // actually all assembler files start with a few lines where each starts with a ';'
141 | // command files start with $EXEC, there are many of these
142 | // menu files start with 1
143 | // clascal files: libtk-uabc4, libtk-uabc3, and seven more in lisa_toolkit/tk3/4/5
144 |
145 | bool Converter::convert(const QDir& fromDir, const QDir& toDir)
146 | {
147 | const int off = fromDir.path().size();
148 | const QStringList files = collectFiles(fromDir, QStringList() << "*.txt");
149 | foreach( const QString& f, files )
150 | {
151 | QString newFilePath = toDir.absoluteFilePath(f.mid(off+1).toLower());
152 | if( newFilePath.endsWith("text.unix.txt") )
153 | newFilePath.chop(13);
154 | else if(newFilePath.endsWith("unix.txt") )
155 | newFilePath.chop(8);
156 | else if(newFilePath.endsWith("txt") )
157 | newFilePath.chop(3);
158 | const QString name = QFileInfo(f).baseName().toLower();
159 | const QString newDirPath = QFileInfo(f).dir().path().mid(off+1).toLower();
160 | if( !newDirPath.isEmpty() )
161 | toDir.mkpath( newDirPath );
162 | QFile in(f);
163 | in.open(QIODevice::ReadOnly);
164 |
165 | const int kind = detectPascal(&in);
166 | if( kind == FullUnit )
167 | newFilePath += "pas";
168 | else if( kind == PartialUnit || kind == AnyPascal )
169 | {
170 | newFilePath += "inc";
171 | //qDebug() << QFileInfo(newFilePath).baseName();
172 | }else if( detectScript(&in) )
173 | newFilePath += "sh";
174 | else if( detectAsm(&in) || name.contains("asm") || name.contains("68k") )
175 | newFilePath += "asm";
176 | else
177 | newFilePath += "txt";
178 |
179 | Q_ASSERT(in.reset());
180 | QFile out(newFilePath);
181 | if( !out.open(QIODevice::WriteOnly) )
182 | {
183 | qCritical() << "### cannot open for writing:" << newFilePath;
184 | continue;
185 | }
186 | QByteArray text = in.readAll();
187 | if( text.endsWith(0xff) )
188 | text.chop(1);
189 | if( text.size() != out.write(text) )
190 | {
191 | qCritical() << "### could not write everything to:" << newFilePath;
192 | continue;
193 | }
194 | }
195 | return true;
196 | }
197 |
--------------------------------------------------------------------------------
/AsmPpLexer.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | ** Copyright (C) 2023 Rochus Keller (me@rochus-keller.ch)
3 | **
4 | ** This file is part of the LisaPascal project.
5 | **
6 | ** $QT_BEGIN_LICENSE:LGPL21$
7 | ** GNU Lesser General Public License Usage
8 | ** This file may be used under the terms of the GNU Lesser
9 | ** General Public License version 2.1 or version 3 as published by the Free
10 | ** Software Foundation and appearing in the file LICENSE.LGPLv21 and
11 | ** LICENSE.LGPLv3 included in the packaging of this file. Please review the
12 | ** following information to ensure the GNU Lesser General Public License
13 | ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
14 | ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
15 | */
16 |
17 | #include "AsmPpLexer.h"
18 | #include
19 | #include
20 | #include
21 | using namespace Asm;
22 | using namespace Lisa;
23 |
24 | PpLexer::PpLexer(FileSystem* fs):d_fs(fs),d_sloc(0)
25 | {
26 | Q_ASSERT(fs);
27 | }
28 |
29 | PpLexer::~PpLexer()
30 | {
31 | for( int i = 0; i < d_files.size(); i++ )
32 | delete d_files[i];
33 | }
34 |
35 | bool PpLexer::reset(const QString& filePath)
36 | {
37 | d_stack.clear();
38 | d_buffer.clear();
39 | for( int i = 0; i < d_files.size(); i++ )
40 | delete d_files[i];
41 | d_files.clear();
42 | d_sloc = 0;
43 | d_includes.clear();
44 |
45 | const FileSystem::File* f = d_fs->findFile(filePath);
46 | if( f == 0 )
47 | return false;
48 | d_stack.push_back(Level());
49 | QFile* file = new QFile(filePath);
50 | if( !file->open(QIODevice::ReadOnly) )
51 | {
52 | delete file;
53 | d_stack.pop_back();
54 | return false;
55 | }
56 | d_stack.back().d_lex.setStream(file,filePath);
57 | d_stack.back().d_lex.setMacros(&d_macros);
58 | return true;
59 | }
60 |
61 | Token PpLexer::nextToken()
62 | {
63 | Token t;
64 | if( !d_buffer.isEmpty() )
65 | {
66 | t = d_buffer.first();
67 | d_buffer.pop_front();
68 | }else
69 | t = nextTokenImp();
70 | Q_ASSERT( t.d_type != Tok_Comment );
71 | return t;
72 | }
73 |
74 | Token PpLexer::peekToken(quint8 lookAhead)
75 | {
76 | Q_ASSERT( lookAhead > 0 );
77 | while( d_buffer.size() < lookAhead )
78 | {
79 | Token t = nextTokenImp();
80 | Q_ASSERT( t.d_type != Tok_Comment );
81 | d_buffer.push_back( t );
82 | }
83 | return d_buffer[ lookAhead - 1 ];
84 | }
85 |
86 | Token PpLexer::nextTokenImp()
87 | {
88 | if( d_stack.isEmpty() )
89 | return Token(Tok_Eof);
90 | Token t = d_stack.back().d_lex.nextToken();
91 | while( t.d_type == Tok_Comment || t.d_type == Tok_Eof )
92 | {
93 | if( t.d_type == Tok_Eof )
94 | {
95 | d_files.removeAll(d_stack.back().d_lex.getDevice());
96 | delete d_stack.back().d_lex.getDevice();
97 | d_sloc += d_stack.back().d_lex.getSloc();
98 | d_mutes.insert(t.d_sourcePath, d_stack.back().d_mutes);
99 | d_stack.pop_back();
100 | if( d_stack.isEmpty() )
101 | return Token(Tok_Eof);
102 | }
103 | t = d_stack.back().d_lex.nextToken();
104 | }
105 | while( t.d_type == Tok_INCLUDE )
106 | {
107 | if( !handleInclude(t) )
108 | {
109 | Token err(Tok_Invalid,t.d_lineNr,t.d_colNr,d_err.toUtf8());
110 | err.d_sourcePath = t.d_sourcePath;
111 | return err;
112 | }
113 | t = d_stack.back().d_lex.nextToken();
114 | }
115 | return t;
116 | }
117 |
118 | bool PpLexer::handleInclude(Token t)
119 | {
120 | const FileSystem::File* f = d_fs->findFile(t.d_sourcePath);
121 | Q_ASSERT( f );
122 |
123 | QStringList path;
124 | int line = t.d_lineNr, startCol = 0, endCol = 0;
125 | while( t.isValid() && t.d_type != Tok_eol )
126 | {
127 | t = d_stack.back().d_lex.nextToken();
128 | if( t.d_type == Tok_ident )
129 | {
130 | if( startCol == 0 )
131 | startCol = t.d_colNr;
132 | path.append( QString::fromUtf8(t.d_val).toLower() );
133 | endCol = t.d_val.size() + t.d_colNr;
134 | }
135 | }
136 |
137 | QString fileName = path.last();
138 | if( fileName.endsWith(".text") )
139 | fileName.chop(5);
140 | const FileSystem::File* found = 0;
141 | // TODO: find can still be improved
142 | if( path.size() == 1 )
143 | {
144 | found = d_fs->findFile(f->d_dir, QString(), fileName);
145 | }else if( path.size() == 2 )
146 | found = d_fs->findFile(f->d_dir, path[0], fileName);
147 |
148 | Include inc;
149 | inc.d_inc = found;
150 | inc.d_loc = RowCol(line,startCol);
151 | inc.d_sourcePath = t.d_sourcePath;
152 | inc.d_len = endCol - startCol;
153 | d_includes.append(inc);
154 | d_err.clear();
155 | if( found )
156 | {
157 | d_stack.push_back(Level());
158 | QFile* file = new QFile(found->d_realPath);
159 | if( !file->open(QIODevice::ReadOnly) )
160 | {
161 | delete file;
162 | d_stack.pop_back();
163 | d_err = QString("file '%1' cannot be opened").arg(path.join('/')).toUtf8();
164 | }else
165 | {
166 | d_stack.back().d_lex.setStream(file,found->d_realPath);
167 | d_stack.back().d_lex.setMacros(&d_macros);
168 | }
169 | }else
170 | d_err = QString("assembler include file '%1' not found").arg(path.join('/')).toUtf8();
171 | return found;
172 | }
173 |
174 | bool PpLexer::handleSetc(const QByteArray& data)
175 | {
176 | #if 0
177 | // TODO
178 | QByteArray statement = data;
179 | QBuffer buf(&statement);
180 | buf.open(QIODevice::ReadOnly);
181 | Lexer lex;
182 | lex.setStream(&buf);
183 | Token tt = lex.nextToken();
184 | if( tt.d_type != Tok_ident )
185 | return error("expecting identifier on left side of SETC assignment");
186 | const QByteArray var = tt.d_val.toLower();
187 | if( var == "true" || var == "false" )
188 | return error("cannot assign to true or false in SETC");
189 | tt = lex.nextToken();
190 | if( tt.d_type != Tok_ColonEq && tt.d_type != Tok_Eq )
191 | return error("expecting ':=' or '=' in SETC assignment");
192 | PpEval e(d_ppVars,lex);
193 | if( !e.eval() )
194 | return error(QString("%1 in SETC expression").arg(e.getErr().constData()));
195 | d_ppVars[var] = e.getRes();
196 | #endif
197 | return true;
198 | }
199 |
200 | bool PpLexer::handleIfc(const QByteArray& data)
201 | {
202 | #if 0
203 | // TODO
204 | QByteArray statement = data;
205 | QBuffer buf(&statement);
206 | buf.open(QIODevice::ReadOnly);
207 | Lexer lex;
208 | lex.setStream(&buf);
209 | PpEval e(d_ppVars,lex);
210 | if( !e.eval() )
211 | return error(QString("%1 in SETC expression").arg(e.getErr().constData()));
212 |
213 | const bool cond = e.getRes();
214 | d_conditionStack.append( ppstatus(false) );
215 | ppsetthis( ppouter().open && cond );
216 | #endif
217 | return true;
218 | }
219 |
220 | bool PpLexer::handleElsec()
221 | {
222 | if( ppthis().elseSeen || d_conditionStack.isEmpty() )
223 | return error("ELSEC not expected here");
224 | else
225 | ppsetthis( ppouter().open && !ppthis().openSeen, true );
226 | return true;
227 | }
228 |
229 | bool PpLexer::handleEndc()
230 | {
231 | if( d_conditionStack.isEmpty() )
232 | return error("spurious ENDC");
233 | else
234 | d_conditionStack.pop_back();
235 | return true;
236 | }
237 |
238 | bool PpLexer::error(const QString& msg)
239 | {
240 | d_err = msg;
241 | return false;
242 | }
243 |
244 |
--------------------------------------------------------------------------------
/LICENSE.LGPLv3:
--------------------------------------------------------------------------------
1 | GNU LESSER GENERAL PUBLIC LICENSE
2 | Version 3, 29 June 2007
3 |
4 | Copyright © 2007 Free Software Foundation, Inc.
5 | Everyone is permitted to copy and distribute verbatim copies of this
6 | licensedocument, but changing it is not allowed.
7 |
8 | This version of the GNU Lesser General Public License incorporates
9 | the terms and conditions of version 3 of the GNU General Public
10 | License, supplemented by the additional permissions listed below.
11 |
12 | 0. Additional Definitions.
13 |
14 | As used herein, “this License” refers to version 3 of the GNU Lesser
15 | General Public License, and the “GNU GPL” refers to version 3 of the
16 | GNU General Public License.
17 |
18 | “The Library” refers to a covered work governed by this License,
19 | other than an Application or a Combined Work as defined below.
20 |
21 | An “Application” is any work that makes use of an interface provided
22 | by the Library, but which is not otherwise based on the Library.
23 | Defining a subclass of a class defined by the Library is deemed a mode
24 | of using an interface provided by the Library.
25 |
26 | A “Combined Work” is a work produced by combining or linking an
27 | Application with the Library. The particular version of the Library
28 | with which the Combined Work was made is also called the “Linked
29 | Version”.
30 |
31 | The “Minimal Corresponding Source” for a Combined Work means the
32 | Corresponding Source for the Combined Work, excluding any source code
33 | for portions of the Combined Work that, considered in isolation, are
34 | based on the Application, and not on the Linked Version.
35 |
36 | The “Corresponding Application Code” for a Combined Work means the
37 | object code and/or source code for the Application, including any data
38 | and utility programs needed for reproducing the Combined Work from the
39 | Application, but excluding the System Libraries of the Combined Work.
40 |
41 | 1. Exception to Section 3 of the GNU GPL.
42 |
43 | You may convey a covered work under sections 3 and 4 of this License
44 | without being bound by section 3 of the GNU GPL.
45 |
46 | 2. Conveying Modified Versions.
47 |
48 | If you modify a copy of the Library, and, in your modifications, a
49 | facility refers to a function or data to be supplied by an Application
50 | that uses the facility (other than as an argument passed when the
51 | facility is invoked), then you may convey a copy of the modified
52 | version:
53 |
54 | a) under this License, provided that you make a good faith effort
55 | to ensure that, in the event an Application does not supply the
56 | function or data, the facility still operates, and performs
57 | whatever part of its purpose remains meaningful, or
58 |
59 | b) under the GNU GPL, with none of the additional permissions of
60 | this License applicable to that copy.
61 |
62 | 3. Object Code Incorporating Material from Library Header Files.
63 |
64 | The object code form of an Application may incorporate material from
65 | a header file that is part of the Library. You may convey such object
66 | code under terms of your choice, provided that, if the incorporated
67 | material is not limited to numerical parameters, data structure
68 | layouts and accessors, or small macros, inline functions and templates
69 | (ten or fewer lines in length), you do both of the following:
70 |
71 | a) Give prominent notice with each copy of the object code that
72 | the Library is used in it and that the Library and its use are
73 | covered by this License.
74 |
75 | b) Accompany the object code with a copy of the GNU GPL and this
76 | license document.
77 |
78 | 4. Combined Works.
79 |
80 | You may convey a Combined Work under terms of your choice that, taken
81 | together, effectively do not restrict modification of the portions of
82 | the Library contained in the Combined Work and reverse engineering for
83 | debugging such modifications, if you also do each of the following:
84 |
85 | a) Give prominent notice with each copy of the Combined Work that
86 | the Library is used in it and that the Library and its use are
87 | covered by this License.
88 |
89 | b) Accompany the Combined Work with a copy of the GNU GPL and this
90 | license document.
91 |
92 | c) For a Combined Work that displays copyright notices during
93 | execution, include the copyright notice for the Library among
94 | these notices, as well as a reference directing the user to the
95 | copies of the GNU GPL and this license document.
96 |
97 | d) Do one of the following:
98 |
99 | 0) Convey the Minimal Corresponding Source under the terms of
100 | this License, and the Corresponding Application Code in a form
101 | suitable for, and under terms that permit, the user to
102 | recombine or relink the Application with a modified version of
103 | the Linked Version to produce a modified Combined Work, in the
104 | manner specified by section 6 of the GNU GPL for conveying
105 | Corresponding Source.
106 |
107 | 1) Use a suitable shared library mechanism for linking with
108 | the Library. A suitable mechanism is one that (a) uses at run
109 | time a copy of the Library already present on the user's
110 | computer system, and (b) will operate properly with a modified
111 | version of the Library that is interface-compatible with the
112 | Linked Version.
113 |
114 | e) Provide Installation Information, but only if you would
115 | otherwise be required to provide such information under section 6
116 | of the GNU GPL, and only to the extent that such information is
117 | necessary to install and execute a modified version of the
118 | Combined Work produced by recombining or relinking the Application
119 | with a modified version of the Linked Version. (If you use option
120 | 4d0, the Installation Information must accompany the Minimal
121 | Corresponding Source and Corresponding Application Code. If you
122 | use option 4d1, you must provide the Installation Information in
123 | the manner specified by section 6 of the GNU GPL for conveying
124 | Corresponding Source.)
125 |
126 | 5. Combined Libraries.
127 |
128 | You may place library facilities that are a work based on the Library
129 | side by side in a single library together with other library
130 | facilities that are not Applications and are not covered by this
131 | License, and convey such a combined library under terms of your
132 | choice, if you do both of the following:
133 |
134 | a) Accompany the combined library with a copy of the same work
135 | based on the Library, uncombined with any other library
136 | facilities, conveyed under the terms of this License.
137 |
138 | b) Give prominent notice with the combined library that part of
139 | it is a work based on the Library, and explaining where to find
140 | the accompanying uncombined form of the same work.
141 |
142 | 6. Revised Versions of the GNU Lesser General Public License.
143 |
144 | The Free Software Foundation may publish revised and/or new versions
145 | of the GNU Lesser General Public License from time to time. Such new
146 | versions will be similar in spirit to the present version, but may
147 | differ in detail to address new problems or concerns.
148 |
149 | Each version is given a distinguishing version number. If the Library
150 | as you received it specifies that a certain numbered version of the
151 | GNU Lesser General Public License “or any later version” applies to
152 | it, you have the option of following the terms and conditions either
153 | of that published version or of any later version published by the
154 | Free Software Foundation. If the Library as you received it does not
155 | specify a version number of the GNU Lesser General Public License,
156 | you may choose any version of the GNU Lesser General Public License
157 | ever published by the Free Software Foundation.
158 |
159 | If the Library as you received it specifies that a proxy can decide
160 | whether future versions of the GNU Lesser General Public License shall
161 | apply, that proxy's public statement of acceptance of any version is
162 | permanent authorization for you to choose that version for the Library.
163 |
164 |
--------------------------------------------------------------------------------
/Readme.md:
--------------------------------------------------------------------------------
1 | This is a parser and code navigator for the Lisa Pascal dialect and associated assembler which I started to implement on January 22, 2023. The reason was that the Computer History Museum published the Apple Lisa source code on January 19, 2023 (see https://computerhistory.org/blog/the-lisa-apples-most-influential-failure/), and I was looking for a tool to study/analyze the code.
2 |
3 | Lisa Pascal was an extension to the Pascal used on the Apple II and III, but not yet object-oriented. I found a [specification of the language here](http://lisa.sunder.net/Pascal_Reference.pdf) which I used to implement the parser. During the project it turned out that also the Lisa OS source tree includes Clascal (~5%), i.e. not only the Lisa Toolkit, and that also a preprocessor had to be implemented to understand the code.
4 |
5 | To develop and debug the grammar I used my [EbnfStudio tool](https://github.com/rochus-keller/EbnfStudio). I started based on a Pascal grammar corresponding to the 1975 version of Wirth and Jensen's "Pascal User Manual & Report" which I found [here](https://www.icosaedro.it/bnf_chk/ebnf-pascal.txt). I then modified this grammar for EbnfStudio compatibility, fixed left recursion and LL(1) ambiguity, and then correlated the grammar with the mentioned "Pascal Reference Manual for the Lisa", which lead to quite a few additions, removals or other changes. After writing a lexer and generating a parser using Coco/R (based on the grammar file generated by EbnfStudio) I adapted the grammar to the actual syntax used in the Lisa source files.
6 |
7 | The Lisa Source code provided by the Computer History Museum contains 1092 plain text source files; further analysis revealed that 614 of which are Pascal and ~203 are MC68000 assembler files; another 126 files are EXEC scripts, and the remaining 144 are emails, documentation, protocols and text resources. About 120 files look like binary encoded sources and other texts which I didn't inspect yet.
8 |
9 | Cloc (http://cloc.sourceforge.net) counts 456 kSLOC, of which 408 kSLOC are Pascal, 45 kSLOC are Assembler and 4 kSLOC are EXEC scripts.
10 |
11 | #### Lisa Code Navigator
12 |
13 | 
14 |
15 | 
16 |
17 | #### Planned features
18 |
19 | My primary goal was to implement tools as I did it e.g. for [Oberon](https://github.com/rochus-keller/Oberon/blob/master/README_old.md) or [Smalltalk](https://github.com/rochus-keller/Smalltalk/blob/master/Readme.md) to analyze the Lisa source code and check it e.g. for completeness and feasibility to compile and run it on a Lisa emulator (such as https://lisa.sunder.net/).
20 |
21 | - [x] Lisa Pascal and Clascal parser, adapted to the source code at hand.
22 | - [x] Preprocessor to include files and employ conditional code directives
23 | - [x] Overlay file system to accomodate original structure and resolve dependencies
24 | - [x] Highlighted code browser
25 | - [x] Mark symbols and navigate from symbols do declarations across all files
26 | - [x] BUSY & LeanQt build
27 | - [x] resolve qualifiers by type for navigation of record fields
28 | - [x] precompiled binary versions for main platforms
29 | - [x] Module detail outline view
30 | - [x] MC68000 assembler integrated with code model and symbol navigation
31 |
32 | #### Features in evaluation
33 |
34 | - [ ] Class hierarchy outline view
35 | - [ ] transpiler to Free Pascal for MC68000 code generation
36 | - [ ] run the code on a Lisa emulator
37 |
38 | #### Status on January 23, 2023
39 |
40 | The parser works in principle; 381 of the 614 Lisa Pascal file found in the source tree parse without an error; most of the other 233 Lisa Pascal files have the same parser error, which is caused because the files are either incomplete or there are alternative parts of the code in the same file. It turned out that the Lisa source code heavily depends on a preprocessor, which is controled by source code directives of the form {$directive arguments}. There is e.g a {$I filepath} directive to include other source files, or an {$IFC variable} directive to enable or mute sections of the file (like #ifdef/#endif in C). Without this preprocessor, which I have not implemented (yet), the mentioned syntax errors cannot be avoided. I e.g. had to add a "non_regular_unit" to the grammar to deal with the fact, that some files only include a part of a program or a unit, so the parser could handle these files; but this is only a provisional fix and to continue the project the implementation of the preprocessor is unavoidable.
41 |
42 | #### Status on January 26, 2023
43 |
44 | The source tree is converted to a virtual file system using the original file names, considering Pascal files only. All program and unit files
45 | of this file system are parsed and include directives are resolved. Of the 360 program or unit files (with includes) 199 parse without an error.
46 | The Lisa toolkit uses Clascal which is not yet supported and leads to parsing errors.
47 |
48 | #### Status on January 28, 2023
49 |
50 | Conditional compilation and the Clascal syntax are implemented and tested. The LISA_OS part of the tree (about 200 kSLOC) parses with no errors but four missing include files. The full source tree (about 400 kSLOC measured with my tools) has 12 missing include files and 7 syntax errors. The 400 kSLOC parse on my machine in less than 7 seconds.
51 |
52 | The CodeNavigator shows the overlay file system (i.e. the one assumed by the source files) with all programs and units; the files can be browsed in a syntax highlighted viewer; semantic navigation is pending.
53 |
54 | #### Status on January 29, 2023
55 |
56 | An AST (as far as required) is constructed from the syntax and symbols are resolved (including imported modules) for crossreferencing. Source code navigation works (e.g. press Ctrl key while moving the cursor over idents and click to navigate to declaration if an underline is visible), but not all idents are indexed yet.
57 | Symbol lookup is too slow in the current implementation; I will do it as I did in my Oberon+ IDE with pointer instead of string comparisons, which requires an extra copy of the ident in lower case; the analysis of the about 400 kSLOC currently requires 11 seconds (instead of 7) on my machine.
58 |
59 | #### Status on January 30, 2023
60 |
61 | After a lot of debugging and fixing source code navigation works as expected (besides some symbols not yet indexed), and also the "Used by" cross-reference list is implemented and can be used for navigation (double-click). Also navigation history is improved (ALT+Left, ALT+Right) und synced with the views.
62 | The indexer now considers the full syntax, including modules and imports, but qualifiers are not yet resolved.
63 | I also implemented internalized strings with comparisons by address instead of by string, and now indexing takes only ~8% more time than just parsing.
64 | There is now also a BUSY build file, see below how to use it.
65 |
66 | #### Status on February 8, 2023
67 |
68 | The MC68000 assembly language parser is implemented and integrated; Pascal procedures marked as external look for assembler implementations in the same virtual directory; the majority of names can be resolved that way (776 vs 534). I also implemented some convenience features like grayed-out sections in Pascal, sizable browser font, marks for unresoved symbols, and more Clascal support. With this release, all features planned so far have been implemented.
69 |
70 | #### Precompiled versions
71 |
72 | The following precompiled versions are available at this time:
73 |
74 | - [Windows x86](http://software.rochus-keller.ch/LisaCodeNavigator_win32.zip)
75 | - [Linux x86_64](http://software.rochus-keller.ch/LisaCodeNavigator_linux64.tar.gz)
76 | - [Mac x86_64](http://software.rochus-keller.ch/LisaCodeNavigator_mac64.zip)
77 |
78 |
79 | #### How to build the parser and code navigator
80 |
81 | The executable can be built on all common platforms using regular Qt 5.x or using [LeanQt](https://github.com/rochus-keller/LeanQt) with minimal dependencies.
82 |
83 | The project includes the CodeNavigator.pro file which can be opened and built in Qt Creator or directly with qmake on the command line.
84 |
85 | To build the Code Navigator using LeanQt and the BUSY build system (with no other dependencies than a C++98 compiler) instead, do the following:
86 |
87 | 1. Create a new directory; we call it the root directory here
88 | 1. Download https://github.com/rochus-keller/LisaPascal/archive/refs/heads/master.zip and unpack it to the root directory; rename the resulting directory to "LisaPascal".
89 | 1. Download https://github.com/rochus-keller/LeanQt/archive/refs/heads/master.zip and unpack it to the root directory; rename the resulting directory to "LeanQt".
90 | 1. Download https://github.com/rochus-keller/BUSY/archive/refs/heads/master.zip and unpack it to the root directory; rename the resulting directory to "build".
91 | 1. Open a command line in the build directory and type `cc *.c -O2 -lm -O2 -o lua` or `cl /O2 /MD /Fe:lua.exe *.c` depending on whether you are on a Unix or Windows machine; wait a few seconds until the Lua executable is built.
92 | 1. Now type `./lua build.lua ../LisaPascal` (or `lua build.lua ../LisaPascal` on Windows); wait until the LisaCodeNavigator executable is built; you find it in the output subdirectory.
93 |
94 | #### Support
95 | If you need support or would like to post issues or feature requests please use the Github issue list at https://github.com/rochus-keller/LisaPascal/issues or send an email to the author.
96 |
97 |
98 |
99 |
100 |
101 |
--------------------------------------------------------------------------------
/LisaCodeModel.h:
--------------------------------------------------------------------------------
1 | #ifndef LISACODEMODEL_H
2 | #define LISACODEMODEL_H
3 |
4 | /*
5 | * Copyright 2023 Rochus Keller
6 | *
7 | * This file is part of the Lisa Pascal Navigator application.
8 | *
9 | * The following is the license that applies to this copy of the
10 | * application. For a license to use the library under conditions
11 | * other than those described here, please email to me@rochus-keller.ch.
12 | *
13 | * GNU General Public License Usage
14 | * This file may be used under the terms of the GNU General Public
15 | * License (GPL) versions 2.0 or 3.0 as published by the Free Software
16 | * Foundation and appearing in the file LICENSE.GPL included in
17 | * the packaging of this file. Please review the following information
18 | * to ensure GNU General Public Licensing requirements will be met:
19 | * http://www.fsf.org/licensing/licenses/info/GPLv2.html and
20 | * http://www.gnu.org/copyleft/gpl.html.
21 | */
22 |
23 | #include
24 | #include
25 | #include
26 | #include
27 | #include "LisaRowCol.h"
28 |
29 | namespace Lisa
30 | {
31 | class Scope;
32 | class UnitFile;
33 | class Symbol;
34 |
35 | class Thing
36 | {
37 | public:
38 | enum Kind { Undefined,
39 | /* Declaration: */ Const, TypeDecl, Var, Func, Proc, AsmDef, MethBlock, Label, Param, Field,
40 | Module, AsmRef, AsmMacro, Self,
41 | /* Scope: */ Interface, Implementation, Body, Members,
42 | /* UnitFile: */ Unit,
43 | /* AsmFile: */ Assembler,
44 | /* AsmInclude: */ AsmIncl,
45 | /* IncludeFile: */ Include,
46 | /* CodeFolder: */ Folder
47 | };
48 | quint8 d_kind;
49 |
50 | virtual FilePos getLoc() const { return FilePos(); }
51 | virtual quint16 getLen() const { return 0; }
52 | virtual QString getName() const;
53 | virtual const FileSystem::File* getFile() const { return 0; }
54 | bool isDeclaration() const { return d_kind >= Const && d_kind <= Self; }
55 | const char* typeName() const;
56 | Thing():d_kind(Undefined){}
57 | virtual ~Thing();
58 | };
59 |
60 | class Type : public QSharedData
61 | {
62 | public:
63 | typedef QExplicitlySharedDataPointer Ref;
64 | enum Kind { Undefined, Pointer, Array, Record, Class
65 | };
66 | Type::Ref d_type;
67 | Scope* d_members; // owns
68 | quint8 d_kind;
69 |
70 | Type():d_type(0), d_members(0),d_kind(Undefined) {}
71 | ~Type();
72 | };
73 |
74 | class Declaration : public Thing
75 | {
76 | public:
77 | Scope* d_body; // owns
78 | Type::Ref d_type;
79 | QByteArray d_name;
80 | const char* d_id; // same as in Token
81 |
82 | FilePos d_loc; // place in unit or any include file where the decl is actually located
83 | Scope* d_owner;
84 |
85 | typedef QList SymList;
86 | typedef QHash Refs;
87 | Refs d_refs; // file path -> Symbols in it
88 | Symbol* d_me; // this is the symbol by which the decl itself is represented in the file
89 | Declaration* d_impl; // points to implementation if this is in an interface or a forward
90 |
91 | FilePos getLoc() const { return d_loc; }
92 | quint16 getLen() const { return d_name.size(); }
93 | QString getName() const;
94 |
95 | UnitFile* getUnitFile() const; // only for ownership, not for actual file position
96 | Declaration():d_body(0),d_owner(0),d_me(0),d_id(0),d_type(0),d_impl(0){}
97 | ~Declaration();
98 | };
99 |
100 | class Scope : public Thing
101 | {
102 | public:
103 | QList d_order; // owns
104 | Thing* d_owner; // either declaration or unit file or asm file or 0
105 | Scope* d_outer;
106 | Scope* d_altOuter; // to access params defined in interface declaration of func/proc
107 |
108 | UnitFile* getUnitFile() const;
109 | Declaration* findDecl(const char* id, bool withImports = true) const;
110 | void clear();
111 | Scope():d_owner(0),d_outer(0),d_altOuter(0){}
112 | ~Scope();
113 | };
114 |
115 | class Symbol
116 | {
117 | public:
118 | Thing* d_decl;
119 | RowCol d_loc; // the position of the symbol in the file (declaration has other position, but same length)
120 | Symbol():d_decl(0){}
121 | };
122 |
123 | class IncludeFile;
124 | class UnitFile;
125 | class AsmFile;
126 | class AsmInclude;
127 | class CodeFolder;
128 |
129 | class CodeFile : public Thing
130 | {
131 | public:
132 | const FileSystem::File* d_file;
133 | CodeFolder* d_folder;
134 |
135 | UnitFile* toUnit();
136 | IncludeFile* toInclude();
137 | AsmFile* toAsmFile();
138 | AsmInclude* toAsmInclude();
139 |
140 | QString getName() const;
141 | const FileSystem::File* getFile() const { return d_file; }
142 | CodeFile():d_file(0),d_folder(0) {}
143 | ~CodeFile();
144 | };
145 |
146 | class IncludeFile : public CodeFile
147 | {
148 | public:
149 | UnitFile* d_unit;
150 | quint16 d_len; // just to make the symbol of the include directive happy
151 |
152 | FilePos getLoc() const; // the landing place when we jump to this file
153 | quint16 getLen() const { return d_len; }
154 | IncludeFile():d_unit(0),d_len(0){ d_kind = Include; }
155 | };
156 |
157 | class UnitFile : public CodeFile
158 | {
159 | public:
160 | Scope* d_intf; // owns, 0 for Program
161 | Scope* d_impl; // owns
162 | Scope* d_globals;
163 | QList d_import;
164 | typedef QList SymList;
165 | QHash d_syms; // owns, all things we can click on in a code file ordered by row/col
166 | QList d_includes; // owns
167 |
168 | QByteArrayList findUses() const;
169 | UnitFile():d_intf(0),d_impl(0),d_globals(0) { d_kind = Unit; }
170 | ~UnitFile();
171 | };
172 |
173 | class AsmInclude : public CodeFile
174 | {
175 | public:
176 | quint16 d_len; // just to make the symbol of the include directive happy
177 | quint16 d_col;
178 | quint32 d_row;
179 | AsmFile* d_unit;
180 |
181 | FilePos getLoc() const; // the landing place when we jump to this file
182 | quint16 getLen() const { return d_len; }
183 | AsmInclude():d_len(0),d_col(0),d_row(0),d_unit(0){ d_kind = AsmIncl; }
184 | };
185 |
186 | class AsmFile : public CodeFile
187 | {
188 | public:
189 | Scope* d_impl; // owns
190 | QList d_includes; // owns
191 | typedef QList SymList;
192 | QHash d_syms; // owns, all things we can click on in a code file ordered by row/col
193 |
194 | AsmFile():d_impl(0){ d_kind = Assembler; }
195 | ~AsmFile();
196 | };
197 |
198 | class CodeFolder : public Thing
199 | {
200 | public:
201 | FileSystem::Dir* d_dir;
202 | QList d_subs; // owns
203 | QList d_files; // owns
204 |
205 | QString getName() const;
206 | void clear();
207 | CodeFolder():d_dir(0){ d_kind = Folder; }
208 | ~CodeFolder() { clear(); }
209 | };
210 |
211 | struct ModelItem
212 | {
213 | Thing* d_thing;
214 | QList d_children;
215 | ModelItem* d_parent;
216 | ModelItem(ModelItem* p = 0, Thing* t = 0):d_parent(p),d_thing(t){ if( p ) p->d_children.append(this); }
217 | ~ModelItem() { foreach( ModelItem* s, d_children ) delete s; }
218 | static bool lessThan( const ModelItem* lhs, const ModelItem* rhs);
219 | };
220 |
221 | class ItemModel : public QAbstractItemModel
222 | {
223 | Q_OBJECT
224 | public:
225 | explicit ItemModel(QObject *parent = 0);
226 | const Thing* getThing(const QModelIndex& index) const;
227 | QModelIndex findThing(const Thing* nt) const;
228 |
229 | // overrides
230 | int columnCount ( const QModelIndex & parent = QModelIndex() ) const { return 1; }
231 | QVariant data ( const QModelIndex & index, int role = Qt::DisplayRole ) const;
232 | QModelIndex index ( int row, int column, const QModelIndex & parent = QModelIndex() ) const;
233 | QModelIndex parent ( const QModelIndex & index ) const;
234 | int rowCount ( const QModelIndex & parent = QModelIndex() ) const;
235 | Qt::ItemFlags flags ( const QModelIndex & index ) const { return Qt::ItemIsEnabled | Qt::ItemIsSelectable; }
236 | protected:
237 | QModelIndex findThing(const ModelItem* slot,const Thing* nt) const;
238 | ModelItem d_root;
239 | };
240 |
241 | class CodeModel : public ItemModel
242 | {
243 | Q_OBJECT
244 | public:
245 | explicit CodeModel(QObject *parent = 0);
246 |
247 | bool load( const QString& rootDir );
248 | Symbol* findSymbolBySourcePos(const QString& path, int line, int col) const;
249 | FileSystem* getFs() const { return d_fs; }
250 | quint32 getSloc() const { return d_sloc; }
251 | CodeFile* getCodeFile(const QString& path) const;
252 | UnitFile* getUnitFile(const QString& path) const;
253 | AsmFile* getAsmFile(const QString& path) const;
254 | Scope* getGlobals() { return &d_globals; }
255 | Ranges getMutes( const QString& path );
256 | int getErrCount() const { return d_errCount; }
257 |
258 | // overrides
259 | QVariant data ( const QModelIndex & index, int role = Qt::DisplayRole ) const;
260 | protected:
261 | void parseAndResolve(UnitFile*);
262 | void parseAndResolve(AsmFile*);
263 |
264 | private:
265 | void fillFolders(ModelItem* root, const FileSystem::Dir* super, CodeFolder* top, QList& fileSlots);
266 | FileSystem* d_fs;
267 | CodeFolder d_top;
268 | Scope d_globals;
269 | QHash d_map1;
270 | QHash d_map2; // real path -> file
271 | quint32 d_sloc; // number of lines of code without empty or comment lines
272 | QHash d_mutes;
273 | int d_errCount;
274 | };
275 |
276 | class ModuleDetailMdl : public ItemModel
277 | {
278 | Q_OBJECT
279 | public:
280 | explicit ModuleDetailMdl(QObject *parent = 0);
281 |
282 | void load(Scope* intf, Scope* impl);
283 |
284 | // overrides
285 | QVariant data ( const QModelIndex & index, int role = Qt::DisplayRole ) const;
286 | private:
287 | void fillItems(ModelItem* parentItem, Scope* scope);
288 | void fillSubs(ModelItem* parentItem, Scope* scope);
289 | Scope* d_intf;
290 | Scope* d_impl;
291 | };
292 |
293 | }
294 |
295 | #endif // LISACODEMODEL_H
296 |
--------------------------------------------------------------------------------
/asm/Parser.frame:
--------------------------------------------------------------------------------
1 | /*-------------------------------------------------------------------------
2 | Compiler Generator Coco/R,
3 | Copyright (c) 1990, 2004 Hanspeter Moessenboeck, University of Linz
4 | extended by M. Loeberbauer & A. Woess, Univ. of Linz
5 | ported to C++ by Csaba Balazs, University of Szeged
6 | with improvements by Pat Terry, Rhodes University
7 | modified by Rochus Keller, me@rochus-keller.ch, (c) 2019
8 |
9 | This program is free software; you can redistribute it and/or modify it
10 | under the terms of the GNU General Public License as published by the
11 | Free Software Foundation; either version 2, or (at your option) any
12 | later version.
13 |
14 | This program is distributed in the hope that it will be useful, but
15 | WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
16 | or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17 | for more details.
18 |
19 | You should have received a copy of the GNU General Public License along
20 | with this program; if not, write to the Free Software Foundation, Inc.,
21 | 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 |
23 | As an exception, it is allowed to write an extension of Coco/R that is
24 | used as a plugin in non-free software.
25 |
26 | If not otherwise stated, any source code generated by Coco/R (other than
27 | Coco/R itself) does not fall under the GNU General Public License.
28 | -------------------------------------------------------------------------*/
29 |
30 | /*----------------------------------------------------------------------
31 | Parser.h Specification
32 | -----------------------------------------------------------------------*/
33 |
34 | -->begin
35 |
36 | // This file was automatically generated by Coco/R; don't modify it.
37 | #if !defined(-->prefixCOCO_PARSER_H__)
38 | #define -->prefixCOCO_PARSER_H__
39 |
40 | -->headerdef
41 |
42 | -->namespace_open
43 |
44 | class PpLexer;
45 | class Parser {
46 | private:
47 | -->constantsheader
48 | int errDist;
49 | int minErrDist;
50 |
51 | void SynErr(int n, const char* ctx = 0);
52 | void Get();
53 | void Expect(int n, const char* ctx = 0);
54 | bool StartOf(int s);
55 | void ExpectWeak(int n, int follow);
56 | bool WeakSeparator(int n, int syFol, int repFol);
57 | void SynErr(int line, int col, int n, const char* ctx, const QString&, const QString& path );
58 |
59 | public:
60 | PpLexer *scanner;
61 | struct Error
62 | {
63 | QString msg;
64 | int row, col;
65 | QString path;
66 | };
67 | QList errors;
68 |
69 | void error(int row, int col, const QString& msg, const QString& path)
70 | {
71 | Error e;
72 | e.row = row;
73 | e.col = col;
74 | e.msg = msg;
75 | e.path = path;
76 | errors.append(e);
77 | }
78 |
79 | Token d_cur;
80 | Token d_next;
81 | QList d_comments;
82 | struct TokDummy
83 | {
84 | int kind;
85 | };
86 | TokDummy d_dummy;
87 | TokDummy *la; // lookahead token
88 |
89 | int peek( quint8 la = 1 );
90 |
91 | void RunParser();
92 |
93 |
94 | -->declarations
95 |
96 | Parser(PpLexer *scanner);
97 | ~Parser();
98 | void SemErr(const char* msg);
99 |
100 | -->productionsheader
101 | void Parse();
102 |
103 | }; // end Parser
104 |
105 | -->namespace_close
106 |
107 | #endif
108 |
109 | -->implementation
110 |
111 | /*----------------------------------------------------------------------
112 | Parser.cpp Specification
113 | -----------------------------------------------------------------------*/
114 |
115 | -->begin
116 |
117 | // This file was automatically generated by Coco/R; don't modify it.
118 | #include "AsmParser.h"
119 | #include "AsmPpLexer.h"
120 |
121 |
122 | -->namespace_open
123 |
124 | static QString coco_string_create( const wchar_t* str )
125 | {
126 | return QString::fromStdWString(str);
127 | }
128 |
129 | int Parser::peek( quint8 la )
130 | {
131 | if( la == 0 )
132 | return d_cur.d_type;
133 | else if( la == 1 )
134 | return d_next.d_type;
135 | else
136 | return scanner->peekToken( la - 1 ).d_type;
137 | }
138 |
139 | void Parser::RunParser()
140 | {
141 | d_stack.push(&d_root);
142 | Parse();
143 | d_stack.pop();
144 | }
145 |
146 | void Parser::SynErr(int n, const char* ctx) {
147 | if (errDist >= minErrDist)
148 | SynErr(d_next.d_lineNr, d_next.d_colNr, n, ctx, QString(), d_next.d_sourcePath);
149 | errDist = 0;
150 | }
151 |
152 | void Parser::SemErr(const char* msg) {
153 | if (errDist >= minErrDist)
154 | error(d_cur.d_lineNr, d_cur.d_colNr, msg, d_cur.d_sourcePath);
155 | errDist = 0;
156 | }
157 |
158 | void Parser::Get() {
159 | for (;;) {
160 | d_cur = d_next;
161 | d_next = scanner->nextToken();
162 | bool deliverToParser = false;
163 | switch( d_next.d_type )
164 | {
165 | case Tok_Invalid:
166 | if( !d_next.d_val.isEmpty() )
167 | error( d_next.d_lineNr, d_next.d_colNr, d_next.d_val, d_next.d_sourcePath );
168 | // else errors already handeled in lexer
169 | break;
170 | case Tok_Comment:
171 | d_comments.append(d_next);
172 | break;
173 | default:
174 | deliverToParser = true;
175 | break;
176 | }
177 |
178 | if( deliverToParser )
179 | {
180 | if( d_next.d_type == Tok_Eof )
181 | d_next.d_type = _EOF;
182 |
183 | la->kind = d_next.d_type;
184 | if (la->kind <= maxT)
185 | {
186 | ++errDist;
187 | break;
188 | }
189 | }
190 | -->pragmas
191 | d_next = d_cur;
192 | }
193 | }
194 |
195 | void Parser::Expect(int n, const char* ctx ) {
196 | if (la->kind==n) Get(); else { SynErr(n, ctx); }
197 | }
198 |
199 | void Parser::ExpectWeak(int n, int follow) {
200 | if (la->kind == n) Get();
201 | else {
202 | SynErr(n);
203 | while (!StartOf(follow)) Get();
204 | }
205 | }
206 |
207 | bool Parser::WeakSeparator(int n, int syFol, int repFol) {
208 | if (la->kind == n) {Get(); return true;}
209 | else if (StartOf(repFol)) {return false;}
210 | else {
211 | SynErr(n);
212 | while (!(StartOf(syFol) || StartOf(repFol) || StartOf(0))) {
213 | Get();
214 | }
215 | return StartOf(syFol);
216 | }
217 | }
218 |
219 | -->productions
220 |
221 |
222 | // If the user declared a method Init and a mehtod Destroy they should
223 | // be called in the contructur and the destructor respctively.
224 | //
225 | // The following templates are used to recognize if the user declared
226 | // the methods Init and Destroy.
227 |
228 | template
229 | struct ParserInitExistsRecognizer {
230 | template
231 | struct ExistsIfInitIsDefinedMarker{};
232 |
233 | struct InitIsMissingType {
234 | char dummy1;
235 | };
236 |
237 | struct InitExistsType {
238 | char dummy1; char dummy2;
239 | };
240 |
241 | // exists always
242 | template
243 | static InitIsMissingType is_here(...);
244 |
245 | // exist only if ExistsIfInitIsDefinedMarker is defined
246 | template
247 | static InitExistsType is_here(ExistsIfInitIsDefinedMarker*);
248 |
249 | enum { InitExists = (sizeof(is_here(NULL)) == sizeof(InitExistsType)) };
250 | };
251 |
252 | template
253 | struct ParserDestroyExistsRecognizer {
254 | template
255 | struct ExistsIfDestroyIsDefinedMarker{};
256 |
257 | struct DestroyIsMissingType {
258 | char dummy1;
259 | };
260 |
261 | struct DestroyExistsType {
262 | char dummy1; char dummy2;
263 | };
264 |
265 | // exists always
266 | template
267 | static DestroyIsMissingType is_here(...);
268 |
269 | // exist only if ExistsIfDestroyIsDefinedMarker is defined
270 | template
271 | static DestroyExistsType is_here(ExistsIfDestroyIsDefinedMarker*);
272 |
273 | enum { DestroyExists = (sizeof(is_here(NULL)) == sizeof(DestroyExistsType)) };
274 | };
275 |
276 | // The folloing templates are used to call the Init and Destroy methods if they exist.
277 |
278 | // Generic case of the ParserInitCaller, gets used if the Init method is missing
279 | template::InitExists>
280 | struct ParserInitCaller {
281 | static void CallInit(T *t) {
282 | // nothing to do
283 | }
284 | };
285 |
286 | // True case of the ParserInitCaller, gets used if the Init method exists
287 | template
288 | struct ParserInitCaller {
289 | static void CallInit(T *t) {
290 | t->Init();
291 | }
292 | };
293 |
294 | // Generic case of the ParserDestroyCaller, gets used if the Destroy method is missing
295 | template::DestroyExists>
296 | struct ParserDestroyCaller {
297 | static void CallDestroy(T *t) {
298 | // nothing to do
299 | }
300 | };
301 |
302 | // True case of the ParserDestroyCaller, gets used if the Destroy method exists
303 | template
304 | struct ParserDestroyCaller {
305 | static void CallDestroy(T *t) {
306 | t->Destroy();
307 | }
308 | };
309 |
310 | void Parser::Parse() {
311 | d_cur = Token();
312 | d_next = Token();
313 | Get();
314 | -->parseRoot
315 | }
316 |
317 | Parser::Parser(PpLexer *scanner) {
318 | -->constants
319 | ParserInitCaller::CallInit(this);
320 | la = &d_dummy;
321 | minErrDist = 2;
322 | errDist = minErrDist;
323 | this->scanner = scanner;
324 | }
325 |
326 | bool Parser::StartOf(int s) {
327 | const bool T = true;
328 | const bool x = false;
329 |
330 | -->initialization
331 |
332 | return set[s][la->kind];
333 | }
334 |
335 | Parser::~Parser() {
336 | ParserDestroyCaller::CallDestroy(this);
337 | }
338 |
339 | void Parser::SynErr(int line, int col, int n, const char* ctx, const QString& str, const QString& path ) {
340 | QString s;
341 | QString ctxStr;
342 | if( ctx )
343 | ctxStr = QString( " in %1" ).arg(ctx);
344 | if( n == 0 )
345 | s = QString("EOF expected%1").arg(ctxStr);
346 | else if( n < TT_Specials )
347 | s = QString("'%2' expected%1").arg(ctxStr).arg(tokenTypeString(n));
348 | else if( n <= TT_Max )
349 | s = QString("%2 expected%1").arg(ctxStr).arg(tokenTypeString(n));
350 | else
351 | switch (n) {
352 | -->errors
353 | default:
354 | {
355 | s = QString( "generic error %1").arg(n);
356 | }
357 | break;
358 | }
359 | if( !str.isEmpty() )
360 | s = QString("%1 %2").arg(s).arg(str);
361 | error(line, col, s, path);
362 | //count++;
363 | }
364 |
365 | -->namespace_close
366 |
--------------------------------------------------------------------------------
/syntax/Parser.frame:
--------------------------------------------------------------------------------
1 | /*-------------------------------------------------------------------------
2 | Compiler Generator Coco/R,
3 | Copyright (c) 1990, 2004 Hanspeter Moessenboeck, University of Linz
4 | extended by M. Loeberbauer & A. Woess, Univ. of Linz
5 | ported to C++ by Csaba Balazs, University of Szeged
6 | with improvements by Pat Terry, Rhodes University
7 | modified by Rochus Keller, me@rochus-keller.ch, (c) 2019
8 |
9 | This program is free software; you can redistribute it and/or modify it
10 | under the terms of the GNU General Public License as published by the
11 | Free Software Foundation; either version 2, or (at your option) any
12 | later version.
13 |
14 | This program is distributed in the hope that it will be useful, but
15 | WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
16 | or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17 | for more details.
18 |
19 | You should have received a copy of the GNU General Public License along
20 | with this program; if not, write to the Free Software Foundation, Inc.,
21 | 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 |
23 | As an exception, it is allowed to write an extension of Coco/R that is
24 | used as a plugin in non-free software.
25 |
26 | If not otherwise stated, any source code generated by Coco/R (other than
27 | Coco/R itself) does not fall under the GNU General Public License.
28 | -------------------------------------------------------------------------*/
29 |
30 | /*----------------------------------------------------------------------
31 | Parser.h Specification
32 | -----------------------------------------------------------------------*/
33 |
34 | -->begin
35 |
36 | // This file was automatically generated by Coco/R; don't modify it.
37 | #if !defined(-->prefixCOCO_PARSER_H__)
38 | #define -->prefixCOCO_PARSER_H__
39 |
40 | -->headerdef
41 |
42 | -->namespace_open
43 |
44 | class PpLexer;
45 | class Parser {
46 | private:
47 | -->constantsheader
48 | int errDist;
49 | int minErrDist;
50 |
51 | void SynErr(int n, const char* ctx = 0);
52 | void Get();
53 | void Expect(int n, const char* ctx = 0);
54 | bool StartOf(int s);
55 | void ExpectWeak(int n, int follow);
56 | bool WeakSeparator(int n, int syFol, int repFol);
57 | void SynErr(int line, int col, int n, const char* ctx, const QString&, const QString& path );
58 |
59 | public:
60 | PpLexer *scanner;
61 | struct Error
62 | {
63 | QString msg;
64 | int row, col;
65 | QString path;
66 | };
67 | QList errors;
68 |
69 | void error(int row, int col, const QString& msg, const QString& path)
70 | {
71 | Error e;
72 | e.row = row;
73 | e.col = col;
74 | e.msg = msg;
75 | e.path = path;
76 | errors.append(e);
77 | }
78 |
79 | Token d_cur;
80 | Token d_next;
81 | QList d_comments;
82 | struct TokDummy
83 | {
84 | int kind;
85 | };
86 | TokDummy d_dummy;
87 | TokDummy *la; // lookahead token
88 |
89 | int peek( quint8 la = 1 );
90 |
91 | void RunParser();
92 |
93 |
94 | -->declarations
95 |
96 | Parser(PpLexer *scanner);
97 | ~Parser();
98 | void SemErr(const char* msg);
99 |
100 | -->productionsheader
101 | void Parse();
102 |
103 | }; // end Parser
104 |
105 | -->namespace_close
106 |
107 | #endif
108 |
109 | -->implementation
110 |
111 | /*----------------------------------------------------------------------
112 | Parser.cpp Specification
113 | -----------------------------------------------------------------------*/
114 |
115 | -->begin
116 |
117 | // This file was automatically generated by Coco/R; don't modify it.
118 | #include "LisaParser.h"
119 | #include "LisaPpLexer.h"
120 |
121 |
122 | -->namespace_open
123 |
124 | static QString coco_string_create( const wchar_t* str )
125 | {
126 | return QString::fromStdWString(str);
127 | }
128 |
129 | int Parser::peek( quint8 la )
130 | {
131 | if( la == 0 )
132 | return d_cur.d_type;
133 | else if( la == 1 )
134 | return d_next.d_type;
135 | else
136 | return scanner->peekToken( la - 1 ).d_type;
137 | }
138 |
139 | void Parser::RunParser()
140 | {
141 | d_stack.push(&d_root);
142 | Parse();
143 | d_stack.pop();
144 | }
145 |
146 | void Parser::SynErr(int n, const char* ctx) {
147 | if (errDist >= minErrDist)
148 | SynErr(d_next.d_lineNr, d_next.d_colNr, n, ctx, QString(), d_next.d_sourcePath);
149 | errDist = 0;
150 | }
151 |
152 | void Parser::SemErr(const char* msg) {
153 | if (errDist >= minErrDist)
154 | error(d_cur.d_lineNr, d_cur.d_colNr, msg, d_cur.d_sourcePath);
155 | errDist = 0;
156 | }
157 |
158 | void Parser::Get() {
159 | for (;;) {
160 | d_cur = d_next;
161 | d_next = scanner->nextToken();
162 | bool deliverToParser = false;
163 | switch( d_next.d_type )
164 | {
165 | case Lisa::Tok_Invalid:
166 | if( !d_next.d_val.isEmpty() )
167 | error( d_next.d_lineNr, d_next.d_colNr, d_next.d_val, d_next.d_sourcePath );
168 | // else errors already handeled in lexer
169 | break;
170 | case Lisa::Tok_Comment:
171 | d_comments.append(d_next);
172 | break;
173 | default:
174 | deliverToParser = true;
175 | break;
176 | }
177 |
178 | if( deliverToParser )
179 | {
180 | if( d_next.d_type == Lisa::Tok_Eof )
181 | d_next.d_type = _EOF;
182 |
183 | la->kind = d_next.d_type;
184 | if (la->kind <= maxT)
185 | {
186 | ++errDist;
187 | break;
188 | }
189 | }
190 | -->pragmas
191 | d_next = d_cur;
192 | }
193 | }
194 |
195 | void Parser::Expect(int n, const char* ctx ) {
196 | if (la->kind==n) Get(); else { SynErr(n, ctx); }
197 | }
198 |
199 | void Parser::ExpectWeak(int n, int follow) {
200 | if (la->kind == n) Get();
201 | else {
202 | SynErr(n);
203 | while (!StartOf(follow)) Get();
204 | }
205 | }
206 |
207 | bool Parser::WeakSeparator(int n, int syFol, int repFol) {
208 | if (la->kind == n) {Get(); return true;}
209 | else if (StartOf(repFol)) {return false;}
210 | else {
211 | SynErr(n);
212 | while (!(StartOf(syFol) || StartOf(repFol) || StartOf(0))) {
213 | Get();
214 | }
215 | return StartOf(syFol);
216 | }
217 | }
218 |
219 | -->productions
220 |
221 |
222 | // If the user declared a method Init and a mehtod Destroy they should
223 | // be called in the contructur and the destructor respctively.
224 | //
225 | // The following templates are used to recognize if the user declared
226 | // the methods Init and Destroy.
227 |
228 | template
229 | struct ParserInitExistsRecognizer {
230 | template
231 | struct ExistsIfInitIsDefinedMarker{};
232 |
233 | struct InitIsMissingType {
234 | char dummy1;
235 | };
236 |
237 | struct InitExistsType {
238 | char dummy1; char dummy2;
239 | };
240 |
241 | // exists always
242 | template
243 | static InitIsMissingType is_here(...);
244 |
245 | // exist only if ExistsIfInitIsDefinedMarker is defined
246 | template
247 | static InitExistsType is_here(ExistsIfInitIsDefinedMarker*);
248 |
249 | enum { InitExists = (sizeof(is_here(NULL)) == sizeof(InitExistsType)) };
250 | };
251 |
252 | template
253 | struct ParserDestroyExistsRecognizer {
254 | template
255 | struct ExistsIfDestroyIsDefinedMarker{};
256 |
257 | struct DestroyIsMissingType {
258 | char dummy1;
259 | };
260 |
261 | struct DestroyExistsType {
262 | char dummy1; char dummy2;
263 | };
264 |
265 | // exists always
266 | template
267 | static DestroyIsMissingType is_here(...);
268 |
269 | // exist only if ExistsIfDestroyIsDefinedMarker is defined
270 | template
271 | static DestroyExistsType is_here(ExistsIfDestroyIsDefinedMarker*);
272 |
273 | enum { DestroyExists = (sizeof(is_here(NULL)) == sizeof(DestroyExistsType)) };
274 | };
275 |
276 | // The folloing templates are used to call the Init and Destroy methods if they exist.
277 |
278 | // Generic case of the ParserInitCaller, gets used if the Init method is missing
279 | template::InitExists>
280 | struct ParserInitCaller {
281 | static void CallInit(T *t) {
282 | // nothing to do
283 | }
284 | };
285 |
286 | // True case of the ParserInitCaller, gets used if the Init method exists
287 | template
288 | struct ParserInitCaller {
289 | static void CallInit(T *t) {
290 | t->Init();
291 | }
292 | };
293 |
294 | // Generic case of the ParserDestroyCaller, gets used if the Destroy method is missing
295 | template::DestroyExists>
296 | struct ParserDestroyCaller {
297 | static void CallDestroy(T *t) {
298 | // nothing to do
299 | }
300 | };
301 |
302 | // True case of the ParserDestroyCaller, gets used if the Destroy method exists
303 | template
304 | struct ParserDestroyCaller {
305 | static void CallDestroy(T *t) {
306 | t->Destroy();
307 | }
308 | };
309 |
310 | void Parser::Parse() {
311 | d_cur = Token();
312 | d_next = Token();
313 | Get();
314 | -->parseRoot
315 | }
316 |
317 | Parser::Parser(PpLexer *scanner) {
318 | -->constants
319 | ParserInitCaller::CallInit(this);
320 | la = &d_dummy;
321 | minErrDist = 2;
322 | errDist = minErrDist;
323 | this->scanner = scanner;
324 | }
325 |
326 | bool Parser::StartOf(int s) {
327 | const bool T = true;
328 | const bool x = false;
329 |
330 | -->initialization
331 |
332 | return set[s][la->kind];
333 | }
334 |
335 | Parser::~Parser() {
336 | ParserDestroyCaller::CallDestroy(this);
337 | }
338 |
339 | void Parser::SynErr(int line, int col, int n, const char* ctx, const QString& str, const QString& path ) {
340 | QString s;
341 | QString ctxStr;
342 | if( ctx )
343 | ctxStr = QString( " in %1" ).arg(ctx);
344 | if( n == 0 )
345 | s = QString("EOF expected%1").arg(ctxStr);
346 | else if( n < TT_Specials )
347 | s = QString("'%2' expected%1").arg(ctxStr).arg(tokenTypeString(n));
348 | else if( n <= TT_Max )
349 | s = QString("%2 expected%1").arg(ctxStr).arg(tokenTypeString(n));
350 | else
351 | switch (n) {
352 | -->errors
353 | default:
354 | {
355 | s = QString( "generic error %1").arg(n);
356 | }
357 | break;
358 | }
359 | if( !str.isEmpty() )
360 | s = QString("%1 %2").arg(s).arg(str);
361 | error(line, col, s, path);
362 | //count++;
363 | }
364 |
365 | -->namespace_close
366 |
--------------------------------------------------------------------------------
/LisaHighlighter.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Rochus Keller
3 | *
4 | * This file is part of the Lisa Pascal Navigator application.
5 | *
6 | * The following is the license that applies to this copy of the
7 | * application. For a license to use the library under conditions
8 | * other than those described here, please email to me@rochus-keller.ch.
9 | *
10 | * GNU General Public License Usage
11 | * This file may be used under the terms of the GNU General Public
12 | * License (GPL) versions 2.0 or 3.0 as published by the Free Software
13 | * Foundation and appearing in the file LICENSE.GPL included in
14 | * the packaging of this file. Please review the following information
15 | * to ensure GNU General Public Licensing requirements will be met:
16 | * http://www.fsf.org/licensing/licenses/info/GPLv2.html and
17 | * http://www.gnu.org/copyleft/gpl.html.
18 | */
19 |
20 | // * Adopted from https://github.com/rochus-keller/Oberon/
21 |
22 | #include "LisaHighlighter.h"
23 | #include "LisaLexer.h"
24 | #include "AsmLexer.h"
25 | #include
26 | using namespace Lisa;
27 |
28 | PascalPainter::PascalPainter(QObject* parent) :
29 | QSyntaxHighlighter(parent)
30 | {
31 | for( int i = 0; i < C_Max; i++ )
32 | {
33 | d_format[i].setFontWeight(QFont::Normal);
34 | d_format[i].setForeground(Qt::black);
35 | d_format[i].setBackground(Qt::transparent);
36 | }
37 | d_format[C_Num].setForeground(QColor(0, 153, 153));
38 | d_format[C_Str].setForeground(QColor(208, 16, 64));
39 | d_format[C_Cmt].setForeground(QColor(153, 153, 136));
40 | d_format[C_Kw].setForeground(QColor(68, 85, 136));
41 | d_format[C_Kw].setFontWeight(QFont::Bold);
42 | d_format[C_Op].setForeground(QColor(153, 0, 0));
43 | d_format[C_Op].setFontWeight(QFont::Bold);
44 | d_format[C_Type].setForeground(QColor(153, 0, 115));
45 | d_format[C_Type].setFontWeight(QFont::Bold);
46 | d_format[C_Pp].setFontWeight(QFont::Bold);
47 | d_format[C_Pp].setForeground(QColor(0, 128, 0));
48 | d_format[C_Pp].setBackground(QColor(230, 255, 230));
49 | d_format[C_Label].setForeground(QColor(251, 138, 0));
50 | d_format[C_Label].setBackground(QColor(253, 217, 165));
51 | }
52 |
53 | void PascalPainter::addBuiltIn(const QByteArray& bi)
54 | {
55 | d_builtins << bi;
56 | }
57 |
58 | void PascalPainter::addKeyword(const QByteArray& kw)
59 | {
60 | d_keywords << kw;
61 | }
62 |
63 | QTextCharFormat PascalPainter::formatForCategory(int c) const
64 | {
65 | return d_format[c];
66 | }
67 |
68 | void PascalPainter::highlightBlock(const QString& text)
69 | {
70 | const int previousBlockState_ = previousBlockState();
71 | int lexerState = 0, initialBraceDepth = 0;
72 | if (previousBlockState_ != -1) {
73 | lexerState = previousBlockState_ & 0xff;
74 | initialBraceDepth = previousBlockState_ >> 8;
75 | }
76 |
77 | int braceDepth = initialBraceDepth;
78 |
79 | // Protocol:
80 | // lexerState == 1: multi-line (* *) comment
81 | // lexerState == 2: multi-line { } comment
82 | // lexerState == 3: (*$ *) directive
83 | // lexerState == 4: {$ } directive
84 |
85 | int start = 0;
86 | if( lexerState == 1 || lexerState == 3 )
87 | {
88 | QTextCharFormat f = formatForCategory( lexerState == 1 ? C_Cmt : C_Pp);
89 | int pos = text.indexOf("*)");
90 | if( pos == -1 )
91 | {
92 | // the whole block ist part of comment
93 | setFormat( start, text.size(), f );
94 | setCurrentBlockState( (braceDepth << 8) | lexerState);
95 | return;
96 | }else
97 | {
98 | // End of comment found
99 | pos += 2;
100 | setFormat( start, pos , f );
101 | lexerState = 0;
102 | braceDepth--;
103 | start = pos;
104 | }
105 | }else if( lexerState == 2 || lexerState == 4 )
106 | {
107 | QTextCharFormat f = formatForCategory( lexerState == 2 ? C_Cmt : C_Pp);
108 | int pos = text.indexOf('}');
109 | if( pos == -1 )
110 | {
111 | // the whole block ist part of comment
112 | setFormat( start, text.size(), f );
113 | setCurrentBlockState( (braceDepth << 8) | lexerState);
114 | return;
115 | }else
116 | {
117 | // End of comment found
118 | pos += 1;
119 | setFormat( start, pos , f );
120 | lexerState = 0;
121 | braceDepth--;
122 | start = pos;
123 | }
124 | }
125 |
126 |
127 | Lisa::Lexer lex;
128 | lex.setIgnoreComments(false);
129 | lex.setPackComments(false);
130 |
131 | QList tokens = lex.tokens(text.mid(start));
132 | for( int i = 0; i < tokens.size(); ++i )
133 | {
134 | Token &t = tokens[i];
135 | t.d_colNr += start;
136 |
137 | QTextCharFormat f;
138 | if( t.d_type == Tok_Latt )
139 | {
140 | if( t.d_val.startsWith("(*$") )
141 | {
142 | f = formatForCategory(C_Pp);
143 | lexerState = 3;
144 | }else
145 | {
146 | f = formatForCategory(C_Cmt);
147 | lexerState = 1;
148 | }
149 | if( t.d_val.endsWith("*)") )
150 | lexerState = 0;
151 | else
152 | braceDepth++;
153 | }else if( t.d_type == Tok_Lbrace )
154 | {
155 | if( t.d_val.startsWith("{$") )
156 | {
157 | f = formatForCategory(C_Pp);
158 | lexerState = 4;
159 | }else
160 | {
161 | f = formatForCategory(C_Cmt);
162 | lexerState = 2;
163 | }
164 | if( t.d_val.endsWith("}") )
165 | lexerState = 0;
166 | else
167 | braceDepth++;
168 | }else if( t.d_type == Tok_string_literal )
169 | f = formatForCategory(C_Str);
170 | else if( t.d_type == Tok_unsigned_real || t.d_type == Tok_digit_sequence || t.d_type == Tok_hex_digit_sequence )
171 | f = formatForCategory(C_Num);
172 | else if( tokenTypeIsLiteral(t.d_type) )
173 | {
174 | f = formatForCategory(C_Op);
175 | }else if( tokenTypeIsKeyword(t.d_type) )
176 | {
177 | f = formatForCategory(C_Kw);
178 | }else if( t.d_type == Tok_identifier )
179 | {
180 | const QByteArray& name = t.d_val.toUpper();
181 | /*if( i+1 < tokens.size() && tokens[i+1].d_type == Tok_Colon)
182 | f = formatForCategory(C_Label);
183 | else */if( d_builtins.contains(name) )
184 | f = formatForCategory(C_Type);
185 | else if( d_keywords.contains(name) )
186 | f = formatForCategory(C_Kw);
187 | else
188 | f = formatForCategory(C_Ident);
189 | }
190 |
191 | /*if( lexerState == 3 )
192 | setFormat( startPp, t.d_colNr - startPp + t.d_val.size(), formatForCategory(C_Pp) );
193 | else */
194 | if( f.isValid() )
195 | setFormat( t.d_colNr-1, t.d_val.isEmpty() ? t.d_len : t.d_val.size(), f );
196 | }
197 |
198 | setCurrentBlockState((braceDepth << 8) | lexerState );
199 | }
200 |
201 |
202 |
203 | LogPainter::LogPainter(QTextDocument* parent):QSyntaxHighlighter(parent)
204 | {
205 |
206 | }
207 |
208 | void LogPainter::highlightBlock(const QString& text)
209 | {
210 | QColor c = Qt::black;
211 | if( text.startsWith("WRN:") )
212 | c = Qt::blue;
213 | else if( text.startsWith("ERR:") )
214 | c = Qt::red;
215 |
216 | setFormat( 0, text.size(), c );
217 | }
218 |
219 |
220 | AsmPainter::AsmPainter(QObject* parent):
221 | QSyntaxHighlighter(parent)
222 | {
223 | for( int i = 0; i < C_Max; i++ )
224 | {
225 | d_format[i].setFontWeight(QFont::Normal);
226 | d_format[i].setForeground(Qt::black);
227 | d_format[i].setBackground(Qt::transparent);
228 | }
229 | d_format[C_Num].setForeground(QColor(0, 153, 153));
230 | d_format[C_Str].setForeground(QColor(208, 16, 64));
231 | d_format[C_Cmt].setForeground(QColor(153, 153, 136));
232 | d_format[C_Kw].setForeground(QColor(68, 85, 136));
233 | d_format[C_Kw].setFontWeight(QFont::Bold);
234 | d_format[C_Op].setForeground(QColor(153, 0, 0));
235 | d_format[C_Op].setFontWeight(QFont::Bold);
236 | d_format[C_Pp].setFontWeight(QFont::Bold);
237 | d_format[C_Pp].setForeground(QColor(0, 128, 0));
238 | d_format[C_Pp].setBackground(QColor(230, 255, 230));
239 | d_format[C_Label].setForeground(QColor(251, 138, 0));
240 | d_format[C_Label].setBackground(QColor(253, 237, 185));
241 | }
242 |
243 | void AsmPainter::highlightBlock(const QString& text)
244 | {
245 | const int previousBlockState_ = previousBlockState();
246 | int lexerState = 0, initialBraceDepth = 0;
247 | if (previousBlockState_ != -1) {
248 | lexerState = previousBlockState_ & 0xff;
249 | initialBraceDepth = previousBlockState_ >> 8;
250 | }
251 |
252 | int braceDepth = initialBraceDepth;
253 |
254 | Asm::Lexer lex;
255 | lex.setIgnoreComments(false);
256 |
257 | QList tokens = lex.tokens(text);
258 | for( int i = 0; i < tokens.size(); ++i )
259 | {
260 | Asm::Token &t = tokens[i];
261 | int len = t.d_val.size();
262 |
263 | QTextCharFormat f;
264 | if( t.d_type == Asm::Tok_Comment )
265 | f = d_format[C_Cmt];
266 | else if( t.d_type == Asm::Tok_string )
267 | f = d_format[C_Str];
268 | else if( t.d_type == Asm::Tok_number)
269 | f = d_format[C_Num];
270 | else if( t.d_type == Asm::Tok_label)
271 | f = d_format[C_Label];
272 | else if( t.d_type == Asm::Tok_dotB || t.d_type == Asm::Tok_dotS || t.d_type == Asm::Tok_dotW
273 | || t.d_type == Asm::Tok_dotL)
274 | f = d_format[C_Kw];
275 | else if( t.d_type == Asm::Tok_substitute)
276 | f = d_format[C_Pp];
277 | else if( Asm::tokenTypeIsLiteral(t.d_type) )
278 | f = d_format[C_Op];
279 | else if( Asm::tokenTypeIsKeyword(t.d_type) )
280 | {
281 | if( Asm::Token::isDirective(t.d_type))
282 | {
283 | f = d_format[C_Pp];
284 | len++;
285 | }else
286 | f = d_format[C_Kw];
287 | }else if( t.d_type == Tok_identifier )
288 | {
289 | if( i+1 < tokens.size() && tokens[i+1].d_type == Tok_Colon )
290 | f = d_format[C_Label];
291 | else
292 | f = d_format[C_Ident];
293 | }
294 |
295 | if( f.isValid() )
296 | setFormat( t.d_colNr-1, len, f );
297 | }
298 |
299 | setCurrentBlockState((braceDepth << 8) | lexerState );
300 | }
301 |
--------------------------------------------------------------------------------
/LisaLexer.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | ** Copyright (C) 2023 Rochus Keller (me@rochus-keller.ch)
3 | **
4 | ** This file is part of the LisaPascal project.
5 | **
6 | ** $QT_BEGIN_LICENSE:LGPL21$
7 | ** GNU Lesser General Public License Usage
8 | ** This file may be used under the terms of the GNU Lesser
9 | ** General Public License version 2.1 or version 3 as published by the Free
10 | ** Software Foundation and appearing in the file LICENSE.LGPLv21 and
11 | ** LICENSE.LGPLv3 included in the packaging of this file. Please review the
12 | ** following information to ensure the GNU Lesser General Public License
13 | ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
14 | ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
15 | */
16 |
17 | #include "LisaLexer.h"
18 | #include
19 | #include
20 | using namespace Lisa;
21 |
22 | Lexer::Lexer():
23 | d_lastToken(Tok_Invalid),d_lineNr(0),d_colNr(0),d_in(0),
24 | d_ignoreComments(true), d_packComments(true),d_sloc(0),d_lineCounted(false)
25 | {
26 |
27 | }
28 |
29 | Lexer::~Lexer()
30 | {
31 | }
32 |
33 | void Lexer::setStream(QIODevice* in, const QString& filePath)
34 | {
35 | d_in = in;
36 | d_lineNr = 0;
37 | d_colNr = 0;
38 | d_lastToken = Tok_Invalid;
39 | d_filePath = filePath;
40 | d_sloc = 0;
41 | d_lineCounted = false;
42 | }
43 |
44 | Token Lexer::nextToken()
45 | {
46 | Token t;
47 | if( !d_buffer.isEmpty() )
48 | {
49 | t = d_buffer.first();
50 | d_buffer.pop_front();
51 | }else
52 | t = nextTokenImp();
53 | while( t.d_type == Tok_Comment && d_ignoreComments )
54 | t = nextToken();
55 | return t;
56 | }
57 |
58 | Token Lexer::peekToken(quint8 lookAhead)
59 | {
60 | Q_ASSERT( lookAhead > 0 );
61 | while( d_buffer.size() < lookAhead )
62 | {
63 | Token t = nextTokenImp();
64 | while( t.d_type == Tok_Comment && d_ignoreComments )
65 | t = nextTokenImp();
66 | d_buffer.push_back( t );
67 | }
68 | return d_buffer[ lookAhead - 1 ];
69 | }
70 |
71 | QList Lexer::tokens(const QString& code)
72 | {
73 | QBuffer in;
74 | in.setData( code.toLatin1() );
75 | in.open(QIODevice::ReadOnly);
76 | setStream( &in );
77 |
78 | QList res;
79 | Token t = nextToken();
80 | while( t.isValid() )
81 | {
82 | res << t;
83 | t = nextToken();
84 | }
85 | return res;
86 | }
87 |
88 | Token Lexer::nextTokenImp()
89 | {
90 | if( d_in == 0 )
91 | return token(Tok_Eof);
92 | skipWhiteSpace();
93 |
94 | while( d_colNr >= d_line.size() )
95 | {
96 | if( d_in->atEnd() )
97 | {
98 | Token t = token( Tok_Eof, 0 );
99 | return t;
100 | }
101 | nextLine();
102 | skipWhiteSpace();
103 | }
104 | Q_ASSERT( d_colNr < d_line.size() );
105 | while( d_colNr < d_line.size() )
106 | {
107 | const char ch = quint8(d_line[d_colNr]);
108 |
109 | if( ch == '\'' )
110 | return string();
111 | else if( ch == '$')
112 | return hexnumber();
113 | else if( ::isalpha(ch) ||
114 | ch == '%' || ch == '_' )
115 | // leading % apparently supported, e.g. in libpl-BLOCKIO2.TEXT.unix.txt
116 | // leading _ apparently supported, e.g. in libdb-HEAP.TEXT.unix.txt
117 | return ident();
118 | else if( ::isdigit(ch) )
119 | return number();
120 | // else
121 | int pos = d_colNr;
122 | TokenType tt = tokenTypeFromString(d_line,&pos);
123 |
124 | if( tt == Tok_Latt )
125 | return comment();
126 | else if( tt == Tok_Lbrace )
127 | return comment(true);
128 | else if( tt == Tok_Invalid || pos == d_colNr )
129 | return token( Tok_Invalid, 1, QString("unexpected character '%1' %2").arg(char(ch)).arg(int(ch)).toUtf8() );
130 | else {
131 | const int len = pos - d_colNr;
132 | return token( tt, len, d_line.mid(d_colNr,len) );
133 | }
134 | }
135 | Q_ASSERT(false);
136 | return token(Tok_Invalid);
137 | }
138 |
139 | int Lexer::skipWhiteSpace()
140 | {
141 | const int colNr = d_colNr;
142 | while( d_colNr < d_line.size() && ( ::isspace( d_line[d_colNr] ) || d_line[d_colNr] == char(0xff) ) )
143 | d_colNr++;
144 | return d_colNr - colNr;
145 | }
146 |
147 | void Lexer::nextLine()
148 | {
149 | d_colNr = 0;
150 | d_lineNr++;
151 | d_line = d_in->readLine();
152 | d_lineCounted = false;
153 |
154 | if( d_line.endsWith("\r\n") )
155 | d_line.chop(2);
156 | else if( d_line.endsWith('\n') || d_line.endsWith('\r') || d_line.endsWith('\025') )
157 | d_line.chop(1);
158 | }
159 |
160 | int Lexer::lookAhead(int off) const
161 | {
162 | if( int( d_colNr + off ) < d_line.size() )
163 | {
164 | return d_line[ d_colNr + off ];
165 | }else
166 | return 0;
167 | }
168 |
169 | Token Lexer::token(TokenType tt, int len, const QByteArray& val)
170 | {
171 | if( tt != Tok_Invalid && tt != Tok_Comment && tt != Tok_Eof )
172 | countLine();
173 | Token t( tt, d_lineNr, d_colNr + 1, val );
174 | d_lastToken = t;
175 | d_colNr += len;
176 | t.d_len = len;
177 | #if 1
178 | if( tt == Tok_identifier )
179 | t.d_id = Token::toId(val);
180 | #endif
181 | t.d_sourcePath = d_filePath;
182 | return t;
183 | }
184 |
185 | Token Lexer::ident()
186 | {
187 | int off = 1;
188 | while( true )
189 | {
190 | const char c = lookAhead(off);
191 | if( !::isalnum(c) && c != '_' && c != '%' )
192 | // % in ident apparently supported, as seen in libfp-FPMODES.TEXT.unix.txt
193 | break;
194 | else
195 | off++;
196 | }
197 | const QByteArray str = d_line.mid(d_colNr, off );
198 | Q_ASSERT( !str.isEmpty() );
199 | int pos = 0;
200 | const QByteArray keyword = str.toLower();
201 | TokenType t = tokenTypeFromString( keyword, &pos );
202 | if( t != Tok_Invalid && pos != str.size() )
203 | t = Tok_Invalid;
204 | if( t != Tok_Invalid )
205 | return token( t, off );
206 | else
207 | return token( Tok_identifier, off, str );
208 | }
209 |
210 | static inline bool isHexDigit( char c )
211 | {
212 | return ::isdigit(c) || c == 'A' || c == 'B' || c == 'C' || c == 'D' || c == 'E' || c == 'F'
213 | || c == 'a' || c == 'b' || c == 'c' || c == 'd' || c == 'e' || c == 'f';
214 | }
215 |
216 | Token Lexer::number()
217 | {
218 | // unsigned_real ::= // digit_sequence [ '.' digit_sequence ] [ scale_factor ]
219 | // scale_factor ::= ('E' | 'e') [sign] digit_sequence
220 | // digit_sequence ::= // digit { digit }
221 |
222 |
223 | int off = 1;
224 | while( true )
225 | {
226 | const char c = lookAhead(off);
227 | if( !::isdigit(c) )
228 | break;
229 | else
230 | off++;
231 | }
232 | bool isReal = false;
233 | if( lookAhead(off) == '.' && lookAhead(off+1) != '.' )
234 | {
235 | isReal = true;
236 | off++;
237 | if( !::isdigit(lookAhead(off)))
238 | return token( Tok_Invalid, off, "invalid real, digit expected after dot" );
239 | while( true )
240 | {
241 | const char c = lookAhead(off);
242 | if( !::isdigit(c) )
243 | break;
244 | else
245 | off++;
246 | }
247 | }
248 | if( lookAhead(off) == 'E' || lookAhead(off) == 'e' )
249 | {
250 | isReal = true;
251 | off++;
252 | char o = lookAhead(off);
253 | if( o == '+' || o == '-' )
254 | {
255 | off++;
256 | o = lookAhead(off);
257 | }
258 | if( !::isdigit(o) )
259 | return token( Tok_Invalid, off, "invalid real, digit expected after exponent" );
260 | while( true )
261 | {
262 | const char c = lookAhead(off);
263 | if( !::isdigit(c) )
264 | break;
265 | else
266 | off++;
267 | }
268 | }
269 | const QByteArray str = d_line.mid(d_colNr, off );
270 | Q_ASSERT( !str.isEmpty() );
271 | if( isReal)
272 | return token( Tok_unsigned_real, off, str );
273 | else
274 | return token( Tok_digit_sequence, off, str );
275 | }
276 |
277 | Token Lexer::hexnumber()
278 | {
279 | // hex_digit_sequence ::= // '$' hex_digit { hex_digit }
280 | // hex_digit ::= digit | 'A'..'F'
281 |
282 | int off = 1;
283 | while( true )
284 | {
285 | const char c = lookAhead(off);
286 | if( !isHexDigit(c) )
287 | break;
288 | else
289 | off++;
290 | }
291 | const QByteArray str = d_line.mid(d_colNr, off );
292 | Q_ASSERT( !str.isEmpty() );
293 | return token( Tok_digit_sequence, off, str );
294 | }
295 |
296 | Token Lexer::comment(bool brace)
297 | {
298 | const int startLine = d_lineNr;
299 | const int startCol = d_colNr;
300 | // startLine and startCol point to first char of (* or {
301 |
302 | const QByteArray tag = brace ? "}" : "*)";
303 | int pos = d_line.indexOf(tag,d_colNr);
304 |
305 | QByteArray str;
306 | bool terminated = false;
307 | if( pos < 0 )
308 | str = d_line.mid(d_colNr);
309 | else
310 | {
311 | terminated = true;
312 | pos += tag.size();
313 | str = d_line.mid(d_colNr,pos-d_colNr);
314 | }
315 | while( !terminated && !d_in->atEnd() )
316 | {
317 | nextLine();
318 | pos = d_line.indexOf(tag,d_colNr);
319 | if( !str.isEmpty() )
320 | str += '\n';
321 | if( pos < 0 )
322 | str += d_line.mid(d_colNr);
323 | else
324 | {
325 | terminated = true;
326 | pos += tag.size();
327 | str += d_line.mid(d_colNr,pos-d_colNr);
328 | }
329 | }
330 | if( d_packComments && !terminated && d_in->atEnd() )
331 | {
332 | d_colNr = d_line.size();
333 | Token t( Tok_Invalid, startLine, startCol + 1, "non-terminated comment" );
334 | t.d_sourcePath = d_filePath;
335 | return t;
336 | }
337 | // Col + 1 weil wir immer bei Spalte 1 beginnen, nicht bei Spalte 0
338 | Token t( ( d_packComments ? Tok_Comment : ( brace ? Tok_Lbrace : Tok_Latt ) ), startLine, startCol + 1, str );
339 | d_lastToken = t;
340 | d_colNr = pos;
341 | t.d_sourcePath = d_filePath;
342 | return t;
343 | }
344 |
345 | Token Lexer::string()
346 | {
347 | int off = 1;
348 | while( true )
349 | {
350 | const char c = lookAhead(off);
351 | off++;
352 | if( c == '\'')
353 | {
354 | if( lookAhead(off) == '\'')
355 | off++;
356 | else
357 | break;
358 | }
359 | if( c == 0 )
360 | return token( Tok_Invalid, off, "non-terminated string" );
361 | }
362 | const QByteArray str = d_line.mid(d_colNr, off );
363 | return token( Tok_string_literal, off, str );
364 | }
365 |
366 | void Lexer::countLine()
367 | {
368 | if( !d_lineCounted )
369 | d_sloc++;
370 | d_lineCounted = true;
371 | }
372 |
--------------------------------------------------------------------------------
/main.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | ** Copyright (C) 2023 Rochus Keller (me@rochus-keller.ch)
3 | **
4 | ** This file is part of the LisaPascal project.
5 | **
6 | ** $QT_BEGIN_LICENSE:LGPL21$
7 | ** GNU Lesser General Public License Usage
8 | ** This file may be used under the terms of the GNU Lesser
9 | ** General Public License version 2.1 or version 3 as published by the Free
10 | ** Software Foundation and appearing in the file LICENSE.LGPLv21 and
11 | ** LICENSE.LGPLv3 included in the packaging of this file. Please review the
12 | ** following information to ensure the GNU Lesser General Public License
13 | ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
14 | ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
15 | */
16 |
17 | #include
18 | #include
19 | #include
20 | #include
21 | #include
22 | #include
23 | #include "LisaPpLexer.h"
24 | #include "LisaParser.h"
25 | #include "Converter.h"
26 | #include "LisaFileSystem.h"
27 | using namespace Lisa;
28 |
29 | static void dump(QTextStream& out, const SynTree* node, int level)
30 | {
31 | QByteArray str;
32 | if( node->d_tok.d_type == Tok_Invalid )
33 | level--;
34 | else if( node->d_tok.d_type < SynTree::R_First )
35 | {
36 | if( tokenTypeIsKeyword( node->d_tok.d_type ) )
37 | str = tokenTypeString(node->d_tok.d_type);
38 | else if( node->d_tok.d_type > TT_Specials )
39 | str = QByteArray("\"") + node->d_tok.d_val + QByteArray("\"");
40 | else
41 | str = QByteArray("\"") + tokenTypeString(node->d_tok.d_type) + QByteArray("\"");
42 |
43 | }else
44 | str = SynTree::rToStr( node->d_tok.d_type );
45 | if( !str.isEmpty() )
46 | {
47 | str += QByteArray("\t") + QFileInfo(node->d_tok.d_sourcePath).baseName().toUtf8() +
48 | ":" + QByteArray::number(node->d_tok.d_lineNr) +
49 | ":" + QByteArray::number(node->d_tok.d_colNr);
50 | QByteArray ws;
51 | for( int i = 0; i < level; i++ )
52 | ws += "| ";
53 | str = ws + str;
54 | out << str.data() << endl;
55 | }
56 | foreach( SynTree* sub, node->d_children )
57 | dump( out, sub, level + 1 );
58 | }
59 |
60 | static void compareFiles( const QStringList& files, int off )
61 | {
62 | foreach( const QString& f, files )
63 | {
64 | QCryptographicHash hash(QCryptographicHash::Md5);
65 | QFile in(f);
66 | in.open(QIODevice::ReadOnly);
67 | hash.addData(in.readAll());
68 | QFileInfo info(f);
69 | qDebug() << f.mid(off) << "\t" << info.fileName().toLower() << "\t" << hash.result().toHex();
70 | }
71 | }
72 |
73 | static void checkDir( const QStringList& files, int off)
74 | {
75 | foreach( const QString& f, files )
76 | {
77 | QFile in(f);
78 | if( !in.open(QIODevice::ReadOnly) )
79 | {
80 | qCritical() << "cannot open file for reading:" << f;
81 | return;
82 | }
83 | if( Converter::detectPascal(&in) == Converter::Unknown )
84 | continue;
85 | QFileInfo info(f);
86 | QDir dir = info.absoluteDir();
87 | const QString fileName = info.fileName().toLower();
88 | QString name;
89 | if( fileName.endsWith("text.unix.txt") )
90 | {
91 | name = fileName;
92 | name.chop(13);
93 | }else
94 | name = info.baseName();
95 | const QStringList parts = name.contains('-') ? name.split('-') : name.split('.');
96 | // name.split(QRegExp("[\-,\.]"));
97 | if( parts.size() == 1 )
98 | qDebug() << "** file with no dir:" << f.mid(off);
99 | else if( parts.size() >= 2 )
100 | {
101 | const QString dirname = dir.dirName().toLower();
102 | if( parts.first() != dirname )
103 | qDebug() << "** actual and virtual dir differ:" << f.mid(off) << dirname << parts.first();
104 | else if( parts.size() > 2 )
105 | qDebug() << "** more than two parts:" << f.mid(off) << dirname << parts.first();
106 | }
107 | }
108 | }
109 |
110 | #define _USE_EBNF_STUDIO_PARSER_
111 |
112 | class Lex
113 | #ifdef _USE_EBNF_STUDIO_PARSER_
114 | : public Scanner
115 | #endif
116 | {
117 | public:
118 | PpLexer lex;
119 | Token next()
120 | {
121 | return lex.nextToken();
122 | }
123 |
124 | Token peek(int offset)
125 | {
126 | return lex.peekToken(offset);
127 | }
128 |
129 | Lex(FileSystem*fs):lex(fs){}
130 | };
131 |
132 | static void runParser(const QString& root)
133 | {
134 | FileSystem fs;
135 | fs.load(root);
136 | // fs.getRoot().dump();
137 |
138 | QList files = fs.getAllPas();
139 | int ok = 0;
140 | QElapsedTimer timer;
141 | timer.start();
142 | foreach( const FileSystem::File* file, files )
143 | {
144 | const QString path = file->getVirtualPath();
145 | Lex lex(&fs);
146 | lex.lex.reset(file->d_realPath);
147 | #ifdef _USE_EBNF_STUDIO_PARSER_
148 | Parser p(&lex);
149 | #else
150 | Parser p(&lex.lex);
151 | #endif
152 | qDebug() << "**** parsing" << path;
153 | p.RunParser();
154 | if( !p.errors.isEmpty() )
155 | {
156 | foreach( const Parser::Error& e, p.errors )
157 | qCritical() << e.path.mid(root.size()) << e.row << e.col << e.msg;
158 | // qCritical() << fs.findFile(e.path)->getVirtualPath() << e.row << e.col << e.msg;
159 |
160 | }else
161 | {
162 | ok++;
163 | qDebug() << "ok";
164 | }
165 | #if 0
166 | QFile out(file->d_realPath + ".st");
167 | out.open(QIODevice::WriteOnly);
168 | QTextStream s(&out);
169 | #ifdef _USE_EBNF_STUDIO_PARSER_
170 | dump(s,&p.root,0);
171 | #else
172 | dump(s,&p.d_root,0);
173 | #endif
174 | #endif
175 | }
176 | qDebug() << "#### finished with" << ok << "files ok of total" << files.size() << "files"
177 | << "in" << timer.elapsed() << " [ms]";
178 | }
179 |
180 | static void runParser(const QString& root, const QString& path)
181 | {
182 | FileSystem fs;
183 | fs.load(root);
184 |
185 | Lex lex(&fs);
186 | lex.lex.reset(path);
187 | #ifdef _USE_EBNF_STUDIO_PARSER_
188 | Parser p(&lex);
189 | #else
190 | Parser p(&lex.lex);
191 | #endif
192 | qDebug() << "**** parsing" << path;
193 | p.RunParser();
194 | if( !p.errors.isEmpty() )
195 | {
196 | foreach( const Parser::Error& e, p.errors )
197 | qCritical() << e.path.mid(root.size()) << e.row << e.col << e.msg;
198 | // qCritical() << fs.findFile(e.path)->getVirtualPath() << e.row << e.col << e.msg;
199 |
200 | }else
201 | {
202 | qDebug() << "ok";
203 | }
204 | #if 0
205 | QFile out(path + ".st");
206 | out.open(QIODevice::WriteOnly);
207 | QTextStream s(&out);
208 | #ifdef _USE_EBNF_STUDIO_PARSER_
209 | dump(s,&p.root,0);
210 | #else
211 | dump(s,&p.d_root,0);
212 | #endif
213 | #endif
214 | }
215 |
216 | static void checkTokens(const QStringList& files)
217 | {
218 | foreach( const QString& file, files )
219 | {
220 | QFile in(file);
221 | if( !in.open(QIODevice::ReadOnly) )
222 | {
223 | qCritical() << "cannot open file for reading:" << file;
224 | return;
225 | }
226 | Lexer lex;
227 | lex.setStream(&in);
228 | lex.setIgnoreComments(false);
229 | Token t = lex.nextToken();
230 | while(t.isValid())
231 | {
232 | // qDebug() << tokenTypeName(t.d_type) << t.d_lineNr << t.d_colNr << t.d_val;
233 | if( t.d_type == Tok_Comment && ( t.d_val.startsWith("{$") || t.d_val.startsWith("(*$") ) )
234 | {
235 | //const QByteArray tmp = t.d_val.toUpper();
236 | //if( tmp.startsWith("{$DECL") || tmp.startsWith("(*$DECL") )
237 | qDebug() << "directive" << QFileInfo(file).fileName() << t.d_lineNr << t.d_colNr << t.d_val;
238 | }
239 | t = lex.nextToken();
240 | }
241 | }
242 | }
243 |
244 | #if 0
245 | static void checkIncludes(const QStringList& files, int off)
246 | {
247 | QMap count;
248 | foreach( const QString& file, files )
249 | {
250 | QFile in(file);
251 | if( !in.open(QIODevice::ReadOnly) )
252 | {
253 | qCritical() << "cannot open file for reading:" << file;
254 | return;
255 | }
256 | Lexer lex;
257 | lex.setStream(&in);
258 | Parser p(&lex);
259 | lex.setStream(&in);
260 | lex.setIgnoreComments(false);
261 | Token t = lex.nextToken();
262 | while(t.isValid())
263 | {
264 | if( t.d_type == Tok_Comment && t.d_val.startsWith("{$") )
265 | {
266 | const int pos = t.d_val.indexOf(' ');
267 | if( pos >= 0 )
268 | {
269 | const QByteArray d = t.d_val.left(pos).mid(2).toUpper();
270 | count[d]++;
271 | if( d == "I" )
272 | qDebug() << "***" << in.fileName().mid(off) << "includes" <<
273 | t.d_val.left(t.d_val.size()-1).mid(pos).trimmed();
274 | }
275 | }
276 | t = lex.nextToken();
277 | }
278 |
279 | }
280 | qDebug() << count;
281 | }
282 | #endif
283 |
284 | static void convert(const QString& root)
285 | {
286 | QFileInfo info(root);
287 | if( info.isDir() )
288 | {
289 | QDir from = info.dir();
290 | QDir to( from.path() + "/converted" );
291 | Converter::convert(from,to);
292 | }
293 | }
294 |
295 | static void checkFileNames(const QStringList& files)
296 | {
297 | foreach( const QString& file, files )
298 | {
299 | QFile in(file);
300 | if( !in.open(QIODevice::ReadOnly) )
301 | {
302 | qCritical() << "cannot open file for reading:" << file;
303 | return;
304 | }
305 | if( Converter::detectPascal(&in) != Converter::Unknown )
306 | {
307 | const QString name = QFileInfo(file).fileName().toLower();
308 | if( !name.endsWith("text.unix.txt") )
309 | qDebug() << "** Pascal file with unexpected suffix:" << files;
310 | }
311 | }
312 | }
313 |
314 | int main(int argc, char *argv[])
315 | {
316 | QCoreApplication a(argc, argv);
317 |
318 | if( a.arguments().size() <= 1 )
319 | return -1;
320 |
321 | #if 0
322 | QStringList files;
323 |
324 | int off = 0;
325 | QFileInfo info(a.arguments()[1]);
326 | if( info.isDir() )
327 | {
328 | files = Converter::collectFiles(info.dir(),QStringList() << "*.txt");
329 | off = a.arguments()[1].size();
330 | }else
331 | files << a.arguments()[1];
332 |
333 | //convert(a.arguments()[1]);
334 | //compareFiles(files,off);
335 | //checkIncludes(files,off);
336 | //checkDir(files,off);
337 | //checkFileNames(files);
338 | //checkTokens(files);
339 | #else
340 | QFileInfo info(a.arguments()[1]);
341 | if( info.isDir() )
342 | runParser(a.arguments()[1]);
343 | else
344 | runParser(info.absolutePath(),info.absoluteFilePath());
345 | #endif
346 |
347 | return 0;
348 | }
349 |
--------------------------------------------------------------------------------
/images/copyright.txt:
--------------------------------------------------------------------------------
1 | This application makes use of some icons of the Lazarus IDE.
2 | The following terms apply:
3 |
4 | LICENSE AND COPYRIGHT INFORMATION ABOUT IMAGES USED IN LAZARUS IDE
5 | ------------------------------------------------------------------
6 |
7 | Public domain Tango https://packages.debian.org/sid/tango-icon-theme
8 | - ToDo
9 |
10 | Creative Commons. Author and source mentioned.
11 | - pkg_sortalphabetically.png, originally sort_ascend.png by Momenticons (got from findicons.com)
12 |
13 | ---
14 |
15 | Following images were created by FTurtle (this holds also for the equally named
16 | files with appendix _150 and _200):
17 |
18 | actions directory:
19 | arrow__darkgreen_down.png
20 | arrow__darkgreen_left.png
21 | arrow__darkgreen_right.png
22 | arrow__darkgreen_up.png
23 | arrow__darkred_down.png
24 | arrow__darkred_left.png
25 | arrow__darkred_right.png
26 | arrow__darkred_up.png
27 | autocomplete.png
28 | filter_any_place.png (used 'item_filter.png' created by Roland Hahn)
29 | filter_from_begin.png (used 'item_filter.png' created by Roland Hahn)
30 | laz_open.png
31 | laz_open_recent.png
32 | laz_open_unit.png
33 | laz_save.png
34 | next_word.png
35 | pastel_colors.png
36 | previous_word.png
37 | restore_default.png
38 | restore_defaults.png
39 | tab_close_All.png
40 | tab_close_L.png
41 | tab_close_LR.png
42 | tab_close_R.png
43 |
44 | debugger directory:
45 | debugger_call_stack.png
46 |
47 | designer directory:
48 | anchor_bottom_bottom.png
49 | anchor_bottom_center.png
50 | anchor_bottom_top.png
51 | anchor_left_center.png
52 | anchor_left_left.png
53 | anchor_left_right.png
54 | anchor_right_center.png
55 | anchor_right_left.png
56 | anchor_right_right.png
57 | anchor_top_bottom.png
58 | anchor_top_center.png
59 | anchor_top_top.png
60 | tab_order.png
61 |
62 | items directory:
63 | datamodule_designer.png (used 'tdatasource.png' created by Roland Hahn)
64 | form_designer.png
65 | frame_designer.png
66 | item_form.png
67 | item_project.png
68 | item_project_source.png
69 | item_unit.png
70 |
71 | menu directory:
72 | menu_add_jump_point_to_history.png
73 | menu_clear_all_bookmarks.png
74 | menu_clear_file_bookmarks.png
75 | menu_close.png
76 | menu_close_all.png
77 | menu_file_revert.png
78 | menu_goto_bookmark0.png
79 | menu_goto_bookmark1.png
80 | menu_goto_bookmark2.png
81 | menu_goto_bookmark3.png
82 | menu_goto_bookmark4.png
83 | menu_goto_bookmark5.png
84 | menu_goto_bookmark6.png
85 | menu_goto_bookmark7.png
86 | menu_goto_bookmark8.png
87 | menu_goto_bookmark9.png
88 | menu_goto_bookmarks.png
89 | menu_goto_line.png
90 | menu_indent.png
91 | menu_jumpto_implementation.png
92 | menu_jumpto_implementationuses.png
93 | menu_jumpto_initialization.png
94 | menu_jumpto_interface.png
95 | menu_jumpto_interfaceuses.png
96 | menu_jumpto_section.png
97 | menu_manage_desktops.png
98 | menu_manage_source_editors.png
99 | menu_new.png
100 | menu_new_form.png
101 | menu_new_search.png
102 | menu_new_unit.png
103 | menu_project_add.png
104 | menu_project_close.png
105 | menu_project_from_file.png
106 | menu_project_inspector.png
107 | menu_project_new.png
108 | menu_project_open.png
109 | menu_project_open_recent.png
110 | menu_project_options.png
111 | menu_project_remove.png
112 | menu_project_save.png
113 | menu_project_save_as.png
114 | menu_redo.png
115 | menu_saveas.png
116 | menu_save_all.png
117 | menu_search_files.png
118 | menu_search_find.png
119 | menu_search_find_next.png
120 | menu_search_find_previous.png
121 | menu_search_incremental.png
122 | menu_search_jumpback.png
123 | menu_search_jumpforward.png
124 | menu_search_next_bookmark.png
125 | menu_search_next_error.png (used 'state_error.png' created by Roland Hahn)
126 | menu_search_openfile_atcursor.png
127 | menu_search_previous_bookmark.png
128 | menu_search_previous_error.png (used 'state_error.png' created by Roland Hahn)
129 | menu_search_procedure_list.png (used 'cc_procedure.png' created by Roland Hahn)
130 | menu_search_replace.png
131 | menu_search_set_bookmark.png
132 | menu_set_free_bookmark.png
133 | menu_stepinto.png
134 | menu_stepout.png
135 | menu_stepover.png
136 | menu_toggle_bookmark0.png
137 | menu_toggle_bookmark1.png
138 | menu_toggle_bookmark2.png
139 | menu_toggle_bookmark3.png
140 | menu_toggle_bookmark4.png
141 | menu_toggle_bookmark5.png
142 | menu_toggle_bookmark6.png
143 | menu_toggle_bookmark7.png
144 | menu_toggle_bookmark8.png
145 | menu_toggle_bookmark9.png
146 | menu_toggle_bookmarks.png
147 | menu_tool_check_lfm.png
148 | menu_tool_syntax_check.png
149 | menu_undo.png
150 | menu_unindent.png
151 | menu_view_anchor_editor.png
152 | menu_view_code_browser.png
153 | menu_view_code_explorer.png
154 | menu_view_components.png
155 | menu_view_forms.png
156 | menu_view_inspector.png
157 | menu_view_jump_history.png
158 | menu_view_messages.png
159 | menu_view_restriction_browser.png
160 | menu_view_search_results.png
161 | menu_view_source_editor.png
162 | menu_view_toggle_form_unit.png
163 | menu_view_units.png
164 | menu_view_unit_info.png
165 |
166 | sourceeditor directory:
167 | bookmark0.png
168 | bookmark1.png
169 | bookmark2.png
170 | bookmark3.png
171 | bookmark4.png
172 | bookmark5.png
173 | bookmark6.png
174 | bookmark7.png
175 | bookmark8.png
176 | bookmark9.png
177 |
178 | states directory:
179 | state_warning.png
180 | state_warning_69.png
181 | state_warning_75.png
182 | state_warning_150.png
183 | state_warning_200.png
184 |
185 | packages directory
186 | pkg_open_recent.png (used 'pkg_open.png' created by Roland Hahn)
187 |
188 | --------------------------------------------------------------------------------
189 |
190 | The following component palette and menu/toolbar icons (including equally named
191 | files with appendix _150 and _200) were created by Roland Hahn (no restrictions).
192 | svg sources can be found on Lazarus Components and Code Repository,
193 | folder image_sources.
194 |
195 | actions folder:
196 | execute.png
197 | laz_cancel.png
198 | laz_edit.png
199 | laz_export.png
200 | laz_highlighter.png
201 | laz_refresh.png
202 | laz_tick.png
203 | laz_wand.png
204 | preferences.png
205 |
206 | codeexplorer folder:
207 | ce_classinterface.png
208 | ce_cycleimplementation.png
209 | ce_cycleinterface.png
210 | ce_default.png
211 | ce_deprecated.png
212 | ce_experimental.png
213 | ce_finalization.png
214 | ce_helper.png
215 | ce_implementation.png
216 | ce_initialization.png
217 | ce_interface.png
218 | ce_library.png
219 | ce_platform.png
220 | ce_program.png
221 | ce_property_readonly.png
222 | ce_section.png
223 | ce_unimplemented.png
224 | show_category.png
225 | show_source.png
226 |
227 | codetoolsdefines folder:
228 | da_block.png
229 | da_define.png
230 | da_definerecurse.png
231 | da_define.png
232 | da_directory.png
233 | da_else.png
234 | da_elseif.png
235 | da_if.png
236 | da_ifdef.png
237 | da_ifndef.png
238 | da_undefine.png
239 | da_undefineall.png
240 | da_undefinerecurse.png
241 |
242 | components folder:
243 | default.png
244 | tactionlist.png
245 | tapplicationproperties.png
246 | tarrow.png
247 | tasyncprocess.png
248 | tbevel.png
249 | tbitbtn.png
250 | tbufdataset.png
251 | tbutton.png
252 | tbuttonpanel.png
253 | tcalcedit.png
254 | tcalculatordialog.png
255 | tcalendar.png
256 | tcalendardialog.png
257 | tcheckbox.png
258 | tcheckcombobox.png
259 | tcheckgroup.png
260 | tchecklistbox.png
261 | tcolorbox.png
262 | tcolorbutton.png
263 | tcolordialog.png
264 | tcolorlistbox.png
265 | tcombobox.png
266 | tcomboboxex.png
267 | tcontrolbar.png
268 | tcoolbar.png
269 | tdatasource.png
270 | tdateedit.png
271 | tdbcalendar.png
272 | tdbcheckbox.png
273 | tdbcombobox.png
274 | tdbdateedit.png
275 | tdbedit.png
276 | tdbgrid.png
277 | tdbgroupbox.png
278 | tdbimage.png
279 | tdblistbox.png
280 | tdblookupcombobox.png
281 | tdblookuplistbox.png
282 | tdbmemo.png
283 | tdbnavigator.png
284 | tdbradiogroup.png
285 | tdbtext.png
286 | tdirectoryedit.png
287 | tdrawgrid.png
288 | tedit.png
289 | teditbutton.png
290 | teventlog.png
291 | tfilelistbox.png
292 | tfilenameedit.png
293 | tfiltercombobox.png
294 | tfinddialog.png
295 | tfloatspinedit.png
296 | tflowpanel.png
297 | tfontdialog.png
298 | tframe.png
299 | tgroupbox.png
300 | theadercontrol.png
301 | thtmlbrowserhelpviewer.png
302 | thtmlhelpdatabase.png
303 | tidedialoglayoutstorage.png
304 | tidletimer.png
305 | timage.png
306 | timagelist.png
307 | tinipropstorage.png
308 | tjsonpropstorage.png
309 | tlabel.png
310 | tlabelededit.png
311 | tlazcomponentqueue.png
312 | tlistbox.png
313 | tlistview.png
314 | tmainmenu.png
315 | tmaskedit.png
316 | tmemo.png
317 | tmouse.png
318 | tnotebook.png
319 | topendialog.png
320 | topenpicturedialog.png
321 | tpagecontrol.png
322 | tpaintbox.png
323 | tpairsplitter.png
324 | tpanel.png
325 | tpicture.png
326 | tpopupmenu.png
327 | tpopupnotifier.png
328 | tprocess.png
329 | tprocessutf8.png
330 | tprogressbar.png
331 | tradiobutton.png
332 | tradiogroup.png
333 | treplacedialog.png
334 | tsavedialog.png
335 | tsavepicturedialog.png
336 | tscrollbar.png
337 | tscrollbox.png
338 | tselectdirectorydialog.png
339 | tservicemanager.png
340 | tshape.png
341 | tshelllistview.png
342 | tshelltreeview.png
343 | tsimpleipcclient.png
344 | tsimpleipcserver.png
345 | tspeedbutton.png
346 | tspinedit.png
347 | tsplitter.png
348 | tstatictext.png
349 | tstatusbar.png
350 | tstringgrid.png
351 | ttabcontrol.png
352 | ttaskdialog.png
353 | ttimeedit.png
354 | ttimer.png
355 | ttogglebox.png
356 | ttoolbar.png
357 | ttrackbar.png
358 | ttrayicon.png
359 | ttreeview.png
360 | tupdown.png
361 | tvaluelisteditor.png
362 | txmlconfig.png
363 | txmlpropstorage.png
364 | unregisteredcomponent.png
365 |
366 | componenttreeview directory
367 | oi_box.png
368 | oi_collection.png
369 | oi_comp.png
370 | oi_control.png
371 | oi_form.png
372 | oi_item.pnt
373 |
374 | debugger directory
375 | callstack_bottom.png
376 | callstack_goto.png
377 | callstack_more.png
378 | callstack_show.png
379 | callstack_top.png
380 | camera.png
381 | camera_add.png
382 | camera_go.png
383 | clock.png
384 | debugger.png
385 | debugger_breakpoints.png
386 | debugger_disable.png
387 | debugger_disable_all.png
388 | debugger_enable.png
389 | debugger_enable_all.png
390 | debugger_evaluate.png
391 | debugger_event_log.png
392 | debugger_inspect.png
393 | debugger_modify.png
394 | debugger_options.png
395 | debugger_output.png
396 | debugger_power.png
397 | debugger_power_grey.png
398 | debugger_show_execution_point.png
399 | debugger_watches.png
400 | evaluate_no_hist.png
401 | evaluate_up.png
402 |
403 | designer directory
404 | align.png
405 | mirror_horizontal.png
406 | mirror_vertical.png
407 | order_back_one.png
408 | order_forward_one.png
409 | order_move_back.png
410 | order_move_front.png
411 | scale.png
412 | size.png
413 |
414 | items directory
415 | item_character.png
416 | item_filter.png
417 | item_font.png
418 | item_keyboard.png
419 | item_library.png
420 | item_package.png
421 | item_todo.png
422 |
423 | lazdoc directory
424 | formatbold.png
425 | formatitalic.png
426 | formatunderline.png
427 | insertcodetag.png
428 | insertremark.png
429 | insertvartag.png
430 |
431 | menu directory
432 | menu_abort_build.png
433 | menu_build.png
434 | menu_build_all.png
435 | menu_build_clean.png
436 | menu_build_file.png
437 | menu_build_lazarus.png
438 | menu_build_run_file.png
439 | menu_clean.png
440 | menu_codetoolsdefineseditor.png
441 | menu_codetoolsoptions.png
442 | menu_comment.png
443 | menu_compiler_options.png
444 | menu_configure_build_lazarus.png
445 | menu_configure_help.png
446 | menu_editor_options.png
447 | menu_edit_lowercase.png
448 | menu_edit_sort.png
449 | menu_edit_uppercase.png
450 | menu_environment_options.png
451 | menu_exit.png
452 | menu_file_print.png
453 | menu_information.png
454 | menu_jumpto_procedurebegin.png
455 | menu_jumptoprocedureheader.png
456 | menu_pause.png
457 | menu_quick_compile.png
458 | menu_reportingbug.png
459 | menu_reset_debugger.png
460 | menu_run_file.png
461 | menu_run_cursor.png
462 | menu_run_file.png
463 | menu_run_parameters.png
464 | menu_run_withoutdebuggin.png
465 | menu_search_set_bookmark.png
466 | menu_select_all.png
467 | menu_stepinto_instr.png
468 | menu_stepinto_instr_run_file.png
469 | menu_stepover:instr.png
470 | menu_stop.png
471 | menu_tool_del_to_laz.png
472 | menu_tool_del_to_laz_form.png
473 | menu_tool_del_to_laz_pkg.png
474 | menu_tool_del_to_laz_project.png
475 | menu_tool_del_to_laz_unit.png
476 | menu_tool_diff.png
477 | menu_tool_make_resourcestring.png
478 | menu_uncomment.png
479 | menu_view_todo.png
480 | SelCompPage.png
481 |
482 | packages directory
483 | pkg_add.png
484 | pkg_binary.png
485 | pkg_compile.png
486 | pkg_conflict.png
487 | pkg_core_overlay.png
488 | pkg_design_overlay.png
489 | pkg_files.png
490 | pkg_fpc_overlay.png
491 | pkg_graph.png
492 | pkg_hierarchical.png
493 | pkg_include.png
494 | pkg_inherited.png
495 | pkg_install.png
496 | pkg_installed.png
497 | pkg_issues.png
498 | pkg_lazarus_overlay.png
499 | pkg_lfm.png
500 | pkg_lrs.png
501 | pkg_open.png
502 | pkg_package_autoinstall.png
503 | pkg_package_circle.png
504 | pkg_package_uninstall.png
505 | pkg_properties.png
506 | pkg_registerunit.png
507 | pkg_removedfiles.png
508 | pkg_removedrequired.png
509 | pkg_required.png
510 | pkg_runtime_overlay.png
511 | pkg_sortalphabetically.png
512 | pkg_text.png
513 | pkg_unit.png
514 |
515 | states directory (also variants with appendix _69 and _75)
516 | quickfix
517 | state_circular_reference
518 | state_error
519 | state_fatal
520 | state_hint
521 | state_information
522 | state_note
523 | state_not_found
524 | state_unit_circular_reference
525 | state_unknown
526 | state_warning
527 |
528 | windows directory
529 | win_formeditor.ico
530 | win_main.ico
531 | win_message.ico
532 | win_objectinspector.ico
533 | win_sourceditor.ico
534 |
535 | images root folder
536 | folder.png
537 | includefile.ico
538 | LazarusForm.ico
539 | lazaruspackage.ico
540 | LazarusSource.ico
541 | lprfile.ico
542 | template.png
543 |
544 | -----------------------------------------
545 |
546 | The following images were created by regs:
547 |
548 | codecompletion folder:
549 | cc_class.png, cc_class_150.png, cc_class_200.png
550 | cc_constant.png, cc_constant_150.png, cc_constant_200.png
551 | cc_constructor.png, cc_constructor_150.png, cc_constructor_200.png
552 | cc_destructor.png, cc_destructor_150.png, cc_destructor_200.png
553 | cc_enum.png, cc_enum_150.png, cc_enum_200.png
554 | cc_function.png, cc_function_150.png, cc_function_200.png
555 | cc_label.png, cc_label_150.png, cc_label_200.png
556 | cc_namespace.png, cc_namespace_150.png, cc_namespace_200.png
557 | cc_procedure.png, cc_procedure_150.png, cc_procedure_200.png
558 | cc_property.png, cc_property_150.png, cc_property_200.png
559 | cc_property_ro.png, cc_property_ro_150.png, cc_property_ro_200.png
560 | cc_record.png, cc_record_150.png, cc_record_200.png
561 | cc_type.png, cc_type_150.png, cc_type_200.png
562 | cc_unit.png, cc_unit_150.png, cc_unit_200.png
563 | cc_variable.png, cc_variable_150.png, cc_variable_200.png
564 |
--------------------------------------------------------------------------------
/syntax/LisaPascal.ebnf:
--------------------------------------------------------------------------------
1 | // Copyright 2023 Rochus Keller and others
2 |
3 | // started with the Pascal EBNF found at https://www.icosaedro.it/bnf_chk/ebnf-pascal.txt
4 | // which itself was translated from https://web.archive.org/web/20100411050221/http://www.lrz-muenchen.de/~bernhard/Pascal-EBNF.html
5 | // Modifications
6 | // - modified the grammar for compatibility with EbnfStudio
7 | // - renamed type to type_, label to label_, program to program_ and set to set_literal to avoid collision with keyword
8 | // - renamed string to string_literal
9 | // - removed variable_list, output_list, output_value, field_width and fraction_length because unused
10 | // - replaced left recursive variable, component_variable, referenced_variable, indexed_variable, array_variable,
11 | // record_variable, file_variable, pointer_variable, field_designator and file_buffer by a generic
12 | // thus removed entire_variable, component_variable, indexed_variable, referenced_variable, field_designator, etc.
13 | // replaced variable by the variable_reference ::= variable_identifier { qualifier } from the Lisa Pascal spec
14 | // - extended the syntax by the additional constructs from LisaPascal according to
15 | // "Pascal Reference Manual for the Lisa", Beta Draft April 1983
16 | // - correlated the whole syntax with appendix C of the said manual and removed constructs not used by Lisa
17 | // - removed all LL(1) ambiguities
18 | // - Correction of the syntax according to actual Lisa source code (in deviation from the reference manual). Changes:
19 | // added procedure_and_function_interface_part
20 | // files can apparently also only contain procedures
21 | // added non_regular_unit
22 | // NOTE that a preprocessor seems to be required which is the reason why certain files per se don't meet syntax,
23 | // or only meet syntax if conditional sections are actively selected or muted and files are included.
24 | // - Added Clascal syntax from spec; modified as long as compatible with the Lisa source code
25 |
26 | // Programs and Blocks
27 |
28 | #define CLASCAL
29 |
30 | LisaPascal ::= program_ | regular_unit | non_regular_unit
31 |
32 | program_ ::=
33 | program_heading ';' [ uses_clause ] block
34 | [ statement_part '.' ] // can apparently be left out, as e.g. APDM-DESK
35 | program_heading ::=
36 | program identifier [ '(' program_parameters ')' ]
37 | program_parameters ::= identifier_list
38 | uses_clause ::= uses identifier_list2 ';'
39 | identifier_list2 ::=
40 | identifier [ '/' identifier ] { ',' identifier [ '/' identifier ] } // apparently legal, seen e.g. in libhw/keyboard
41 |
42 | regular_unit ::=
43 | unit_heading ';' [ intrinsic [shared] ';' ] // apparently the sources deviate from the spec for intrinsic
44 | interface_part implementation_part
45 | [ end '.' ] // end can apparently be left out, as done in some files
46 | unit_heading ::=
47 | unit identifier
48 | interface_part ::=
49 | interface
50 | [ uses_clause ]
51 | { ( constant_declaration_part
52 | | type_declaration_part
53 | | variable_declaration_part
54 | | procedure_and_function_interface_part ) }
55 | implementation_part ::=
56 | implementation
57 | { ( constant_declaration_part
58 | | type_declaration_part
59 | | variable_declaration_part
60 | #ifdef CLASCAL
61 | | subroutine_part
62 | #else
63 | | procedure_and_function_declaration_part
64 | #endif
65 | ) }
66 |
67 | non_regular_unit ::=
68 | // Coco seems to have an issue with this in that the generated procedure
69 | // without the \LA starts with while( la in {procedure,function,end}
70 | { \LA: 1:(procedure|function)\ procedure_and_function_declaration_part }
71 | [ statement_part '.' | end '.' ]
72 |
73 | block ::=
74 | { ( label_declaration_part
75 | | constant_declaration_part
76 | | type_declaration_part
77 | | variable_declaration_part
78 | | procedure_and_function_declaration_part ) }
79 | // statement_part removed to make it optional if need be
80 | label_declaration_part ::=
81 | label label_ { ',' label_ } ';'
82 | label_ ::=
83 | digit_sequence
84 | constant_declaration_part ::=
85 | const constant_declaration { constant_declaration }
86 | constant_declaration ::=
87 | identifier '=' // constant [';'] // apparently optional, seen e.g. in libte/lcut:46
88 | expression [';'] // apparently this can be a full expression, as e.g. seen in libtk/uabc
89 | constant ::=
90 | [ sign ] ( identifier [ actual_parameter_list ] // constant_identifier or built-in function (apparently supported as well)
91 | | unsigned_number ) | string_literal
92 | type_declaration_part ::=
93 | type type_declaration { type_declaration }
94 | type_declaration ::=
95 | identifier '=' type_ ';'
96 | variable_declaration_part ::=
97 | var variable_declaration { variable_declaration }
98 | variable_declaration ::=
99 | identifier_list ':' type_ ';'
100 | procedure_and_function_interface_part ::=
101 | { procedure_heading ';' | function_heading ';' }
102 | procedure_and_function_declaration_part ::=
103 | { procedure_declaration | function_declaration }
104 | #ifdef CLASCAL
105 | subroutine_part ::=
106 | { procedure_declaration | function_declaration | method_block }
107 | method_block ::=
108 | methods of identifier [';'] // class_identifier
109 | // semi can apparently be left out as seen e.g. in libut/uunivtext
110 | [ procedure_and_function_declaration_part ]
111 | // this is the specified syntax, but apparently nowhere used [ [creation] begin block statement_part ] // creation_block
112 | // creation can apparently be left out, as seen in libqp/uqpgraph
113 | ( statement_part | end ) [';'] // this is the actual syntax used in the code
114 | #endif
115 | procedure_declaration ::=
116 | procedure_heading ';' body_ ';'
117 | body_ ::= // procedure_body, function_body
118 | block statement_part | 'forward' | 'external' | 'inline' constant
119 | function_declaration ::=
120 | function_heading ';' body_ ';'
121 | statement_part ::=
122 | compound_statement
123 |
124 | // Procedure and Function Definitions
125 |
126 | procedure_heading ::=
127 | procedure identifier [ '.' identifier ] [ formal_parameter_list ]
128 | // apparently in method_interface proc and func names can be Class.Name
129 | function_heading ::=
130 | function identifier [ '.' identifier ] [ formal_parameter_list ]
131 | [':' result_type ] // return type can apparently be left out, as done in some files
132 | result_type ::=
133 | type_identifier // ordinal/real/pointer_type_ident
134 | formal_parameter_list ::=
135 | '(' formal_parameter_section { [';'] // semicolon can apparently be optional, seen in libfp-MATHLIB.TEXT
136 | formal_parameter_section } ')'
137 | formal_parameter_section ::=
138 | parameter_declaration |
139 | procedure_heading |
140 | function_heading
141 | parameter_declaration ::=
142 | [var] identifier_list ':' type_identifier // original Pascal in contrast to Lisa also supports conformant_array_schema
143 |
144 | // Statements
145 |
146 | statement_sequence ::=
147 | statement { ';' statement }
148 | statement ::=
149 | [ label_ ':' ] ( [simple_statement] | structured_statement)
150 | simple_statement ::=
151 | // assignment_statement | procedure_statement | goto_statement
152 | assigOrCall | goto_statement
153 | assignment_statement- ::=
154 | (variable_reference | function_identifier) ':=' expression
155 | assigOrCall ::=
156 | variable_reference // covers assig lhs incl. function_identifier
157 | [ ':=' expression ] // covers assig rhs
158 | // no in variable_ref: | [ actual_parameter_list ] ) // covers procedure_statement, but only if lhs has no qualifier
159 | procedure_statement- ::=
160 | procedure_identifier [ actual_parameter_list ]
161 | goto_statement ::=
162 | goto label_
163 | structured_statement ::=
164 | compound_statement | repetitive_statement | conditional_statement | with_statement
165 | compound_statement ::=
166 | begin statement_sequence end
167 | repetitive_statement ::=
168 | while_statement | repeat_statement | for_statement
169 | while_statement ::=
170 | while expression do statement
171 | repeat_statement ::=
172 | repeat statement_sequence until expression
173 | for_statement ::=
174 | for variable_identifier ':=' initial_value (to | downto) final_value do statement
175 | initial_value ::=
176 | expression
177 | final_value ::=
178 | expression
179 | conditional_statement ::=
180 | if_statement | case_statement
181 | if_statement ::=
182 | if expression then statement [ else statement ]
183 | case_statement ::=
184 | case expression of
185 | [case_limb { \LA: 1: ';' & 2:(!end&!otherwise)\ ';' [case_limb] } ] // apparently stray ';' are allowed in case
186 | // can apparently be empty, as seen e.g. in libtk/uobject:1531
187 | [ \LL:2\ otherwise_clause ] [ ';' ]
188 | end
189 | case_limb ::=
190 | case_label_list ':' statement
191 | case_label_list ::=
192 | constant { ',' constant }
193 | otherwise_clause ::=
194 | [';'] otherwise statement
195 | // semi can apparently be missing, as seen e.g. in libtk/uobject:1531
196 | with_statement ::=
197 | with variable_reference { ',' variable_reference } do statement // references a record
198 | actual_parameter_list ::=
199 | '(' actual_parameter { ',' actual_parameter } ')'
200 | actual_parameter ::=
201 | expression // included | variable_reference | procedure_identifier | function_identifier
202 |
203 | // Expressions
204 |
205 | expression ::=
206 | simple_expression [ relational_operator simple_expression ]
207 | simple_expression ::=
208 | [ sign ] term { addition_operator term }
209 | term ::=
210 | factor { multiplication_operator factor }
211 | factor ::=
212 | '@' variable_reference
213 | | identifier { qualifier | actual_parameter_list } // function_designator, bound_identifier, constant_identifier
214 | // Lisa combines unsigned_number, string, constant_identifier and nil to unsigned_constant
215 | | unsigned_number
216 | | string_literal
217 | | nil
218 | | set_literal
219 | | '(' expression ')'
220 | | not factor
221 | relational_operator ::=
222 | '=' | '<>' | '<' | '<=' | '>' | '>=' | in
223 | addition_operator ::=
224 | '+' | '-' | or
225 | multiplication_operator ::=
226 | '*' | '/' | ':' | div | mod | and // ':' is apparently also supported instead of div
227 |
228 | variable_reference ::=
229 | variable_identifier { qualifier | actual_parameter_list } // apparently lhs can be function call with deref
230 | qualifier ::=
231 | index | field_designator | dereferencer
232 | index ::=
233 | '[' expression_list ']'
234 | field_designator ::=
235 | '.' field_identifier
236 | dereferencer ::= // Lisa: file_buffer_symbol or pointer_object_symbol
237 | '^'
238 |
239 | set_literal ::= // Lisa: set_constructor
240 | '[' [ member_group { ',' member_group } ] ']'
241 | member_group ::=
242 | expression [ '..' expression ]
243 | //function_designator ::=
244 | // function_identifier [ actual_parameter_list ]
245 |
246 | // Types
247 |
248 | type_ ::=
249 | simple_type | string_type | structured_type | pointer_type // already includes ident via simple_type subrange_type: | type_identifier
250 | // ident for real_type_ident, ordinal_type_ident, string_type_ident, structured_type_ident and pointer_type_ident
251 | simple_type ::=
252 | \LA: 1:identifier & 2:!'..'\ identifier
253 | | subrange_type
254 | | enumerated_type
255 | ordinal_type ::=
256 | simple_type // already includes constant_ident via subrange_type: | type_identifier // for ordinal_type_ident
257 | string_type ::= string '[' size_attribute ']'
258 | size_attribute ::=
259 | unsigned_integer
260 | | identifier // apparently also supported
261 | enumerated_type ::=
262 | '(' identifier_list ')'
263 | subrange_type ::=
264 | constant ( '..' | ':' ) constant // ':' apparently is supported too, e.g. in SOURCE-VMSTUFF
265 | structured_type ::=
266 | [ packed ] ( array_type | record_type | set_type | file_type
267 | #ifdef CLASCAL
268 | | class_type
269 | #endif
270 | )
271 | array_type ::=
272 | array '[' index_type { ',' index_type } ']' of type_
273 | index_type ::=
274 | ordinal_type
275 | set_type ::=
276 | set of ordinal_type
277 | file_type ::=
278 | file [ of type_ ] // of type_ can apparently be left out, see source/nwshell
279 | pointer_type ::=
280 | '^' type_identifier
281 |
282 | #ifdef CLASCAL
283 | class_type ::=
284 | subclass of ( type_identifier | nil ) // class_identifier; nil apparently supported too, seen in libpl/blkiointr
285 | [ field_list ]
286 | method_interface { method_interface }
287 | end
288 | method_interface ::=
289 | ( procedure_heading | function_heading )
290 | [ \LL:2\ ';' identifier ] ';' // 'abstract' | 'classwide' | 'override' | 'default'
291 | // override not in spec but used in code
292 | #endif
293 |
294 | // Records
295 |
296 | record_type ::=
297 | record [ field_list ] end
298 | field_list ::=
299 | (fixed_part [ \LL:2\ ';' variant_part ] | variant_part) [ ';' ]
300 | fixed_part ::=
301 | field_declaration { \LL:2\ ';' field_declaration }
302 | field_declaration ::=
303 | identifier_list ':' type_
304 | variant_part ::=
305 | case [ \LL:2\ tag_field] type_identifier // ordinal_type_ident
306 | of variant { \LA: 1:';' & 2:!(end|')')\ ';' variant }
307 | tag_field ::=
308 | identifier ':'
309 | variant ::=
310 | case_label_list ':' '(' [field_list] ')'
311 |
312 | // Variable and Identifier Categories
313 |
314 | field_identifier ::=
315 | identifier
316 | constant_identifier- ::=
317 | identifier
318 | variable_identifier ::=
319 | identifier
320 | type_identifier ::=
321 | identifier
322 | procedure_identifier- ::=
323 | identifier
324 | function_identifier- ::=
325 | identifier
326 | //bound_identifier ::=
327 | // identifier
328 |
329 | // Low Level Definitions
330 |
331 | identifier ::= // letter { letter | digit | '_' }
332 | // letter ::= 'A' .. 'Z' | 'a' .. 'z'
333 | // digit ::= '0' .. '9'
334 | identifier_list ::=
335 | identifier { ',' identifier }
336 | expression_list ::=
337 | expression { ',' expression }
338 |
339 | unsigned_integer ::= digit_sequence | hex_digit_sequence
340 | unsigned_real ::= // digit_sequence [ '.' digit_sequence ] [ scale_factor ]
341 | // scale_factor ::= ('E' | 'e') [sign] digit_sequence
342 | unsigned_number ::= unsigned_integer | unsigned_real
343 | digit_sequence ::= // digit { digit }
344 | hex_digit_sequence ::= // '$' hex_digit { hex_digit }
345 | // hex_digit ::= digit | 'A'..'F'
346 | sign ::= '+' | '-'
347 | string_literal ::= // ''' string_character { string_character } '''
348 |
349 | // Helper Tokens
350 | Comment ::=
351 | Directive ::=
352 | comment- ::= '(*' '*)' '{' '}'
353 | #ifndef CLASCAL
354 | oostuff- ::= methods subclass creation
355 | #endif
356 |
357 | // Pragmas
358 | %module ::= 'LisaPascal'
359 | %namespace ::= 'Lisa'
360 | %suppress ::= ';' ',' '.'
361 |
362 | // comaring the syntax of Pascal Manual & Report 2nd (1975) and 4th edition
363 | // - the set of keywords are identical
364 |
365 | // comparing the syntax of LisaPascal 1983 with Manual & Report
366 | // - LisaPascal added these keywords: creation, implementation, interface, intrinsic, methods, otherwise, string
367 | // subclass, unit, uses; no keywords were removed
368 |
369 | // Comparing the syntax of LisaPascal Version 3 with Beta 1983
370 | // - Went through all synatx diagrams in both appendices C
371 | // - All are identical
372 | // - the keywords subclass, methods, creation not used
373 |
--------------------------------------------------------------------------------