42 Commits
Author SHA1 Message Date
chrisly42 62f7f13323 Bumped to IntelliJ/CLion 2021.2.2 2021-09-25 21:29:17 +02:00
chrisly42 c4051a0377 'END' detection was breaking parsing, causing havoc. 2021-09-25 17:20:45 +02:00
chrisly42 a03de6c394 Added documentation provider info for global labels. Shows directives and comments above.
Fixed BNF for labels with preprocessor statements.
Bumped versions.
2021-09-25 15:19:05 +02:00
chrisly42 1bff1a12c2 Documentation for instruction with special register shows specific register expected. 2021-09-05 18:42:20 +02:00
chrisly42 665947827b Updated build to latest versions. 2021-09-04 14:23:15 +02:00
chrisly42 3bb6165a58 Courtesy of Yann:
Bugfix: Special registers for address mode matching only worked with lower case register names.
Bugfix: movem with pc-relative mode was missing for weird immediate mode.
Bugfix: btst with pc-relative and weird immediate mode was missing.
Enhancement: Assembler syntax with implicit immediate 1 for shifts and rotations no longer cause syntax errors.
2021-09-04 14:08:10 +02:00
chrisly42 89bd964fe7 Minor updates to documentation. 2021-08-09 15:27:12 +02:00
chrisly42 0cb90ff8d7 'END' directive stops parsing. Prepared next release. 2021-08-09 12:14:02 +02:00
chrisly42 431caf64fd Added inspection for unresolved symbols, macros and labels. 2021-08-09 11:26:13 +02:00
chrisly42 a3f7ddb4f7 New: Added inspection suppression possibility and quickfix. 2021-08-09 10:08:41 +02:00
chrisly42 593719043e New: Code completion for local label definitions, suggesting undefined labels already referenced. 2021-08-08 13:40:01 +02:00
chrisly42 e0cdfef42b New: Files in 'include' directives can be referenced and renamed/refactored. 2021-08-06 20:03:47 +02:00
chrisly42 8d7977927f Added M68kIncludeFileProvider, but dunno what it's actually for. 2021-08-06 19:12:54 +02:00
chrisly42 ddf78ec210 Slightly reworked lexer to for a few directives:
'opt' and several other directives ('printt', 'fail' etc.) no longer causes a syntax error when unquoted.
'include', 'incdir' and 'incbin' and 'output' with '<pathname>' quotes no longer cause syntax error.
2021-08-06 10:06:48 +02:00
chrisly42 2c3daf28f7 TODO list. Prepared next release (for tomorrow). 2021-08-05 19:02:55 +02:00
chrisly42 1dcf288d27 Added inspection to warn about unexpected condition code unaffecting instructions before conditional instructions.
Extended documentation.
Bugfix in M68kDeadWriteInspection.
2021-08-05 18:42:32 +02:00
chrisly42 2abb5af8b0 Macros with register name now abort Dead Write analysis. Fix for modifying statements extending the with of the written data. 2021-08-05 16:21:32 +02:00
chrisly42 6c9a726b86 Preprocessor statements now abort Dead Write analysis. 2021-08-05 15:46:16 +02:00
chrisly42 921449cbb8 Refactored stuff.
Added control flow information to ISA.
In ISA exg is no longer treated as setting a definitive value.
Added inspection find dead writes to registers.
2021-08-04 17:39:54 +02:00
chrisly42 6f99c2ffcc Moved Condition-Code stuff to separate file, added reverse mapping function.
Reworked Instruction Documentation provider, now shows condition codes.
Cosmetics: Removed MutableList information where unnecessary
2021-08-04 12:24:16 +02:00
chrisly42 5881dcdaf8 Optimized mnemonic lookup. 2021-08-03 18:28:53 +02:00
chrisly42 71398f51d2 Reworked and extended ISA to hold condition code testing and affecting information (not used yet).
Minor fix for `andi/eori/ori to ccr` which were not byte sized in ISA.
Added alternate condition code tests HS (=CC) and LO (=CS).
2021-08-03 13:45:44 +02:00
chrisly42 eb26793a20 movem ISA was wrong regarding movem.w <ea>,<registerlist> (sign extends registers).
Changed Register Flow Documentation wording from 'reads' to 'uses' and from 'modifies' to 'changes'.
Updated screenshot. Added another test case for M68kRegisterFlowDocumentationProviderTest.
2021-08-03 10:57:53 +02:00
chrisly42 954f42bf63 Tweaking for M68kRegisterFlowDocumentationProvider regarding colors, formatting and abbreviated documentation on hover. Prepared next release. 2021-08-03 07:59:47 +02:00
chrisly42 94001c8b87 Added explicit IndexRegister-PSI-Element. Major rework to support new DocumentationProvider on registers.
When asking for documentation on registers, a code flow analysis is done.
2021-08-02 20:54:30 +02:00
chrisly42 55403f89a6 Added a few tests for M68kSyntaxInspection. 2021-08-02 10:07:25 +02:00
chrisly42 7744b589d4 Added support for movem with register list crossing from data to address (e.g. d0-a6) as found in p61a source. 2021-08-02 09:43:42 +02:00
chrisly42 19e3b519db Bugfix: Macro definitions with colons and without space supported (as found in P61a source). 2021-08-02 09:41:51 +02:00
chrisly42 587b284d25 Fix in movem ISA (supports pc relative if first parameter). Also, single registers must also work (often optimized by the assembler). Increased default max macro parsing length to 250 lines. 2021-08-02 09:41:51 +02:00
chrisly42 719460ebfe Minor code refactoring. 2021-08-01 20:02:36 +02:00
chrisly42 44a4721d77 Added names for Adressing Modes.
Added Documentation Provider for symbol definitions (shows assigned declaration).
Added Documentation Provider for mnemonics (simple version, generated out of ISA information).
Work in progress for Register Flow Documentation Provider.
New minimum required version of IDE is now 2020.3.
2021-08-01 19:51:42 +02:00
chrisly42 09a4e62c7c Bugfix: Interpretation of register lists was wrong in BNF.
Massively extended M68kIsa with description on register modifications (not yet used in production code).
Changed BNF for additional AddressingMode interfaces.
2021-08-01 10:08:01 +02:00
chrisly42 ce3cdbbed6 Bugfix: Uppercase hexadecimal literals were not parsed (JFlex bug?) 2021-07-31 14:12:58 +02:00
chrisly42 27b7593de8 Added several missing assembler directives (opt, machine, etc.) 2021-07-31 14:04:18 +02:00
chrisly42 3aeb415974 Massively reworked and extended ISA-Description class.
Added inspection to validate the correctness of a MC68000 instruction regarding operation size and address modes.
2021-07-31 13:56:07 +02:00
chrisly42 128330d2c7 Added Structure View filters for Symbols, Macros and Labels. 2021-07-30 15:25:48 +02:00
chrisly42 ef900e9c19 Added LICENSE.TXT, changed build.gradle to 2021.2 and added new build to plugin verification. Minor change to README.md regarding caching of coveralls badge. 2021-07-30 14:05:37 +02:00
chrisly42 8ea70f0dfa Docs update. Prepared next release. 2021-07-28 08:00:09 +02:00
chrisly42 fa1ef0b3d5 Reduced lexer code by combining state rules. Removed one rule, that seemed to be wrong. 2021-07-27 20:27:58 +02:00
chrisly42 3de9e9eba2 Restored compatibility with IDEs versions < 2021.1. Added PluginVerifier to build.gradle. 2021-07-27 17:46:11 +02:00
chrisly42 25450a9bf8 Macro definitions are now word and indexed, macro calls reference to definition.
Macro definition refactoring and find usages support.
Structural View also shows macro definitions.
Missing REPT and ENDR assembler directives added.
Changed or added some icons at various places.
Reference search for global labels and symbols now uses stub index.
2021-07-27 16:34:49 +02:00
chrisly42 6e683eb6a0 Started working on macro support. Macro-Definition are now plain, unparsed lines. Added Syntax-Highlighter options. 2021-07-27 12:42:26 +02:00
173 changed files with 6836 additions and 1412 deletions
+13
View File
@@ -0,0 +1,13 @@
Copyright 2021 Chris Hodges <chrisly@platon42.de>
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
+162 -19
View File
@@ -1,8 +1,8 @@
# MC68000 Assembly Language Plugin [![Build Status](https://travis-ci.com/chrisly42/mc68000-asm-plugin.svg?branch=main)](https://travis-ci.com/chrisly42/mc68000-asm-plugin) [![Coverage Status](https://coveralls.io/repos/github/chrisly42/mc68000-asm-plugin/badge.svg?branch=main)](https://coveralls.io/github/chrisly42/mc68000-asm-plugin?branch=main) # MC68000 Assembly Language Plugin [![Build Status](https://travis-ci.com/chrisly42/mc68000-asm-plugin.svg?branch=main)](https://travis-ci.com/chrisly42/mc68000-asm-plugin) [![Coverage Status](https://coveralls.io/repos/github/chrisly42/mc68000-asm-plugin/badge.svg?branch=main&kill_cache=1)](https://coveralls.io/github/chrisly42/mc68000-asm-plugin?branch=main)
_MC68000 Assembly Language Plugin_ is plugin for Jetbrains IDEs (CLion, IntelliJ, etc.). _MC68000 Assembly Language Plugin_ is plugin for Jetbrains IDEs (CLion, IntelliJ, etc.).
![Example Syntax Highlighting](docs/syntaxhighlighting.png "Example Syntax Highlighting") ![Example IDE Screenshot](docs/example.png "Example IDE Screenshot")
## Purpose ## Purpose
@@ -10,8 +10,8 @@ This plugin delivers support for MC68000 assembly language files ([VAsm](http://
It adds a language parser with syntax highlighting, referencing and refactoring support, and a few more features. It adds a language parser with syntax highlighting, referencing and refactoring support, and a few more features.
I'm an Amiga retro democoder, and the lack of a plugin for M68k was the motivation to write one. Also, diving deep into custom language plugins has a steep I'm an Amiga retro democoder (among other things), and the lack of a plugin for M68k was the motivation to write one. Also, diving deep into custom language
learning curve. plugins has a steep learning curve.
When I started the plugin in July 2021, I was not aware of the [M68k plugin efforts by Jetbrains employee Yann Cébron](https://github.com/YannCebron/m68kplugin) When I started the plugin in July 2021, I was not aware of the [M68k plugin efforts by Jetbrains employee Yann Cébron](https://github.com/YannCebron/m68kplugin)
who has been working on the same topic for quite some time. At the time of writing, his plugin however, has not been release yet. Nevertheless, it has a lot of who has been working on the same topic for quite some time. At the time of writing, his plugin however, has not been release yet. Nevertheless, it has a lot of
@@ -19,40 +19,118 @@ awesome features and is pretty advanced. Check it out. You can install both plug
Big kudos to Yann -- a few features were _inspired_ by his code. Big kudos to Yann -- a few features were _inspired_ by his code.
My plugin, on the other hand, is still pretty basic and is the result of about a week's effort. I released a really early first version it because I think My plugin, on the other hand, is still pretty basic and is the result of a few weeks of work. I released the first versions because I think it's "good enough"
it's "good enough" to get started, and I can return to demo coding with its current state. to get started, and I can return to demo coding with its current state.
## Features ## Features
- Parser / Lexer for MC68000 (yes, only 68000 right now!) assembly language files in VAsm / DevPac style - Parser / Lexer for MC68000 (yes, only 68000 right now!) assembly language files in VAsm / DevPac style
- Validates the assembly syntax against the 68000 ISA.
- Syntax highlighting and Color Settings Page (you should really modify the color settings to your likings!) - Syntax highlighting and Color Settings Page (you should really modify the color settings to your likings!)
- Mnemonics code completion - Mnemonics code completion
- Symbols / Labels code completion - Symbols / labels / macros code completion
- References / Refactoring support for local and global labels, and symbol assignments. - References / refactoring support for local and global labels, symbol assignments, and macros.
- Simple register usage flow (hover over register or press F1 for full flow)
- Brace matching - Brace matching
- Quote handler - Quote handler
- Goto Symbol support - Goto Symbol support
- Structure view - Structure view
- Documentation provider for symbol definitions and mnemonics (listing available addressing modes etc.).
### Inspections
The plugin provides a few inspections for code analysis. An error or warning can be suppressed by placing a `; suppress <InspectionName>` comment either on an
end of line comment behind the statement or in a full line comment above the statement.
#### M68kSyntax - Assembly instruction validity
Checks the validity of the current instruction. If an instruction is not recognized, you may get one of the following errors:
- Instruction _mnemonic_ not supported on selected cpu (you won't get this currently as only MC68000 is supported)
- No operands expected for _mnemonic_
- Second operand _op_ unexpected for _mnemonic_
- Unsupported addressing mode for _mnemonic_
- Unsupported addressing mode _op_ for first operand of _mnemonic_
- Unsupported addressing mode _op_ for second operand of _mnemonic_
- Unsupported addressing modes for operands in this order for _mnemonic_ (try swapping)
- Instruction _mnemonic_ is unsized (you tried to specify `.b`, `.w` or `.l`)
- Operation size _(.b,.w,.l)_ unsupported for _mnemonic_
- Operation size _(.b,.w,.l)_ unsupported (should be _(.b,.w,.l)_)
#### M68kDeadWrite - Dead writes to registers
This inspection looks at register writes and tries to find instructions that renders a write moot because it was overwritten by another instruction before
anything useful was done with it.
Analysis is aborted at global labels, flow control instructions, directives
(e.g. conditional assembly) and macros with the register names as parameter.
The inspection tries to take condition code changing into account and puts out a weak warning if the statement merely changes condition codes before the
contents of the register are overwritten. In this case, it is sometimes better to replace `move` by `tst`.
#### M68kUnexpectedConditionalInstruction - Unaffected condition codes before conditional instruction
Especially for novice coders, it is not clear that some instructions do not affect the condition codes for a subsequent condition branch or `scc` instruction.
`movea`, `adda` and `suba` come to my mind.
The inspection will report such suspicious instruction sequences.
However, this does not need to be a programming error. Advanced coders sometimes make use of the fact that instructions do not change condition codes and thus
optimize the order of execution.
#### M68kUnresolvedReference - Unresolved label/symbol/macro reference
Points out unresolved references such for global and local labels, macros or symbols. Right now, missing symbol and global label references are shown only as
weak warnings as missing macro evaluation will not resolve symbols defined via `STRUCT` macros.
### Documentation provider
#### M68kSymbolDefinition
Provides the assigned value of a `=`, `set` or `equ` symbol definition when hovering over a symbol.
#### M68kGlobalLabel
Shows the comments above the label and if the first statement after the label is a directive like `include` or `dc.b`, shows it, too.
#### M68kRegisterFlow
When hovering over or placing the cursor at a data or address register, the documentation will scan through the instructions backwards and forwards and will
show all read, changes of the register contents. It does this until an instruction is found that defines (sets) the contents of the register
(according to the size of the instruction where the cursor was placed).
The analysis ignores all code flow instructions and might be inaccurate for branches, macro use, etc. It also stops at global labels.
The documentation will search up to 100 instructions in each direction, but only four when hovering over the register
(so if you need the whole analysis, use the documentation window).
#### M68kInstruction
When hovering over a mnemonic, it will show a short description of the assembly instruction.
For the documentation window, affected condition codes, allowed operation sizes and addressing modes are listed for the selected instruction
(so only stuff from `cmpa` is listed when you're looking at a `cmp.w a0,a1` instruction).
If the current statement has no valid syntax, the instruction details of all matching mnemonics will be shown instead.
## Known issues ## Known issues
- No referencing of macro invocations and macro definitions. - `Find Usages` always shows _"Unclassified"_ though it shouldn't (?)
- `Find Usages` always shows _"Unclassified"_ though it shouldn't. - `END` detection was breaking parsing, so this is disabled for now until I find a working solution.
- Macro definitions may cause syntax errors when using backslash arguments.
- Macro invocations are not yet evaluated, thus no referencing to symbols defined via macros (e.g. `STRUCT`). - Macro invocations are not yet evaluated, thus no referencing to symbols defined via macros (e.g. `STRUCT`).
- No support for includes. Scoping is for global symbols and labels is currently the whole project. - Scoping for global symbols and labels is currently the whole project.
- No support for register replacement (e.g. registers replaced by `EQUR` or `EQURL` will cause syntax errors) - No support for register replacement (e.g. registers replaced by `EQUR` or `EQURL` will cause syntax errors)
- While the Lexer supports the -spaces option (where a space introduces a comment), this cannot be configured yet. - While the Lexer supports the -spaces option (where a space introduces a comment), this cannot be configured yet (default is off).
- No support for other processor instructions, FPU or 68020+ address modes. - No support for other processor instructions, FPU or 68020+ address modes.
- No semantic checking for allowed address modes or data widths yet.
- Unit Test coverage is not as good as it could be (ahem). - Unit Test coverage is not as good as it could be (ahem).
- Missing but planned features: - Missing but planned features:
- Macro definition and evaluation on invocation - Macro evaluation on invocation
- Folding - Folding
- Semantic inspections - More semantic inspections
- Quick fixes - Quick fixes
- Formatter + Code Style Settings - Maybe formatter + Code Style Settings
- Register use analysis (but this only makes sense after macro evaluation) - Register use analysis (but this only makes sense after macro evaluation)
- Cycle counting
## Recommendations ## Recommendations
@@ -67,13 +145,78 @@ It is probably the only plugin (besides [Cajon](https://github.com/chrisly42/caj
far (or at least the only one I'm aware of ;) ). The IntelliJ framework actually uses the JUnit 3 TestCase for plugin testing, and it took me quite a while to far (or at least the only one I'm aware of ;) ). The IntelliJ framework actually uses the JUnit 3 TestCase for plugin testing, and it took me quite a while to
make it work with JUnit 5. Feel free to use the code (in package ```de.platon42.intellij.jupiter```) for your projects (with attribution). make it work with JUnit 5. Feel free to use the code (in package ```de.platon42.intellij.jupiter```) for your projects (with attribution).
## Feedback
I guess there are currently over 500 users of this plugin and while I wrote this mainly for myself, I'm only doing this in my spare time.
Feedback and [rating](https://plugins.jetbrains.com/plugin/17268-mc68000-assembly-language-support/reviews)
are appreciated. It really is keeping me motivated to continue development.
## Changelog ## Changelog
### V0.7 (26-Sep-21)
- Bugfix: `btst` with pc-relative and weird immediate mode was missing (courtesy of Yann).
- Bugfix: `movem` with pc-relative mode was missing for weird immediate mode (courtesy of Yann).
- Bugfix: Special registers for address mode matching only worked with lower case register names (courtesy of Yann).
- Enhancement: Assembler syntax with implicit immediate 1 for shifts and rotations no longer cause syntax errors (courtesy of Yann).
- Enhancement: Documentation for instruction with special register shows specific register expected.
- New: Added documentation provider info for global labels. Shows directives and comments above.
- Bugfix: Fixed BNF for labels with preprocessor statements.
- Disabled: `END` detection was breaking parsing, causing havoc.
### V0.6 (09-Aug-21)
- Enhancement: `opt` and several other directives (`printt`, `fail` etc.) no longer causes a syntax error when unquoted.
- Enhancement: `include`, `incdir` and `incbin` and `output` with `<pathname>` quotes no longer cause syntax error.
- New: Files in `include` directives can be referenced and renamed/refactored.
- New: Code completion for local label definitions, suggesting undefined labels already referenced.
- New: Added inspection suppression possibility and quickfix.
- New: Added inspection for unresolved symbols, macros and labels.
- Enhancement: 'END' directive stops parsing.
### V0.5 (06-Aug-21)
- Bugfix: `movem` ISA was wrong regarding the `movem.w <ea>,<registerlist>` (sign extends registers).
- Cosmetics: Changed Register Flow Documentation wording from _reads_ to _uses_ and from _modifies_ to _changes_.
- Bugfix: Minor fix for `andi/eori/ori to ccr` which were not byte sized in ISA.
- Bugfix: Added alternate condition code tests `HS (=CC)` and `LO (=CS)`.
- Performance: Optimized mnemonic lookup.
- Enhancement: Reworked Instruction Documentation provider, now shows condition codes.
- Bugfix: In ISA `exg` is no longer treated as setting a definitive value.
- New: Added inspection to find dead writes to registers!
- New: Added inspection to warn about unexpected condition code unaffecting instructions before conditional instructions.
### V0.4 (03-Aug-21)
- Notice: Due to major new API use, this plugin no longer works on IDEs >=2019.3.1, but rather requires >=2020.3.
- Enhancement: Added Structure View filters.
- New: Added inspection to validate the correctness of a MC68000 instruction regarding operation size and address modes.
- Bugfix: Added several missing assembler directives (`opt`, `machine`, etc.).
- Bugfix: Uppercase hexadecimal literals were not parsed (JFlex bug?).
- Bugfix: Interpretation of register lists was wrong in BNF.
- New: Added Documentation Provider for symbol definitions (shows assigned declaration).
- New: Added Documentation Provider for mnemonics (simple version, generated out of ISA information).
- Bugfix: Macro definitions with colons and without space supported (as found in P61a source).
- New: When asking for documentation on registers, a code flow analysis is done. Cool stuff!
### V0.3 (28-Jul-21)
- Enhancement: Macro contents are no longer parsed, added syntax highlighting options for macros.
- Enhancement: Macro definitions are now word and stub indexed, macro calls reference to definition.
- New: Macro definition refactoring and find usages support.
- Enhancement: Structural View also shows macro definitions.
- Bugfix: Missing `REPT` and `ENDR` assembler directives added.
- Cosmetics: Changed or added some icons at various places.
- Performance: Reference search for global labels and symbols now uses stub index.
- Compatibility: Restored compatibility with IDE versions < 2021.1.
- Performance: Optimized lexer.
### V0.2 (27-Jul-21) ### V0.2 (27-Jul-21)
- Cosmetics: Added (same) icon for plugin as for file type. - Cosmetics: Added (same) icon for plugin as for file type.
- Performance improvement: Use Word-Index for global labels and symbols instead of iterating over the file. - Performance: Use Word-Index for global labels and symbols instead of iterating over the file.
- Performance improvement: Use Stub-Index for global labels and symbols. - Performance: Use Stub-Index for global labels and symbols.
- Bugfix: No longer reports a syntax error when file lacks terminating End-Of-Line. - Bugfix: No longer reports a syntax error when file lacks terminating End-Of-Line.
- Enhancement: Registers are now offered for code completion, making editing less annoying. - Enhancement: Registers are now offered for code completion, making editing less annoying.
+30 -19
View File
@@ -1,13 +1,13 @@
plugins { plugins {
id 'java' id 'java'
id 'org.jetbrains.intellij' version '1.1.3' id 'org.jetbrains.intellij' version '1.1.6'
id 'org.jetbrains.kotlin.jvm' version '1.5.21' id 'org.jetbrains.kotlin.jvm' version '1.5.21'
id 'jacoco' id 'jacoco'
id 'com.github.kt3k.coveralls' version '2.11.0' id 'com.github.kt3k.coveralls' version '2.12.0'
} }
group = 'de.platon42' group = 'de.platon42'
version = '0.2' version = '0.7'
sourceCompatibility = "1.8" sourceCompatibility = "1.8"
targetCompatibility = "1.8" targetCompatibility = "1.8"
@@ -21,17 +21,20 @@ repositories {
*/ */
dependencies { dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8" implementation 'org.jetbrains.kotlin:kotlin-stdlib-jdk8'
testImplementation "org.assertj:assertj-core:3.20.2" testImplementation "org.assertj:assertj-core:3.21.0"
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.0-M1' testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.1'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.0-M1' testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.1'
testImplementation "org.jetbrains.kotlin:kotlin-test" testImplementation "org.jetbrains.kotlin:kotlin-test"
testImplementation "org.jetbrains.kotlin:kotlin-reflect" testImplementation "org.jetbrains.kotlin:kotlin-reflect"
// testImplementation "org.jetbrains.kotlin:kotlin-test-junit" // testImplementation "org.jetbrains.kotlin:kotlin-test-junit"
} }
compileKotlin { compileKotlin {
kotlinOptions.jvmTarget = "1.8" kotlinOptions {
jvmTarget = "1.8"
freeCompilerArgs += "-Xjvm-default=all"
}
} }
compileTestKotlin { compileTestKotlin {
@@ -39,24 +42,32 @@ compileTestKotlin {
} }
intellij { intellij {
setVersion("2021.1.3") // LATEST-EAP-SNAPSHOT setVersion("2021.2.2") // LATEST-EAP-SNAPSHOT
setUpdateSinceUntilBuild(false) setUpdateSinceUntilBuild(false)
// setPlugins(["com.intellij.java"]) // setPlugins(["com.intellij.java"])
} }
runPluginVerifier {
ideVersions = ["IC-203.6682.168", "IC-212.5284.40", // 2020.3 - 2021.2.2
"CL-203.5981.166", "CL-203.8084.11", // 2020.3
"CL-211.6693.114", "CL-211.7628.27", // 2021.1
"CL-212.4746.93", "CL-212.5284.51"] // 2021.2 - 2021.2.2
downloadDir = System.getProperty("user.home") + "/.gradle/caches/modules-2/files-2.1/com.jetbrains.intellij.idea/verifier"
}
patchPluginXml { patchPluginXml {
setChangeNotes(""" setChangeNotes("""
<h4>V0.2 (27-Jul-21)</h4> <p>I still got zero feedback and zero <a href="https://plugins.jetbrains.com/plugin/17268-mc68000-assembly-language-support/reviews">ratings</a> :-(</p>
<h4>V0.7 (26-Sep-21)</h4>
<ul> <ul>
<li>Cosmetics: Added (same) icon for plugin as for file type. <li>Bugfix: 'btst' with pc-relative and weird immediate mode was missing (courtesy of Yann).
<li>Performance improvement: Use Word-Index for global labels and symbols instead of iterating over the file. <li>Bugfix: 'movem' with pc-relative mode was missing for weird immediate mode (courtesy of Yann).
<li>Performance improvement: Use Stub-Index for global labels and symbols. <li>Bugfix: Special registers for address mode matching only worked with lower case register names (courtesy of Yann).
<li>Bugfix: No longer reports a syntax error when file lacks terminating End-Of-Line. <li>Enhancement: Assembler syntax with implicit immediate 1 for shifts and rotations no longer cause syntax errors (courtesy of Yann).
<li>Enhancement: Registers are now offered for code completion, making editing less annoying. <li>Enhancement: Documentation for instruction with special register shows specific register expected.
</ul> <li>New: Added documentation provider info for global labels. Shows directives and comments above.
<h4>V0.1 (20-Jul-21)</h4> <li>Bugfix: Fixed BNF for labels with preprocessor statements.
<ul> <li>Disabled: 'END' detection was breaking parsing, causing havoc.
<li>Initial public release.
</ul> </ul>
<p>Full changelog available at <a href="https://github.com/chrisly42/mc68000-asm-plugin#changelog">Github project site</a>.</p> <p>Full changelog available at <a href="https://github.com/chrisly42/mc68000-asm-plugin#changelog">Github project site</a>.</p>
""") """)
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 91 KiB

File diff suppressed because it is too large Load Diff
@@ -211,7 +211,7 @@ public class M68kParser implements PsiParser, LightPsiParser {
} }
/* ********************************************************** */ /* ********************************************************** */
// ROUND_L (expr SEPARATOR)? AddressRegister SEPARATOR DataOrAddressRegister DataWidth? ROUND_R // ROUND_L (expr SEPARATOR)? AddressRegister SEPARATOR IndexRegister ROUND_R
public static boolean AddressRegisterIndirectWithIndexNewAddressingMode(PsiBuilder b, int l) { public static boolean AddressRegisterIndirectWithIndexNewAddressingMode(PsiBuilder b, int l) {
if (!recursion_guard_(b, l, "AddressRegisterIndirectWithIndexNewAddressingMode")) return false; if (!recursion_guard_(b, l, "AddressRegisterIndirectWithIndexNewAddressingMode")) return false;
if (!nextTokenIsFast(b, ROUND_L)) return false; if (!nextTokenIsFast(b, ROUND_L)) return false;
@@ -221,8 +221,7 @@ public class M68kParser implements PsiParser, LightPsiParser {
r = r && AddressRegisterIndirectWithIndexNewAddressingMode_1(b, l + 1); r = r && AddressRegisterIndirectWithIndexNewAddressingMode_1(b, l + 1);
r = r && AddressRegister(b, l + 1); r = r && AddressRegister(b, l + 1);
r = r && consumeToken(b, SEPARATOR); r = r && consumeToken(b, SEPARATOR);
r = r && DataOrAddressRegister(b, l + 1); r = r && IndexRegister(b, l + 1);
r = r && AddressRegisterIndirectWithIndexNewAddressingMode_5(b, l + 1);
r = r && consumeToken(b, ROUND_R); r = r && consumeToken(b, ROUND_R);
exit_section_(b, l, m, r, false, null); exit_section_(b, l, m, r, false, null);
return r; return r;
@@ -246,15 +245,8 @@ public class M68kParser implements PsiParser, LightPsiParser {
return r; return r;
} }
// DataWidth?
private static boolean AddressRegisterIndirectWithIndexNewAddressingMode_5(PsiBuilder b, int l) {
if (!recursion_guard_(b, l, "AddressRegisterIndirectWithIndexNewAddressingMode_5")) return false;
DataWidth(b, l + 1);
return true;
}
/* ********************************************************** */ /* ********************************************************** */
// expr? ROUND_L AddressRegister SEPARATOR DataOrAddressRegister DataWidth? ROUND_R // expr? ROUND_L AddressRegister SEPARATOR IndexRegister ROUND_R
public static boolean AddressRegisterIndirectWithIndexOldAddressingMode(PsiBuilder b, int l) { public static boolean AddressRegisterIndirectWithIndexOldAddressingMode(PsiBuilder b, int l) {
if (!recursion_guard_(b, l, "AddressRegisterIndirectWithIndexOldAddressingMode")) return false; if (!recursion_guard_(b, l, "AddressRegisterIndirectWithIndexOldAddressingMode")) return false;
boolean r; boolean r;
@@ -263,8 +255,7 @@ public class M68kParser implements PsiParser, LightPsiParser {
r = r && consumeToken(b, ROUND_L); r = r && consumeToken(b, ROUND_L);
r = r && AddressRegister(b, l + 1); r = r && AddressRegister(b, l + 1);
r = r && consumeToken(b, SEPARATOR); r = r && consumeToken(b, SEPARATOR);
r = r && DataOrAddressRegister(b, l + 1); r = r && IndexRegister(b, l + 1);
r = r && AddressRegisterIndirectWithIndexOldAddressingMode_5(b, l + 1);
r = r && consumeToken(b, ROUND_R); r = r && consumeToken(b, ROUND_R);
exit_section_(b, l, m, r, false, null); exit_section_(b, l, m, r, false, null);
return r; return r;
@@ -277,13 +268,6 @@ public class M68kParser implements PsiParser, LightPsiParser {
return true; return true;
} }
// DataWidth?
private static boolean AddressRegisterIndirectWithIndexOldAddressingMode_5(PsiBuilder b, int l) {
if (!recursion_guard_(b, l, "AddressRegisterIndirectWithIndexOldAddressingMode_5")) return false;
DataWidth(b, l + 1);
return true;
}
/* ********************************************************** */ /* ********************************************************** */
// OPSIZE_W|OPSIZE_L // OPSIZE_W|OPSIZE_L
public static boolean AddressSize(PsiBuilder b, int l) { public static boolean AddressSize(PsiBuilder b, int l) {
@@ -364,12 +348,12 @@ public class M68kParser implements PsiParser, LightPsiParser {
// MNEMONIC OperandSize? // MNEMONIC OperandSize?
public static boolean AsmOp(PsiBuilder b, int l) { public static boolean AsmOp(PsiBuilder b, int l) {
if (!recursion_guard_(b, l, "AsmOp")) return false; if (!recursion_guard_(b, l, "AsmOp")) return false;
if (!nextTokenIs(b, MNEMONIC)) return false; if (!nextTokenIs(b, "<mnemonic>", MNEMONIC)) return false;
boolean r; boolean r;
Marker m = enter_section_(b); Marker m = enter_section_(b, l, _NONE_, ASM_OP, "<mnemonic>");
r = consumeToken(b, MNEMONIC); r = consumeToken(b, MNEMONIC);
r = r && AsmOp_1(b, l + 1); r = r && AsmOp_1(b, l + 1);
exit_section_(b, m, ASM_OP, r); exit_section_(b, l, m, r, false, null);
return r; return r;
} }
@@ -547,11 +531,30 @@ public class M68kParser implements PsiParser, LightPsiParser {
return r; return r;
} }
/* ********************************************************** */
// DataOrAddressRegister DataWidth?
public static boolean IndexRegister(PsiBuilder b, int l) {
if (!recursion_guard_(b, l, "IndexRegister")) return false;
boolean r;
Marker m = enter_section_(b, l, _NONE_, INDEX_REGISTER, "<index register>");
r = DataOrAddressRegister(b, l + 1);
r = r && IndexRegister_1(b, l + 1);
exit_section_(b, l, m, r, false, null);
return r;
}
// DataWidth?
private static boolean IndexRegister_1(PsiBuilder b, int l) {
if (!recursion_guard_(b, l, "IndexRegister_1")) return false;
DataWidth(b, l + 1);
return true;
}
/* ********************************************************** */ /* ********************************************************** */
// AsmInstruction | MacroCall // AsmInstruction | MacroCall
static boolean Instruction(PsiBuilder b, int l) { static boolean Instruction(PsiBuilder b, int l) {
if (!recursion_guard_(b, l, "Instruction")) return false; if (!recursion_guard_(b, l, "Instruction")) return false;
if (!nextTokenIs(b, "", MACRO_INVOKATION, MNEMONIC)) return false; if (!nextTokenIs(b, "", MACRO_INVOCATION, MNEMONIC)) return false;
boolean r; boolean r;
r = AsmInstruction(b, l + 1); r = AsmInstruction(b, l + 1);
if (!r) r = MacroCall(b, l + 1); if (!r) r = MacroCall(b, l + 1);
@@ -559,9 +562,13 @@ public class M68kParser implements PsiParser, LightPsiParser {
} }
/* ********************************************************** */ /* ********************************************************** */
// Instruction // Instruction|PreprocessorDirective
static boolean InstructionOnly(PsiBuilder b, int l) { static boolean InstructionOnly(PsiBuilder b, int l) {
return Instruction(b, l + 1); if (!recursion_guard_(b, l, "InstructionOnly")) return false;
boolean r;
r = Instruction(b, l + 1);
if (!r) r = PreprocessorDirective(b, l + 1);
return r;
} }
/* ********************************************************** */ /* ********************************************************** */
@@ -593,18 +600,27 @@ public class M68kParser implements PsiParser, LightPsiParser {
} }
/* ********************************************************** */ /* ********************************************************** */
// Label Instruction // Label (Instruction|PreprocessorDirective)
static boolean LabelWithInstruction(PsiBuilder b, int l) { static boolean LabelWithInstruction(PsiBuilder b, int l) {
if (!recursion_guard_(b, l, "LabelWithInstruction")) return false; if (!recursion_guard_(b, l, "LabelWithInstruction")) return false;
if (!nextTokenIs(b, "", GLOBAL_LABEL_DEF, LOCAL_LABEL_DEF)) return false; if (!nextTokenIs(b, "", GLOBAL_LABEL_DEF, LOCAL_LABEL_DEF)) return false;
boolean r; boolean r;
Marker m = enter_section_(b); Marker m = enter_section_(b);
r = Label(b, l + 1); r = Label(b, l + 1);
r = r && Instruction(b, l + 1); r = r && LabelWithInstruction_1(b, l + 1);
exit_section_(b, m, null, r); exit_section_(b, m, null, r);
return r; return r;
} }
// Instruction|PreprocessorDirective
private static boolean LabelWithInstruction_1(PsiBuilder b, int l) {
if (!recursion_guard_(b, l, "LabelWithInstruction_1")) return false;
boolean r;
r = Instruction(b, l + 1);
if (!r) r = PreprocessorDirective(b, l + 1);
return r;
}
/* ********************************************************** */ /* ********************************************************** */
// LOCAL_LABEL_DEF COLON? // LOCAL_LABEL_DEF COLON?
public static boolean LocalLabel(PsiBuilder b, int l) { public static boolean LocalLabel(PsiBuilder b, int l) {
@@ -638,13 +654,13 @@ public class M68kParser implements PsiParser, LightPsiParser {
} }
/* ********************************************************** */ /* ********************************************************** */
// MACRO_INVOKATION PlainOperands? // MACRO_INVOCATION PlainOperands?
public static boolean MacroCall(PsiBuilder b, int l) { public static boolean MacroCall(PsiBuilder b, int l) {
if (!recursion_guard_(b, l, "MacroCall")) return false; if (!recursion_guard_(b, l, "MacroCall")) return false;
if (!nextTokenIs(b, MACRO_INVOKATION)) return false; if (!nextTokenIs(b, MACRO_INVOCATION)) return false;
boolean r; boolean r;
Marker m = enter_section_(b); Marker m = enter_section_(b);
r = consumeToken(b, MACRO_INVOKATION); r = consumeToken(b, MACRO_INVOCATION);
r = r && MacroCall_1(b, l + 1); r = r && MacroCall_1(b, l + 1);
exit_section_(b, m, MACRO_CALL, r); exit_section_(b, m, MACRO_CALL, r);
return r; return r;
@@ -657,6 +673,97 @@ public class M68kParser implements PsiParser, LightPsiParser {
return true; return true;
} }
/* ********************************************************** */
// ((MacroNameDefinition COLON? MACRO_TAG)|(MACRO_TAG MacroNameDefinition)) MacroPlainLine* MACRO_END_TAG
public static boolean MacroDefinition(PsiBuilder b, int l) {
if (!recursion_guard_(b, l, "MacroDefinition")) return false;
if (!nextTokenIs(b, "<macro definition>", MACRO_NAME, MACRO_TAG)) return false;
boolean r, p;
Marker m = enter_section_(b, l, _NONE_, MACRO_DEFINITION, "<macro definition>");
r = MacroDefinition_0(b, l + 1);
p = r; // pin = 1
r = r && report_error_(b, MacroDefinition_1(b, l + 1));
r = p && consumeToken(b, MACRO_END_TAG) && r;
exit_section_(b, l, m, r, p, null);
return r || p;
}
// (MacroNameDefinition COLON? MACRO_TAG)|(MACRO_TAG MacroNameDefinition)
private static boolean MacroDefinition_0(PsiBuilder b, int l) {
if (!recursion_guard_(b, l, "MacroDefinition_0")) return false;
boolean r;
Marker m = enter_section_(b);
r = MacroDefinition_0_0(b, l + 1);
if (!r) r = MacroDefinition_0_1(b, l + 1);
exit_section_(b, m, null, r);
return r;
}
// MacroNameDefinition COLON? MACRO_TAG
private static boolean MacroDefinition_0_0(PsiBuilder b, int l) {
if (!recursion_guard_(b, l, "MacroDefinition_0_0")) return false;
boolean r;
Marker m = enter_section_(b);
r = MacroNameDefinition(b, l + 1);
r = r && MacroDefinition_0_0_1(b, l + 1);
r = r && consumeToken(b, MACRO_TAG);
exit_section_(b, m, null, r);
return r;
}
// COLON?
private static boolean MacroDefinition_0_0_1(PsiBuilder b, int l) {
if (!recursion_guard_(b, l, "MacroDefinition_0_0_1")) return false;
consumeToken(b, COLON);
return true;
}
// MACRO_TAG MacroNameDefinition
private static boolean MacroDefinition_0_1(PsiBuilder b, int l) {
if (!recursion_guard_(b, l, "MacroDefinition_0_1")) return false;
boolean r;
Marker m = enter_section_(b);
r = consumeToken(b, MACRO_TAG);
r = r && MacroNameDefinition(b, l + 1);
exit_section_(b, m, null, r);
return r;
}
// MacroPlainLine*
private static boolean MacroDefinition_1(PsiBuilder b, int l) {
if (!recursion_guard_(b, l, "MacroDefinition_1")) return false;
while (true) {
int c = current_position_(b);
if (!MacroPlainLine(b, l + 1)) break;
if (!empty_element_parsed_guard_(b, "MacroDefinition_1", c)) break;
}
return true;
}
/* ********************************************************** */
// MACRO_NAME
public static boolean MacroNameDefinition(PsiBuilder b, int l) {
if (!recursion_guard_(b, l, "MacroNameDefinition")) return false;
if (!nextTokenIs(b, MACRO_NAME)) return false;
boolean r;
Marker m = enter_section_(b);
r = consumeToken(b, MACRO_NAME);
exit_section_(b, m, MACRO_NAME_DEFINITION, r);
return r;
}
/* ********************************************************** */
// MACRO_LINE
public static boolean MacroPlainLine(PsiBuilder b, int l) {
if (!recursion_guard_(b, l, "MacroPlainLine")) return false;
if (!nextTokenIs(b, MACRO_LINE)) return false;
boolean r;
Marker m = enter_section_(b);
r = consumeToken(b, MACRO_LINE);
exit_section_(b, m, MACRO_PLAIN_LINE, r);
return r;
}
/* ********************************************************** */ /* ********************************************************** */
// OPSIZE_BS|OPSIZE_W|OPSIZE_L // OPSIZE_BS|OPSIZE_W|OPSIZE_L
public static boolean OperandSize(PsiBuilder b, int l) { public static boolean OperandSize(PsiBuilder b, int l) {
@@ -671,19 +778,27 @@ public class M68kParser implements PsiParser, LightPsiParser {
} }
/* ********************************************************** */ /* ********************************************************** */
// STRINGLIT (SEPARATOR STRINGLIT)* // (expr|AddressingMode) (SEPARATOR (expr|AddressingMode))*
static boolean PlainOperands(PsiBuilder b, int l) { static boolean PlainOperands(PsiBuilder b, int l) {
if (!recursion_guard_(b, l, "PlainOperands")) return false; if (!recursion_guard_(b, l, "PlainOperands")) return false;
if (!nextTokenIs(b, STRINGLIT)) return false;
boolean r; boolean r;
Marker m = enter_section_(b); Marker m = enter_section_(b);
r = consumeToken(b, STRINGLIT); r = PlainOperands_0(b, l + 1);
r = r && PlainOperands_1(b, l + 1); r = r && PlainOperands_1(b, l + 1);
exit_section_(b, m, null, r); exit_section_(b, m, null, r);
return r; return r;
} }
// (SEPARATOR STRINGLIT)* // expr|AddressingMode
private static boolean PlainOperands_0(PsiBuilder b, int l) {
if (!recursion_guard_(b, l, "PlainOperands_0")) return false;
boolean r;
r = expr(b, l + 1, -1);
if (!r) r = AddressingMode(b, l + 1);
return r;
}
// (SEPARATOR (expr|AddressingMode))*
private static boolean PlainOperands_1(PsiBuilder b, int l) { private static boolean PlainOperands_1(PsiBuilder b, int l) {
if (!recursion_guard_(b, l, "PlainOperands_1")) return false; if (!recursion_guard_(b, l, "PlainOperands_1")) return false;
while (true) { while (true) {
@@ -694,53 +809,59 @@ public class M68kParser implements PsiParser, LightPsiParser {
return true; return true;
} }
// SEPARATOR STRINGLIT // SEPARATOR (expr|AddressingMode)
private static boolean PlainOperands_1_0(PsiBuilder b, int l) { private static boolean PlainOperands_1_0(PsiBuilder b, int l) {
if (!recursion_guard_(b, l, "PlainOperands_1_0")) return false; if (!recursion_guard_(b, l, "PlainOperands_1_0")) return false;
boolean r; boolean r;
Marker m = enter_section_(b); Marker m = enter_section_(b);
r = consumeTokens(b, 0, SEPARATOR, STRINGLIT); r = consumeToken(b, SEPARATOR);
r = r && PlainOperands_1_0_1(b, l + 1);
exit_section_(b, m, null, r); exit_section_(b, m, null, r);
return r; return r;
} }
// expr|AddressingMode
private static boolean PlainOperands_1_0_1(PsiBuilder b, int l) {
if (!recursion_guard_(b, l, "PlainOperands_1_0_1")) return false;
boolean r;
r = expr(b, l + 1, -1);
if (!r) r = AddressingMode(b, l + 1);
return r;
}
/* ********************************************************** */ /* ********************************************************** */
// Label? (DATA_DIRECTIVE | OTHER_DIRECTIVE) // PreprocessorKeyword PreprocessorOperands?
// PreprocessorOperands?
public static boolean PreprocessorDirective(PsiBuilder b, int l) { public static boolean PreprocessorDirective(PsiBuilder b, int l) {
if (!recursion_guard_(b, l, "PreprocessorDirective")) return false; if (!recursion_guard_(b, l, "PreprocessorDirective")) return false;
if (!nextTokenIs(b, "<preprocessor directive>", DATA_DIRECTIVE, OTHER_DIRECTIVE)) return false;
boolean r; boolean r;
Marker m = enter_section_(b, l, _NONE_, PREPROCESSOR_DIRECTIVE, "<preprocessor directive>"); Marker m = enter_section_(b, l, _NONE_, PREPROCESSOR_DIRECTIVE, "<preprocessor directive>");
r = PreprocessorDirective_0(b, l + 1); r = PreprocessorKeyword(b, l + 1);
r = r && PreprocessorDirective_1(b, l + 1); r = r && PreprocessorDirective_1(b, l + 1);
r = r && PreprocessorDirective_2(b, l + 1);
exit_section_(b, l, m, r, false, null); exit_section_(b, l, m, r, false, null);
return r; return r;
} }
// Label? // PreprocessorOperands?
private static boolean PreprocessorDirective_0(PsiBuilder b, int l) {
if (!recursion_guard_(b, l, "PreprocessorDirective_0")) return false;
Label(b, l + 1);
return true;
}
// DATA_DIRECTIVE | OTHER_DIRECTIVE
private static boolean PreprocessorDirective_1(PsiBuilder b, int l) { private static boolean PreprocessorDirective_1(PsiBuilder b, int l) {
if (!recursion_guard_(b, l, "PreprocessorDirective_1")) return false; if (!recursion_guard_(b, l, "PreprocessorDirective_1")) return false;
boolean r;
r = consumeToken(b, DATA_DIRECTIVE);
if (!r) r = consumeToken(b, OTHER_DIRECTIVE);
return r;
}
// PreprocessorOperands?
private static boolean PreprocessorDirective_2(PsiBuilder b, int l) {
if (!recursion_guard_(b, l, "PreprocessorDirective_2")) return false;
PreprocessorOperands(b, l + 1); PreprocessorOperands(b, l + 1);
return true; return true;
} }
/* ********************************************************** */
// DATA_DIRECTIVE | OTHER_DIRECTIVE
public static boolean PreprocessorKeyword(PsiBuilder b, int l) {
if (!recursion_guard_(b, l, "PreprocessorKeyword")) return false;
if (!nextTokenIs(b, "<preprocessor keyword>", DATA_DIRECTIVE, OTHER_DIRECTIVE)) return false;
boolean r;
Marker m = enter_section_(b, l, _NONE_, PREPROCESSOR_KEYWORD, "<preprocessor keyword>");
r = consumeToken(b, DATA_DIRECTIVE);
if (!r) r = consumeToken(b, OTHER_DIRECTIVE);
exit_section_(b, l, m, r, false, null);
return r;
}
/* ********************************************************** */ /* ********************************************************** */
// expr // expr
static boolean PreprocessorOperand(PsiBuilder b, int l) { static boolean PreprocessorOperand(PsiBuilder b, int l) {
@@ -829,7 +950,7 @@ public class M68kParser implements PsiParser, LightPsiParser {
} }
/* ********************************************************** */ /* ********************************************************** */
// ROUND_L (expr SEPARATOR)? PC SEPARATOR DataOrAddressRegister DataWidth? ROUND_R // ROUND_L (expr SEPARATOR)? PC SEPARATOR IndexRegister ROUND_R
public static boolean ProgramCounterIndirectWithIndexNewAddressingMode(PsiBuilder b, int l) { public static boolean ProgramCounterIndirectWithIndexNewAddressingMode(PsiBuilder b, int l) {
if (!recursion_guard_(b, l, "ProgramCounterIndirectWithIndexNewAddressingMode")) return false; if (!recursion_guard_(b, l, "ProgramCounterIndirectWithIndexNewAddressingMode")) return false;
if (!nextTokenIsFast(b, ROUND_L)) return false; if (!nextTokenIsFast(b, ROUND_L)) return false;
@@ -838,8 +959,7 @@ public class M68kParser implements PsiParser, LightPsiParser {
r = consumeTokenFast(b, ROUND_L); r = consumeTokenFast(b, ROUND_L);
r = r && ProgramCounterIndirectWithIndexNewAddressingMode_1(b, l + 1); r = r && ProgramCounterIndirectWithIndexNewAddressingMode_1(b, l + 1);
r = r && consumeTokens(b, 0, PC, SEPARATOR); r = r && consumeTokens(b, 0, PC, SEPARATOR);
r = r && DataOrAddressRegister(b, l + 1); r = r && IndexRegister(b, l + 1);
r = r && ProgramCounterIndirectWithIndexNewAddressingMode_5(b, l + 1);
r = r && consumeToken(b, ROUND_R); r = r && consumeToken(b, ROUND_R);
exit_section_(b, l, m, r, false, null); exit_section_(b, l, m, r, false, null);
return r; return r;
@@ -863,23 +983,15 @@ public class M68kParser implements PsiParser, LightPsiParser {
return r; return r;
} }
// DataWidth?
private static boolean ProgramCounterIndirectWithIndexNewAddressingMode_5(PsiBuilder b, int l) {
if (!recursion_guard_(b, l, "ProgramCounterIndirectWithIndexNewAddressingMode_5")) return false;
DataWidth(b, l + 1);
return true;
}
/* ********************************************************** */ /* ********************************************************** */
// expr? ROUND_L PC SEPARATOR DataOrAddressRegister DataWidth? ROUND_R // expr? ROUND_L PC SEPARATOR IndexRegister ROUND_R
public static boolean ProgramCounterIndirectWithIndexOldAddressingMode(PsiBuilder b, int l) { public static boolean ProgramCounterIndirectWithIndexOldAddressingMode(PsiBuilder b, int l) {
if (!recursion_guard_(b, l, "ProgramCounterIndirectWithIndexOldAddressingMode")) return false; if (!recursion_guard_(b, l, "ProgramCounterIndirectWithIndexOldAddressingMode")) return false;
boolean r; boolean r;
Marker m = enter_section_(b, l, _NONE_, PROGRAM_COUNTER_INDIRECT_WITH_INDEX_OLD_ADDRESSING_MODE, "<AddressingMode>"); Marker m = enter_section_(b, l, _NONE_, PROGRAM_COUNTER_INDIRECT_WITH_INDEX_OLD_ADDRESSING_MODE, "<AddressingMode>");
r = ProgramCounterIndirectWithIndexOldAddressingMode_0(b, l + 1); r = ProgramCounterIndirectWithIndexOldAddressingMode_0(b, l + 1);
r = r && consumeTokens(b, 0, ROUND_L, PC, SEPARATOR); r = r && consumeTokens(b, 0, ROUND_L, PC, SEPARATOR);
r = r && DataOrAddressRegister(b, l + 1); r = r && IndexRegister(b, l + 1);
r = r && ProgramCounterIndirectWithIndexOldAddressingMode_5(b, l + 1);
r = r && consumeToken(b, ROUND_R); r = r && consumeToken(b, ROUND_R);
exit_section_(b, l, m, r, false, null); exit_section_(b, l, m, r, false, null);
return r; return r;
@@ -892,13 +1004,6 @@ public class M68kParser implements PsiParser, LightPsiParser {
return true; return true;
} }
// DataWidth?
private static boolean ProgramCounterIndirectWithIndexOldAddressingMode_5(PsiBuilder b, int l) {
if (!recursion_guard_(b, l, "ProgramCounterIndirectWithIndexOldAddressingMode_5")) return false;
DataWidth(b, l + 1);
return true;
}
/* ********************************************************** */ /* ********************************************************** */
// CURRENT_PC_SYMBOL // CURRENT_PC_SYMBOL
public static boolean ProgramCounterReference(PsiBuilder b, int l) { public static boolean ProgramCounterReference(PsiBuilder b, int l) {
@@ -925,27 +1030,27 @@ public class M68kParser implements PsiParser, LightPsiParser {
} }
/* ********************************************************** */ /* ********************************************************** */
// (DataOrAddressRegister|RegisterRange) ((OP_AR_DIV|OP_MINUS) (DataOrAddressRegister|RegisterRange))* // (RegisterRange|DataOrAddressRegister) (OP_AR_DIV (RegisterRange|DataOrAddressRegister))*
public static boolean RegisterListAddressingMode(PsiBuilder b, int l) { public static boolean RegisterListAddressingMode(PsiBuilder b, int l) {
if (!recursion_guard_(b, l, "RegisterListAddressingMode")) return false; if (!recursion_guard_(b, l, "RegisterListAddressingMode")) return false;
boolean r; boolean r;
Marker m = enter_section_(b, l, _NONE_, REGISTER_LIST_ADDRESSING_MODE, "<AddressingMode>"); Marker m = enter_section_(b, l, _NONE_, REGISTER_LIST_ADDRESSING_MODE, "<register list>");
r = RegisterListAddressingMode_0(b, l + 1); r = RegisterListAddressingMode_0(b, l + 1);
r = r && RegisterListAddressingMode_1(b, l + 1); r = r && RegisterListAddressingMode_1(b, l + 1);
exit_section_(b, l, m, r, false, null); exit_section_(b, l, m, r, false, null);
return r; return r;
} }
// DataOrAddressRegister|RegisterRange // RegisterRange|DataOrAddressRegister
private static boolean RegisterListAddressingMode_0(PsiBuilder b, int l) { private static boolean RegisterListAddressingMode_0(PsiBuilder b, int l) {
if (!recursion_guard_(b, l, "RegisterListAddressingMode_0")) return false; if (!recursion_guard_(b, l, "RegisterListAddressingMode_0")) return false;
boolean r; boolean r;
r = DataOrAddressRegister(b, l + 1); r = RegisterRange(b, l + 1);
if (!r) r = RegisterRange(b, l + 1); if (!r) r = DataOrAddressRegister(b, l + 1);
return r; return r;
} }
// ((OP_AR_DIV|OP_MINUS) (DataOrAddressRegister|RegisterRange))* // (OP_AR_DIV (RegisterRange|DataOrAddressRegister))*
private static boolean RegisterListAddressingMode_1(PsiBuilder b, int l) { private static boolean RegisterListAddressingMode_1(PsiBuilder b, int l) {
if (!recursion_guard_(b, l, "RegisterListAddressingMode_1")) return false; if (!recursion_guard_(b, l, "RegisterListAddressingMode_1")) return false;
while (true) { while (true) {
@@ -956,44 +1061,71 @@ public class M68kParser implements PsiParser, LightPsiParser {
return true; return true;
} }
// (OP_AR_DIV|OP_MINUS) (DataOrAddressRegister|RegisterRange) // OP_AR_DIV (RegisterRange|DataOrAddressRegister)
private static boolean RegisterListAddressingMode_1_0(PsiBuilder b, int l) { private static boolean RegisterListAddressingMode_1_0(PsiBuilder b, int l) {
if (!recursion_guard_(b, l, "RegisterListAddressingMode_1_0")) return false; if (!recursion_guard_(b, l, "RegisterListAddressingMode_1_0")) return false;
boolean r; boolean r;
Marker m = enter_section_(b); Marker m = enter_section_(b);
r = RegisterListAddressingMode_1_0_0(b, l + 1); r = consumeTokenFast(b, OP_AR_DIV);
r = r && RegisterListAddressingMode_1_0_1(b, l + 1); r = r && RegisterListAddressingMode_1_0_1(b, l + 1);
exit_section_(b, m, null, r); exit_section_(b, m, null, r);
return r; return r;
} }
// OP_AR_DIV|OP_MINUS // RegisterRange|DataOrAddressRegister
private static boolean RegisterListAddressingMode_1_0_0(PsiBuilder b, int l) {
if (!recursion_guard_(b, l, "RegisterListAddressingMode_1_0_0")) return false;
boolean r;
r = consumeTokenFast(b, OP_AR_DIV);
if (!r) r = consumeTokenFast(b, OP_MINUS);
return r;
}
// DataOrAddressRegister|RegisterRange
private static boolean RegisterListAddressingMode_1_0_1(PsiBuilder b, int l) { private static boolean RegisterListAddressingMode_1_0_1(PsiBuilder b, int l) {
if (!recursion_guard_(b, l, "RegisterListAddressingMode_1_0_1")) return false; if (!recursion_guard_(b, l, "RegisterListAddressingMode_1_0_1")) return false;
boolean r; boolean r;
r = DataOrAddressRegister(b, l + 1); r = RegisterRange(b, l + 1);
if (!r) r = RegisterRange(b, l + 1); if (!r) r = DataOrAddressRegister(b, l + 1);
return r; return r;
} }
/* ********************************************************** */ /* ********************************************************** */
// DataOrAddressRegister OP_MINUS DataOrAddressRegister // (DataRegister OP_MINUS DataRegister) | (AddressRegister OP_MINUS AddressRegister) | (DataRegister OP_MINUS AddressRegister)
static boolean RegisterRange(PsiBuilder b, int l) { public static boolean RegisterRange(PsiBuilder b, int l) {
if (!recursion_guard_(b, l, "RegisterRange")) return false; if (!recursion_guard_(b, l, "RegisterRange")) return false;
boolean r; boolean r;
Marker m = enter_section_(b, l, _NONE_, REGISTER_RANGE, "<register range>");
r = RegisterRange_0(b, l + 1);
if (!r) r = RegisterRange_1(b, l + 1);
if (!r) r = RegisterRange_2(b, l + 1);
exit_section_(b, l, m, r, false, null);
return r;
}
// DataRegister OP_MINUS DataRegister
private static boolean RegisterRange_0(PsiBuilder b, int l) {
if (!recursion_guard_(b, l, "RegisterRange_0")) return false;
boolean r;
Marker m = enter_section_(b); Marker m = enter_section_(b);
r = DataOrAddressRegister(b, l + 1); r = DataRegister(b, l + 1);
r = r && consumeToken(b, OP_MINUS); r = r && consumeToken(b, OP_MINUS);
r = r && DataOrAddressRegister(b, l + 1); r = r && DataRegister(b, l + 1);
exit_section_(b, m, null, r);
return r;
}
// AddressRegister OP_MINUS AddressRegister
private static boolean RegisterRange_1(PsiBuilder b, int l) {
if (!recursion_guard_(b, l, "RegisterRange_1")) return false;
boolean r;
Marker m = enter_section_(b);
r = AddressRegister(b, l + 1);
r = r && consumeToken(b, OP_MINUS);
r = r && AddressRegister(b, l + 1);
exit_section_(b, m, null, r);
return r;
}
// DataRegister OP_MINUS AddressRegister
private static boolean RegisterRange_2(PsiBuilder b, int l) {
if (!recursion_guard_(b, l, "RegisterRange_2")) return false;
boolean r;
Marker m = enter_section_(b);
r = DataRegister(b, l + 1);
r = r && consumeToken(b, OP_MINUS);
r = r && AddressRegister(b, l + 1);
exit_section_(b, m, null, r); exit_section_(b, m, null, r);
return r; return r;
} }
@@ -1048,13 +1180,13 @@ public class M68kParser implements PsiParser, LightPsiParser {
} }
/* ********************************************************** */ /* ********************************************************** */
// !<<eof>> statement (<<eof>>|EOL) // !<<eof>> (MacroDefinition | statement) (<<eof>>|EOL)
static boolean line(PsiBuilder b, int l) { static boolean line(PsiBuilder b, int l) {
if (!recursion_guard_(b, l, "line")) return false; if (!recursion_guard_(b, l, "line")) return false;
boolean r; boolean r;
Marker m = enter_section_(b); Marker m = enter_section_(b);
r = line_0(b, l + 1); r = line_0(b, l + 1);
r = r && statement(b, l + 1); r = r && line_1(b, l + 1);
r = r && line_2(b, l + 1); r = r && line_2(b, l + 1);
exit_section_(b, m, null, r); exit_section_(b, m, null, r);
return r; return r;
@@ -1070,6 +1202,17 @@ public class M68kParser implements PsiParser, LightPsiParser {
return r; return r;
} }
// MacroDefinition | statement
private static boolean line_1(PsiBuilder b, int l) {
if (!recursion_guard_(b, l, "line_1")) return false;
boolean r;
Marker m = enter_section_(b);
r = MacroDefinition(b, l + 1);
if (!r) r = statement(b, l + 1);
exit_section_(b, m, null, r);
return r;
}
// <<eof>>|EOL // <<eof>>|EOL
private static boolean line_2(PsiBuilder b, int l) { private static boolean line_2(PsiBuilder b, int l) {
if (!recursion_guard_(b, l, "line_2")) return false; if (!recursion_guard_(b, l, "line_2")) return false;
@@ -1083,14 +1226,12 @@ public class M68kParser implements PsiParser, LightPsiParser {
/* ********************************************************** */ /* ********************************************************** */
// Assignment // Assignment
// | PreprocessorDirective
// | LabelInsts // | LabelInsts
public static boolean statement(PsiBuilder b, int l) { public static boolean statement(PsiBuilder b, int l) {
if (!recursion_guard_(b, l, "statement")) return false; if (!recursion_guard_(b, l, "statement")) return false;
boolean r; boolean r;
Marker m = enter_section_(b, l, _NONE_, STATEMENT, "<statement>"); Marker m = enter_section_(b, l, _NONE_, STATEMENT, "<statement>");
r = Assignment(b, l + 1); r = Assignment(b, l + 1);
if (!r) r = PreprocessorDirective(b, l + 1);
if (!r) r = LabelInsts(b, l + 1); if (!r) r = LabelInsts(b, l + 1);
exit_section_(b, l, m, r, false, M68kParser::statement_recover); exit_section_(b, l, m, r, false, M68kParser::statement_recover);
return r; return r;
@@ -1102,11 +1243,21 @@ public class M68kParser implements PsiParser, LightPsiParser {
if (!recursion_guard_(b, l, "statement_recover")) return false; if (!recursion_guard_(b, l, "statement_recover")) return false;
boolean r; boolean r;
Marker m = enter_section_(b, l, _NOT_); Marker m = enter_section_(b, l, _NOT_);
r = !consumeToken(b, EOL); r = !statement_recover_0(b, l + 1);
exit_section_(b, l, m, r, false, null); exit_section_(b, l, m, r, false, null);
return r; return r;
} }
// (EOL)
private static boolean statement_recover_0(PsiBuilder b, int l) {
if (!recursion_guard_(b, l, "statement_recover_0")) return false;
boolean r;
Marker m = enter_section_(b);
r = consumeTokenFast(b, EOL);
exit_section_(b, m, null, r);
return r;
}
/* ********************************************************** */ /* ********************************************************** */
// Expression root: expr // Expression root: expr
// Operator priority table: // Operator priority table:
@@ -3,7 +3,7 @@ package de.platon42.intellij.plugins.m68k.psi;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
public interface M68kAddressRegisterIndirectAddressingMode extends M68kAddressingMode { public interface M68kAddressRegisterIndirectAddressingMode extends M68kAddressingMode, M68kWithAddressRegisterIndirect {
@NotNull @NotNull
M68kAddressRegister getAddressRegister(); M68kAddressRegister getAddressRegister();
@@ -3,7 +3,7 @@ package de.platon42.intellij.plugins.m68k.psi;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
public interface M68kAddressRegisterIndirectPostIncAddressingMode extends M68kAddressingMode { public interface M68kAddressRegisterIndirectPostIncAddressingMode extends M68kAddressingMode, M68kWithAddressRegisterIndirect {
@NotNull @NotNull
M68kAddressRegister getAddressRegister(); M68kAddressRegister getAddressRegister();
@@ -3,7 +3,7 @@ package de.platon42.intellij.plugins.m68k.psi;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
public interface M68kAddressRegisterIndirectPreDecAddressingMode extends M68kAddressingMode { public interface M68kAddressRegisterIndirectPreDecAddressingMode extends M68kAddressingMode, M68kWithAddressRegisterIndirect {
@NotNull @NotNull
M68kAddressRegister getAddressRegister(); M68kAddressRegister getAddressRegister();
@@ -3,12 +3,12 @@ package de.platon42.intellij.plugins.m68k.psi;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
public interface M68kAddressRegisterIndirectWithDisplacementNewAddressingMode extends M68kAddressingMode { public interface M68kAddressRegisterIndirectWithDisplacementNewAddressingMode extends M68kAddressingMode, M68kWithAddressRegisterIndirect, M68kWithDisplacement {
@NotNull @NotNull
M68kAddressRegister getAddressRegister(); M68kAddressRegister getAddressRegister();
@NotNull @NotNull
M68kExpr getExpr(); M68kExpr getDisplacement();
} }
@@ -3,12 +3,12 @@ package de.platon42.intellij.plugins.m68k.psi;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
public interface M68kAddressRegisterIndirectWithDisplacementOldAddressingMode extends M68kAddressingMode { public interface M68kAddressRegisterIndirectWithDisplacementOldAddressingMode extends M68kAddressingMode, M68kWithAddressRegisterIndirect, M68kWithDisplacement {
@NotNull @NotNull
M68kAddressRegister getAddressRegister(); M68kAddressRegister getAddressRegister();
@NotNull @NotNull
M68kExpr getExpr(); M68kExpr getDisplacement();
} }
@@ -4,18 +4,15 @@ package de.platon42.intellij.plugins.m68k.psi;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
public interface M68kAddressRegisterIndirectWithIndexNewAddressingMode extends M68kAddressingMode { public interface M68kAddressRegisterIndirectWithIndexNewAddressingMode extends M68kAddressingMode, M68kWithAddressRegisterIndirect, M68kWithDisplacement, M68kWithIndexRegister {
@NotNull @NotNull
M68kAddressRegister getAddressRegister(); M68kAddressRegister getAddressRegister();
@Nullable
M68kDataWidth getDataWidth();
@NotNull @NotNull
M68kRegister getRegister(); M68kIndexRegister getIndexRegister();
@Nullable @Nullable
M68kExpr getExpr(); M68kExpr getDisplacement();
} }
@@ -4,18 +4,15 @@ package de.platon42.intellij.plugins.m68k.psi;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
public interface M68kAddressRegisterIndirectWithIndexOldAddressingMode extends M68kAddressingMode { public interface M68kAddressRegisterIndirectWithIndexOldAddressingMode extends M68kAddressingMode, M68kWithAddressRegisterIndirect, M68kWithDisplacement, M68kWithIndexRegister {
@NotNull @NotNull
M68kAddressRegister getAddressRegister(); M68kAddressRegister getAddressRegister();
@Nullable
M68kDataWidth getDataWidth();
@NotNull @NotNull
M68kRegister getRegister(); M68kIndexRegister getIndexRegister();
@Nullable @Nullable
M68kExpr getExpr(); M68kExpr getDisplacement();
} }
@@ -1,6 +1,7 @@
// This is a generated file. Not intended for manual editing. // This is a generated file. Not intended for manual editing.
package de.platon42.intellij.plugins.m68k.psi; package de.platon42.intellij.plugins.m68k.psi;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
public interface M68kAsmOp extends M68kPsiElement { public interface M68kAsmOp extends M68kPsiElement {
@@ -8,4 +9,9 @@ public interface M68kAsmOp extends M68kPsiElement {
@Nullable @Nullable
M68kOperandSize getOperandSize(); M68kOperandSize getOperandSize();
@NotNull
String getMnemonic();
int getOpSize();
} }
@@ -0,0 +1,17 @@
// This is a generated file. Not intended for manual editing.
package de.platon42.intellij.plugins.m68k.psi;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public interface M68kIndexRegister extends M68kPsiElement {
@Nullable
M68kDataWidth getDataWidth();
@NotNull
M68kRegister getRegister();
boolean isLongWidth();
}
@@ -1,6 +1,19 @@
// This is a generated file. Not intended for manual editing. // This is a generated file. Not intended for manual editing.
package de.platon42.intellij.plugins.m68k.psi; package de.platon42.intellij.plugins.m68k.psi;
import org.jetbrains.annotations.NotNull;
import java.util.List;
public interface M68kMacroCall extends M68kPsiElement { public interface M68kMacroCall extends M68kPsiElement {
@NotNull
List<M68kAddressingMode> getAddressingModeList();
@NotNull
List<M68kExpr> getExprList();
@NotNull
String getMacroName();
} }
@@ -0,0 +1,29 @@
// This is a generated file. Not intended for manual editing.
package de.platon42.intellij.plugins.m68k.psi;
import com.intellij.psi.PsiElement;
import com.intellij.psi.StubBasedPsiElement;
import de.platon42.intellij.plugins.m68k.stubs.M68kMacroDefinitionStub;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
public interface M68kMacroDefinition extends M68kNamedElement, StubBasedPsiElement<M68kMacroDefinitionStub> {
@NotNull
M68kMacroNameDefinition getMacroNameDefinition();
@NotNull
List<M68kMacroPlainLine> getMacroPlainLineList();
@Nullable
String getName();
@NotNull
PsiElement setName(@NotNull String name);
@NotNull
PsiElement getNameIdentifier();
}
@@ -0,0 +1,6 @@
// This is a generated file. Not intended for manual editing.
package de.platon42.intellij.plugins.m68k.psi;
public interface M68kMacroNameDefinition extends M68kPsiElement {
}
@@ -0,0 +1,6 @@
// This is a generated file. Not intended for manual editing.
package de.platon42.intellij.plugins.m68k.psi;
public interface M68kMacroPlainLine extends M68kPsiElement {
}
@@ -3,4 +3,6 @@ package de.platon42.intellij.plugins.m68k.psi;
public interface M68kOperandSize extends M68kPsiElement { public interface M68kOperandSize extends M68kPsiElement {
int getSize();
} }
@@ -2,17 +2,13 @@
package de.platon42.intellij.plugins.m68k.psi; package de.platon42.intellij.plugins.m68k.psi;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List; import java.util.List;
public interface M68kPreprocessorDirective extends M68kPsiElement { public interface M68kPreprocessorDirective extends M68kPsiElement {
@Nullable @NotNull
M68kGlobalLabel getGlobalLabel(); M68kPreprocessorKeyword getPreprocessorKeyword();
@Nullable
M68kLocalLabel getLocalLabel();
@NotNull @NotNull
List<M68kExpr> getExprList(); List<M68kExpr> getExprList();
@@ -0,0 +1,6 @@
// This is a generated file. Not intended for manual editing.
package de.platon42.intellij.plugins.m68k.psi;
public interface M68kPreprocessorKeyword extends M68kPsiElement {
}
@@ -3,9 +3,9 @@ package de.platon42.intellij.plugins.m68k.psi;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
public interface M68kProgramCounterIndirectWithDisplacementNewAddressingMode extends M68kAddressingMode { public interface M68kProgramCounterIndirectWithDisplacementNewAddressingMode extends M68kAddressingMode, M68kWithDisplacement {
@NotNull @NotNull
M68kExpr getExpr(); M68kExpr getDisplacement();
} }
@@ -3,9 +3,9 @@ package de.platon42.intellij.plugins.m68k.psi;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
public interface M68kProgramCounterIndirectWithDisplacementOldAddressingMode extends M68kAddressingMode { public interface M68kProgramCounterIndirectWithDisplacementOldAddressingMode extends M68kAddressingMode, M68kWithDisplacement {
@Nullable @Nullable
M68kExpr getExpr(); M68kExpr getDisplacement();
} }
@@ -4,15 +4,12 @@ package de.platon42.intellij.plugins.m68k.psi;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
public interface M68kProgramCounterIndirectWithIndexNewAddressingMode extends M68kAddressingMode { public interface M68kProgramCounterIndirectWithIndexNewAddressingMode extends M68kAddressingMode, M68kWithDisplacement, M68kWithIndexRegister {
@Nullable
M68kDataWidth getDataWidth();
@NotNull @NotNull
M68kRegister getRegister(); M68kIndexRegister getIndexRegister();
@Nullable @Nullable
M68kExpr getExpr(); M68kExpr getDisplacement();
} }
@@ -4,15 +4,12 @@ package de.platon42.intellij.plugins.m68k.psi;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
public interface M68kProgramCounterIndirectWithIndexOldAddressingMode extends M68kAddressingMode { public interface M68kProgramCounterIndirectWithIndexOldAddressingMode extends M68kAddressingMode, M68kWithDisplacement, M68kWithIndexRegister {
@Nullable
M68kDataWidth getDataWidth();
@NotNull @NotNull
M68kRegister getRegister(); M68kIndexRegister getIndexRegister();
@Nullable @Nullable
M68kExpr getExpr(); M68kExpr getDisplacement();
} }
@@ -1,13 +1,21 @@
// This is a generated file. Not intended for manual editing. // This is a generated file. Not intended for manual editing.
package de.platon42.intellij.plugins.m68k.psi; package de.platon42.intellij.plugins.m68k.psi;
import de.platon42.intellij.plugins.m68k.asm.Register;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.util.List; import java.util.List;
import java.util.Set;
public interface M68kRegisterListAddressingMode extends M68kAddressingMode { public interface M68kRegisterListAddressingMode extends M68kAddressingMode {
@NotNull @NotNull
List<M68kRegister> getRegisterList(); List<M68kRegister> getRegisterList();
@NotNull
List<M68kRegisterRange> getRegisterRangeList();
@NotNull
Set<Register> getRegisters();
} }
@@ -0,0 +1,20 @@
// This is a generated file. Not intended for manual editing.
package de.platon42.intellij.plugins.m68k.psi;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
public interface M68kRegisterRange extends M68kPsiElement {
@NotNull
List<M68kRegister> getRegisterList();
@NotNull
M68kRegister getStartRegister();
@Nullable
M68kRegister getEndRegister();
}
@@ -48,12 +48,17 @@ public interface M68kTypes {
IElementType EXPR = new M68kElementType("EXPR"); IElementType EXPR = new M68kElementType("EXPR");
IElementType GLOBAL_LABEL = M68kStubElementTypeFactory.stubFactory("GLOBAL_LABEL"); IElementType GLOBAL_LABEL = M68kStubElementTypeFactory.stubFactory("GLOBAL_LABEL");
IElementType IMMEDIATE_DATA = new M68kElementType("IMMEDIATE_DATA"); IElementType IMMEDIATE_DATA = new M68kElementType("IMMEDIATE_DATA");
IElementType INDEX_REGISTER = new M68kElementType("INDEX_REGISTER");
IElementType LITERAL_EXPR = new M68kElementType("LITERAL_EXPR"); IElementType LITERAL_EXPR = new M68kElementType("LITERAL_EXPR");
IElementType LOCAL_LABEL = new M68kElementType("LOCAL_LABEL"); IElementType LOCAL_LABEL = new M68kElementType("LOCAL_LABEL");
IElementType MACRO_CALL = new M68kElementType("MACRO_CALL"); IElementType MACRO_CALL = new M68kElementType("MACRO_CALL");
IElementType MACRO_DEFINITION = M68kStubElementTypeFactory.stubFactory("MACRO_DEFINITION");
IElementType MACRO_NAME_DEFINITION = new M68kElementType("MACRO_NAME_DEFINITION");
IElementType MACRO_PLAIN_LINE = new M68kElementType("MACRO_PLAIN_LINE");
IElementType OPERAND_SIZE = new M68kElementType("OPERAND_SIZE"); IElementType OPERAND_SIZE = new M68kElementType("OPERAND_SIZE");
IElementType PAREN_EXPR = new M68kElementType("PAREN_EXPR"); IElementType PAREN_EXPR = new M68kElementType("PAREN_EXPR");
IElementType PREPROCESSOR_DIRECTIVE = new M68kElementType("PREPROCESSOR_DIRECTIVE"); IElementType PREPROCESSOR_DIRECTIVE = new M68kElementType("PREPROCESSOR_DIRECTIVE");
IElementType PREPROCESSOR_KEYWORD = new M68kElementType("PREPROCESSOR_KEYWORD");
IElementType PROGRAM_COUNTER_INDIRECT_WITH_DISPLACEMENT_NEW_ADDRESSING_MODE = new M68kElementType("PROGRAM_COUNTER_INDIRECT_WITH_DISPLACEMENT_NEW_ADDRESSING_MODE"); IElementType PROGRAM_COUNTER_INDIRECT_WITH_DISPLACEMENT_NEW_ADDRESSING_MODE = new M68kElementType("PROGRAM_COUNTER_INDIRECT_WITH_DISPLACEMENT_NEW_ADDRESSING_MODE");
IElementType PROGRAM_COUNTER_INDIRECT_WITH_DISPLACEMENT_OLD_ADDRESSING_MODE = new M68kElementType("PROGRAM_COUNTER_INDIRECT_WITH_DISPLACEMENT_OLD_ADDRESSING_MODE"); IElementType PROGRAM_COUNTER_INDIRECT_WITH_DISPLACEMENT_OLD_ADDRESSING_MODE = new M68kElementType("PROGRAM_COUNTER_INDIRECT_WITH_DISPLACEMENT_OLD_ADDRESSING_MODE");
IElementType PROGRAM_COUNTER_INDIRECT_WITH_INDEX_NEW_ADDRESSING_MODE = new M68kElementType("PROGRAM_COUNTER_INDIRECT_WITH_INDEX_NEW_ADDRESSING_MODE"); IElementType PROGRAM_COUNTER_INDIRECT_WITH_INDEX_NEW_ADDRESSING_MODE = new M68kElementType("PROGRAM_COUNTER_INDIRECT_WITH_INDEX_NEW_ADDRESSING_MODE");
@@ -62,6 +67,7 @@ public interface M68kTypes {
IElementType REF_EXPR = new M68kElementType("REF_EXPR"); IElementType REF_EXPR = new M68kElementType("REF_EXPR");
IElementType REGISTER = new M68kElementType("REGISTER"); IElementType REGISTER = new M68kElementType("REGISTER");
IElementType REGISTER_LIST_ADDRESSING_MODE = new M68kElementType("REGISTER_LIST_ADDRESSING_MODE"); IElementType REGISTER_LIST_ADDRESSING_MODE = new M68kElementType("REGISTER_LIST_ADDRESSING_MODE");
IElementType REGISTER_RANGE = new M68kElementType("REGISTER_RANGE");
IElementType SPECIAL_REGISTER = new M68kElementType("SPECIAL_REGISTER"); IElementType SPECIAL_REGISTER = new M68kElementType("SPECIAL_REGISTER");
IElementType SPECIAL_REGISTER_DIRECT_ADDRESSING_MODE = new M68kElementType("SPECIAL_REGISTER_DIRECT_ADDRESSING_MODE"); IElementType SPECIAL_REGISTER_DIRECT_ADDRESSING_MODE = new M68kElementType("SPECIAL_REGISTER_DIRECT_ADDRESSING_MODE");
IElementType STATEMENT = new M68kElementType("STATEMENT"); IElementType STATEMENT = new M68kElementType("STATEMENT");
@@ -86,7 +92,11 @@ public interface M68kTypes {
IElementType HASH = new M68kTokenType("HASH"); IElementType HASH = new M68kTokenType("HASH");
IElementType HEXADECIMAL = new M68kTokenType("HEXADECIMAL"); IElementType HEXADECIMAL = new M68kTokenType("HEXADECIMAL");
IElementType LOCAL_LABEL_DEF = new M68kTokenType("LOCAL_LABEL_DEF"); IElementType LOCAL_LABEL_DEF = new M68kTokenType("LOCAL_LABEL_DEF");
IElementType MACRO_INVOKATION = new M68kTokenType("MACRO_INVOKATION"); IElementType MACRO_END_TAG = new M68kTokenType("MACRO_END_TAG");
IElementType MACRO_INVOCATION = new M68kTokenType("MACRO_INVOCATION");
IElementType MACRO_LINE = new M68kTokenType("MACRO_LINE");
IElementType MACRO_NAME = new M68kTokenType("MACRO_NAME");
IElementType MACRO_TAG = new M68kTokenType("MACRO_TAG");
IElementType MNEMONIC = new M68kTokenType("MNEMONIC"); IElementType MNEMONIC = new M68kTokenType("MNEMONIC");
IElementType OCTAL = new M68kTokenType("OCTAL"); IElementType OCTAL = new M68kTokenType("OCTAL");
IElementType OPSIZE_BS = new M68kTokenType("OPSIZE_BS"); IElementType OPSIZE_BS = new M68kTokenType("OPSIZE_BS");
@@ -204,18 +214,28 @@ public interface M68kTypes {
return new M68kGlobalLabelImpl(node); return new M68kGlobalLabelImpl(node);
} else if (type == IMMEDIATE_DATA) { } else if (type == IMMEDIATE_DATA) {
return new M68kImmediateDataImpl(node); return new M68kImmediateDataImpl(node);
} else if (type == INDEX_REGISTER) {
return new M68kIndexRegisterImpl(node);
} else if (type == LITERAL_EXPR) { } else if (type == LITERAL_EXPR) {
return new M68kLiteralExprImpl(node); return new M68kLiteralExprImpl(node);
} else if (type == LOCAL_LABEL) { } else if (type == LOCAL_LABEL) {
return new M68kLocalLabelImpl(node); return new M68kLocalLabelImpl(node);
} else if (type == MACRO_CALL) { } else if (type == MACRO_CALL) {
return new M68kMacroCallImpl(node); return new M68kMacroCallImpl(node);
} else if (type == MACRO_DEFINITION) {
return new M68kMacroDefinitionImpl(node);
} else if (type == MACRO_NAME_DEFINITION) {
return new M68kMacroNameDefinitionImpl(node);
} else if (type == MACRO_PLAIN_LINE) {
return new M68kMacroPlainLineImpl(node);
} else if (type == OPERAND_SIZE) { } else if (type == OPERAND_SIZE) {
return new M68kOperandSizeImpl(node); return new M68kOperandSizeImpl(node);
} else if (type == PAREN_EXPR) { } else if (type == PAREN_EXPR) {
return new M68kParenExprImpl(node); return new M68kParenExprImpl(node);
} else if (type == PREPROCESSOR_DIRECTIVE) { } else if (type == PREPROCESSOR_DIRECTIVE) {
return new M68kPreprocessorDirectiveImpl(node); return new M68kPreprocessorDirectiveImpl(node);
} else if (type == PREPROCESSOR_KEYWORD) {
return new M68kPreprocessorKeywordImpl(node);
} else if (type == PROGRAM_COUNTER_INDIRECT_WITH_DISPLACEMENT_NEW_ADDRESSING_MODE) { } else if (type == PROGRAM_COUNTER_INDIRECT_WITH_DISPLACEMENT_NEW_ADDRESSING_MODE) {
return new M68kProgramCounterIndirectWithDisplacementNewAddressingModeImpl(node); return new M68kProgramCounterIndirectWithDisplacementNewAddressingModeImpl(node);
} else if (type == PROGRAM_COUNTER_INDIRECT_WITH_DISPLACEMENT_OLD_ADDRESSING_MODE) { } else if (type == PROGRAM_COUNTER_INDIRECT_WITH_DISPLACEMENT_OLD_ADDRESSING_MODE) {
@@ -230,6 +250,8 @@ public interface M68kTypes {
return new M68kRefExprImpl(node); return new M68kRefExprImpl(node);
} else if (type == REGISTER_LIST_ADDRESSING_MODE) { } else if (type == REGISTER_LIST_ADDRESSING_MODE) {
return new M68kRegisterListAddressingModeImpl(node); return new M68kRegisterListAddressingModeImpl(node);
} else if (type == REGISTER_RANGE) {
return new M68kRegisterRangeImpl(node);
} else if (type == SPECIAL_REGISTER) { } else if (type == SPECIAL_REGISTER) {
return new M68kSpecialRegisterImpl(node); return new M68kSpecialRegisterImpl(node);
} else if (type == SPECIAL_REGISTER_DIRECT_ADDRESSING_MODE) { } else if (type == SPECIAL_REGISTER_DIRECT_ADDRESSING_MODE) {
@@ -20,30 +20,43 @@ public class M68kVisitor extends PsiElementVisitor {
public void visitAddressRegisterIndirectAddressingMode(@NotNull M68kAddressRegisterIndirectAddressingMode o) { public void visitAddressRegisterIndirectAddressingMode(@NotNull M68kAddressRegisterIndirectAddressingMode o) {
visitAddressingMode(o); visitAddressingMode(o);
// visitWithAddressRegisterIndirect(o);
} }
public void visitAddressRegisterIndirectPostIncAddressingMode(@NotNull M68kAddressRegisterIndirectPostIncAddressingMode o) { public void visitAddressRegisterIndirectPostIncAddressingMode(@NotNull M68kAddressRegisterIndirectPostIncAddressingMode o) {
visitAddressingMode(o); visitAddressingMode(o);
// visitWithAddressRegisterIndirect(o);
} }
public void visitAddressRegisterIndirectPreDecAddressingMode(@NotNull M68kAddressRegisterIndirectPreDecAddressingMode o) { public void visitAddressRegisterIndirectPreDecAddressingMode(@NotNull M68kAddressRegisterIndirectPreDecAddressingMode o) {
visitAddressingMode(o); visitAddressingMode(o);
// visitWithAddressRegisterIndirect(o);
} }
public void visitAddressRegisterIndirectWithDisplacementNewAddressingMode(@NotNull M68kAddressRegisterIndirectWithDisplacementNewAddressingMode o) { public void visitAddressRegisterIndirectWithDisplacementNewAddressingMode(@NotNull M68kAddressRegisterIndirectWithDisplacementNewAddressingMode o) {
visitAddressingMode(o); visitAddressingMode(o);
// visitWithAddressRegisterIndirect(o);
// visitWithDisplacement(o);
} }
public void visitAddressRegisterIndirectWithDisplacementOldAddressingMode(@NotNull M68kAddressRegisterIndirectWithDisplacementOldAddressingMode o) { public void visitAddressRegisterIndirectWithDisplacementOldAddressingMode(@NotNull M68kAddressRegisterIndirectWithDisplacementOldAddressingMode o) {
visitAddressingMode(o); visitAddressingMode(o);
// visitWithAddressRegisterIndirect(o);
// visitWithDisplacement(o);
} }
public void visitAddressRegisterIndirectWithIndexNewAddressingMode(@NotNull M68kAddressRegisterIndirectWithIndexNewAddressingMode o) { public void visitAddressRegisterIndirectWithIndexNewAddressingMode(@NotNull M68kAddressRegisterIndirectWithIndexNewAddressingMode o) {
visitAddressingMode(o); visitAddressingMode(o);
// visitWithAddressRegisterIndirect(o);
// visitWithDisplacement(o);
// visitWithIndexRegister(o);
} }
public void visitAddressRegisterIndirectWithIndexOldAddressingMode(@NotNull M68kAddressRegisterIndirectWithIndexOldAddressingMode o) { public void visitAddressRegisterIndirectWithIndexOldAddressingMode(@NotNull M68kAddressRegisterIndirectWithIndexOldAddressingMode o) {
visitAddressingMode(o); visitAddressingMode(o);
// visitWithAddressRegisterIndirect(o);
// visitWithDisplacement(o);
// visitWithIndexRegister(o);
} }
public void visitAddressSize(@NotNull M68kAddressSize o) { public void visitAddressSize(@NotNull M68kAddressSize o) {
@@ -86,6 +99,10 @@ public class M68kVisitor extends PsiElementVisitor {
visitAddressingMode(o); visitAddressingMode(o);
} }
public void visitIndexRegister(@NotNull M68kIndexRegister o) {
visitPsiElement(o);
}
public void visitLocalLabel(@NotNull M68kLocalLabel o) { public void visitLocalLabel(@NotNull M68kLocalLabel o) {
visitNamedElement(o); visitNamedElement(o);
} }
@@ -94,6 +111,18 @@ public class M68kVisitor extends PsiElementVisitor {
visitPsiElement(o); visitPsiElement(o);
} }
public void visitMacroDefinition(@NotNull M68kMacroDefinition o) {
visitNamedElement(o);
}
public void visitMacroNameDefinition(@NotNull M68kMacroNameDefinition o) {
visitPsiElement(o);
}
public void visitMacroPlainLine(@NotNull M68kMacroPlainLine o) {
visitPsiElement(o);
}
public void visitOperandSize(@NotNull M68kOperandSize o) { public void visitOperandSize(@NotNull M68kOperandSize o) {
visitPsiElement(o); visitPsiElement(o);
} }
@@ -102,20 +131,30 @@ public class M68kVisitor extends PsiElementVisitor {
visitPsiElement(o); visitPsiElement(o);
} }
public void visitPreprocessorKeyword(@NotNull M68kPreprocessorKeyword o) {
visitPsiElement(o);
}
public void visitProgramCounterIndirectWithDisplacementNewAddressingMode(@NotNull M68kProgramCounterIndirectWithDisplacementNewAddressingMode o) { public void visitProgramCounterIndirectWithDisplacementNewAddressingMode(@NotNull M68kProgramCounterIndirectWithDisplacementNewAddressingMode o) {
visitAddressingMode(o); visitAddressingMode(o);
// visitWithDisplacement(o);
} }
public void visitProgramCounterIndirectWithDisplacementOldAddressingMode(@NotNull M68kProgramCounterIndirectWithDisplacementOldAddressingMode o) { public void visitProgramCounterIndirectWithDisplacementOldAddressingMode(@NotNull M68kProgramCounterIndirectWithDisplacementOldAddressingMode o) {
visitAddressingMode(o); visitAddressingMode(o);
// visitWithDisplacement(o);
} }
public void visitProgramCounterIndirectWithIndexNewAddressingMode(@NotNull M68kProgramCounterIndirectWithIndexNewAddressingMode o) { public void visitProgramCounterIndirectWithIndexNewAddressingMode(@NotNull M68kProgramCounterIndirectWithIndexNewAddressingMode o) {
visitAddressingMode(o); visitAddressingMode(o);
// visitWithDisplacement(o);
// visitWithIndexRegister(o);
} }
public void visitProgramCounterIndirectWithIndexOldAddressingMode(@NotNull M68kProgramCounterIndirectWithIndexOldAddressingMode o) { public void visitProgramCounterIndirectWithIndexOldAddressingMode(@NotNull M68kProgramCounterIndirectWithIndexOldAddressingMode o) {
visitAddressingMode(o); visitAddressingMode(o);
// visitWithDisplacement(o);
// visitWithIndexRegister(o);
} }
public void visitProgramCounterReference(@NotNull M68kProgramCounterReference o) { public void visitProgramCounterReference(@NotNull M68kProgramCounterReference o) {
@@ -130,6 +169,10 @@ public class M68kVisitor extends PsiElementVisitor {
visitAddressingMode(o); visitAddressingMode(o);
} }
public void visitRegisterRange(@NotNull M68kRegisterRange o) {
visitPsiElement(o);
}
public void visitSpecialRegister(@NotNull M68kSpecialRegister o) { public void visitSpecialRegister(@NotNull M68kSpecialRegister o) {
visitRegister(o); visitRegister(o);
} }
@@ -35,7 +35,7 @@ public class M68kAddressRegisterIndirectWithDisplacementNewAddressingModeImpl ex
@Override @Override
@NotNull @NotNull
public M68kExpr getExpr() { public M68kExpr getDisplacement() {
return notNullChild(PsiTreeUtil.getChildOfType(this, M68kExpr.class)); return notNullChild(PsiTreeUtil.getChildOfType(this, M68kExpr.class));
} }
@@ -35,7 +35,7 @@ public class M68kAddressRegisterIndirectWithDisplacementOldAddressingModeImpl ex
@Override @Override
@NotNull @NotNull
public M68kExpr getExpr() { public M68kExpr getDisplacement() {
return notNullChild(PsiTreeUtil.getChildOfType(this, M68kExpr.class)); return notNullChild(PsiTreeUtil.getChildOfType(this, M68kExpr.class));
} }
@@ -31,21 +31,15 @@ public class M68kAddressRegisterIndirectWithIndexNewAddressingModeImpl extends M
return notNullChild(PsiTreeUtil.getChildOfType(this, M68kAddressRegister.class)); return notNullChild(PsiTreeUtil.getChildOfType(this, M68kAddressRegister.class));
} }
@Override
@Nullable
public M68kDataWidth getDataWidth() {
return PsiTreeUtil.getChildOfType(this, M68kDataWidth.class);
}
@Override @Override
@NotNull @NotNull
public M68kRegister getRegister() { public M68kIndexRegister getIndexRegister() {
return notNullChild(PsiTreeUtil.getChildOfType(this, M68kRegister.class)); return notNullChild(PsiTreeUtil.getChildOfType(this, M68kIndexRegister.class));
} }
@Override @Override
@Nullable @Nullable
public M68kExpr getExpr() { public M68kExpr getDisplacement() {
return PsiTreeUtil.getChildOfType(this, M68kExpr.class); return PsiTreeUtil.getChildOfType(this, M68kExpr.class);
} }
@@ -31,21 +31,15 @@ public class M68kAddressRegisterIndirectWithIndexOldAddressingModeImpl extends M
return notNullChild(PsiTreeUtil.getChildOfType(this, M68kAddressRegister.class)); return notNullChild(PsiTreeUtil.getChildOfType(this, M68kAddressRegister.class));
} }
@Override
@Nullable
public M68kDataWidth getDataWidth() {
return PsiTreeUtil.getChildOfType(this, M68kDataWidth.class);
}
@Override @Override
@NotNull @NotNull
public M68kRegister getRegister() { public M68kIndexRegister getIndexRegister() {
return notNullChild(PsiTreeUtil.getChildOfType(this, M68kRegister.class)); return notNullChild(PsiTreeUtil.getChildOfType(this, M68kIndexRegister.class));
} }
@Override @Override
@Nullable @Nullable
public M68kExpr getExpr() { public M68kExpr getDisplacement() {
return PsiTreeUtil.getChildOfType(this, M68kExpr.class); return PsiTreeUtil.getChildOfType(this, M68kExpr.class);
} }
@@ -7,6 +7,7 @@ import com.intellij.psi.PsiElementVisitor;
import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiTreeUtil;
import de.platon42.intellij.plugins.m68k.psi.M68kAsmOp; import de.platon42.intellij.plugins.m68k.psi.M68kAsmOp;
import de.platon42.intellij.plugins.m68k.psi.M68kOperandSize; import de.platon42.intellij.plugins.m68k.psi.M68kOperandSize;
import de.platon42.intellij.plugins.m68k.psi.M68kPsiImplUtil;
import de.platon42.intellij.plugins.m68k.psi.M68kVisitor; import de.platon42.intellij.plugins.m68k.psi.M68kVisitor;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
@@ -33,4 +34,15 @@ public class M68kAsmOpImpl extends ASTWrapperPsiElement implements M68kAsmOp {
return PsiTreeUtil.getChildOfType(this, M68kOperandSize.class); return PsiTreeUtil.getChildOfType(this, M68kOperandSize.class);
} }
@Override
@NotNull
public String getMnemonic() {
return M68kPsiImplUtil.getMnemonic(this);
}
@Override
public int getOpSize() {
return M68kPsiImplUtil.getOpSize(this);
}
} }
@@ -0,0 +1,45 @@
// This is a generated file. Not intended for manual editing.
package de.platon42.intellij.plugins.m68k.psi.impl;
import com.intellij.extapi.psi.ASTWrapperPsiElement;
import com.intellij.lang.ASTNode;
import com.intellij.psi.PsiElementVisitor;
import com.intellij.psi.util.PsiTreeUtil;
import de.platon42.intellij.plugins.m68k.psi.*;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class M68kIndexRegisterImpl extends ASTWrapperPsiElement implements M68kIndexRegister {
public M68kIndexRegisterImpl(@NotNull ASTNode node) {
super(node);
}
public void accept(@NotNull M68kVisitor visitor) {
visitor.visitIndexRegister(this);
}
@Override
public void accept(@NotNull PsiElementVisitor visitor) {
if (visitor instanceof M68kVisitor) accept((M68kVisitor) visitor);
else super.accept(visitor);
}
@Override
@Nullable
public M68kDataWidth getDataWidth() {
return PsiTreeUtil.getChildOfType(this, M68kDataWidth.class);
}
@Override
@NotNull
public M68kRegister getRegister() {
return notNullChild(PsiTreeUtil.getChildOfType(this, M68kRegister.class));
}
@Override
public boolean isLongWidth() {
return M68kPsiImplUtil.isLongWidth(this);
}
}
@@ -1,14 +1,15 @@
// This is a generated file. Not intended for manual editing. // This is a generated file. Not intended for manual editing.
package de.platon42.intellij.plugins.m68k.psi.impl; package de.platon42.intellij.plugins.m68k.psi.impl;
import com.intellij.extapi.psi.ASTWrapperPsiElement;
import com.intellij.lang.ASTNode; import com.intellij.lang.ASTNode;
import com.intellij.psi.PsiElementVisitor; import com.intellij.psi.PsiElementVisitor;
import de.platon42.intellij.plugins.m68k.psi.M68kMacroCall; import com.intellij.psi.util.PsiTreeUtil;
import de.platon42.intellij.plugins.m68k.psi.M68kVisitor; import de.platon42.intellij.plugins.m68k.psi.*;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
public class M68kMacroCallImpl extends ASTWrapperPsiElement implements M68kMacroCall { import java.util.List;
public class M68kMacroCallImpl extends M68kMacroCallMixin implements M68kMacroCall {
public M68kMacroCallImpl(@NotNull ASTNode node) { public M68kMacroCallImpl(@NotNull ASTNode node) {
super(node); super(node);
@@ -24,4 +25,22 @@ public class M68kMacroCallImpl extends ASTWrapperPsiElement implements M68kMacro
else super.accept(visitor); else super.accept(visitor);
} }
@Override
@NotNull
public List<M68kAddressingMode> getAddressingModeList() {
return PsiTreeUtil.getChildrenOfTypeAsList(this, M68kAddressingMode.class);
}
@Override
@NotNull
public List<M68kExpr> getExprList() {
return PsiTreeUtil.getChildrenOfTypeAsList(this, M68kExpr.class);
}
@Override
@NotNull
public String getMacroName() {
return M68kPsiImplUtil.getMacroName(this);
}
} }
@@ -0,0 +1,66 @@
// This is a generated file. Not intended for manual editing.
package de.platon42.intellij.plugins.m68k.psi.impl;
import com.intellij.lang.ASTNode;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiElementVisitor;
import com.intellij.psi.stubs.IStubElementType;
import com.intellij.psi.util.PsiTreeUtil;
import de.platon42.intellij.plugins.m68k.psi.*;
import de.platon42.intellij.plugins.m68k.stubs.M68kMacroDefinitionStub;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
public class M68kMacroDefinitionImpl extends M68kMacroDefinitionMixin implements M68kMacroDefinition {
public M68kMacroDefinitionImpl(@NotNull ASTNode node) {
super(node);
}
public M68kMacroDefinitionImpl(@NotNull M68kMacroDefinitionStub stub, @NotNull IStubElementType<?, ?> nodeType) {
super(stub, nodeType);
}
public void accept(@NotNull M68kVisitor visitor) {
visitor.visitMacroDefinition(this);
}
@Override
public void accept(@NotNull PsiElementVisitor visitor) {
if (visitor instanceof M68kVisitor) accept((M68kVisitor) visitor);
else super.accept(visitor);
}
@Override
@NotNull
public M68kMacroNameDefinition getMacroNameDefinition() {
return notNullChild(PsiTreeUtil.getChildOfType(this, M68kMacroNameDefinition.class));
}
@Override
@NotNull
public List<M68kMacroPlainLine> getMacroPlainLineList() {
return PsiTreeUtil.getChildrenOfTypeAsList(this, M68kMacroPlainLine.class);
}
@Override
@Nullable
public String getName() {
return M68kPsiImplUtil.getName(this);
}
@Override
@NotNull
public PsiElement setName(@NotNull String name) {
return M68kPsiImplUtil.setName(this, name);
}
@Override
@NotNull
public PsiElement getNameIdentifier() {
return M68kPsiImplUtil.getNameIdentifier(this);
}
}
@@ -0,0 +1,27 @@
// This is a generated file. Not intended for manual editing.
package de.platon42.intellij.plugins.m68k.psi.impl;
import com.intellij.extapi.psi.ASTWrapperPsiElement;
import com.intellij.lang.ASTNode;
import com.intellij.psi.PsiElementVisitor;
import de.platon42.intellij.plugins.m68k.psi.M68kMacroNameDefinition;
import de.platon42.intellij.plugins.m68k.psi.M68kVisitor;
import org.jetbrains.annotations.NotNull;
public class M68kMacroNameDefinitionImpl extends ASTWrapperPsiElement implements M68kMacroNameDefinition {
public M68kMacroNameDefinitionImpl(@NotNull ASTNode node) {
super(node);
}
public void accept(@NotNull M68kVisitor visitor) {
visitor.visitMacroNameDefinition(this);
}
@Override
public void accept(@NotNull PsiElementVisitor visitor) {
if (visitor instanceof M68kVisitor) accept((M68kVisitor) visitor);
else super.accept(visitor);
}
}
@@ -0,0 +1,27 @@
// This is a generated file. Not intended for manual editing.
package de.platon42.intellij.plugins.m68k.psi.impl;
import com.intellij.extapi.psi.ASTWrapperPsiElement;
import com.intellij.lang.ASTNode;
import com.intellij.psi.PsiElementVisitor;
import de.platon42.intellij.plugins.m68k.psi.M68kMacroPlainLine;
import de.platon42.intellij.plugins.m68k.psi.M68kVisitor;
import org.jetbrains.annotations.NotNull;
public class M68kMacroPlainLineImpl extends ASTWrapperPsiElement implements M68kMacroPlainLine {
public M68kMacroPlainLineImpl(@NotNull ASTNode node) {
super(node);
}
public void accept(@NotNull M68kVisitor visitor) {
visitor.visitMacroPlainLine(this);
}
@Override
public void accept(@NotNull PsiElementVisitor visitor) {
if (visitor instanceof M68kVisitor) accept((M68kVisitor) visitor);
else super.accept(visitor);
}
}
@@ -5,6 +5,7 @@ import com.intellij.extapi.psi.ASTWrapperPsiElement;
import com.intellij.lang.ASTNode; import com.intellij.lang.ASTNode;
import com.intellij.psi.PsiElementVisitor; import com.intellij.psi.PsiElementVisitor;
import de.platon42.intellij.plugins.m68k.psi.M68kOperandSize; import de.platon42.intellij.plugins.m68k.psi.M68kOperandSize;
import de.platon42.intellij.plugins.m68k.psi.M68kPsiImplUtil;
import de.platon42.intellij.plugins.m68k.psi.M68kVisitor; import de.platon42.intellij.plugins.m68k.psi.M68kVisitor;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@@ -24,4 +25,9 @@ public class M68kOperandSizeImpl extends ASTWrapperPsiElement implements M68kOpe
else super.accept(visitor); else super.accept(visitor);
} }
@Override
public int getSize() {
return M68kPsiImplUtil.getSize(this);
}
} }
@@ -1,17 +1,15 @@
// This is a generated file. Not intended for manual editing. // This is a generated file. Not intended for manual editing.
package de.platon42.intellij.plugins.m68k.psi.impl; package de.platon42.intellij.plugins.m68k.psi.impl;
import com.intellij.extapi.psi.ASTWrapperPsiElement;
import com.intellij.lang.ASTNode; import com.intellij.lang.ASTNode;
import com.intellij.psi.PsiElementVisitor; import com.intellij.psi.PsiElementVisitor;
import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiTreeUtil;
import de.platon42.intellij.plugins.m68k.psi.*; import de.platon42.intellij.plugins.m68k.psi.*;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List; import java.util.List;
public class M68kPreprocessorDirectiveImpl extends ASTWrapperPsiElement implements M68kPreprocessorDirective { public class M68kPreprocessorDirectiveImpl extends M68kPreprocessorDirectiveMixin implements M68kPreprocessorDirective {
public M68kPreprocessorDirectiveImpl(@NotNull ASTNode node) { public M68kPreprocessorDirectiveImpl(@NotNull ASTNode node) {
super(node); super(node);
@@ -28,15 +26,9 @@ public class M68kPreprocessorDirectiveImpl extends ASTWrapperPsiElement implemen
} }
@Override @Override
@Nullable @NotNull
public M68kGlobalLabel getGlobalLabel() { public M68kPreprocessorKeyword getPreprocessorKeyword() {
return PsiTreeUtil.getChildOfType(this, M68kGlobalLabel.class); return notNullChild(PsiTreeUtil.getChildOfType(this, M68kPreprocessorKeyword.class));
}
@Override
@Nullable
public M68kLocalLabel getLocalLabel() {
return PsiTreeUtil.getChildOfType(this, M68kLocalLabel.class);
} }
@Override @Override
@@ -0,0 +1,27 @@
// This is a generated file. Not intended for manual editing.
package de.platon42.intellij.plugins.m68k.psi.impl;
import com.intellij.extapi.psi.ASTWrapperPsiElement;
import com.intellij.lang.ASTNode;
import com.intellij.psi.PsiElementVisitor;
import de.platon42.intellij.plugins.m68k.psi.M68kPreprocessorKeyword;
import de.platon42.intellij.plugins.m68k.psi.M68kVisitor;
import org.jetbrains.annotations.NotNull;
public class M68kPreprocessorKeywordImpl extends ASTWrapperPsiElement implements M68kPreprocessorKeyword {
public M68kPreprocessorKeywordImpl(@NotNull ASTNode node) {
super(node);
}
public void accept(@NotNull M68kVisitor visitor) {
visitor.visitPreprocessorKeyword(this);
}
@Override
public void accept(@NotNull PsiElementVisitor visitor) {
if (visitor instanceof M68kVisitor) accept((M68kVisitor) visitor);
else super.accept(visitor);
}
}
@@ -28,7 +28,7 @@ public class M68kProgramCounterIndirectWithDisplacementNewAddressingModeImpl ext
@Override @Override
@NotNull @NotNull
public M68kExpr getExpr() { public M68kExpr getDisplacement() {
return notNullChild(PsiTreeUtil.getChildOfType(this, M68kExpr.class)); return notNullChild(PsiTreeUtil.getChildOfType(this, M68kExpr.class));
} }
@@ -29,7 +29,7 @@ public class M68kProgramCounterIndirectWithDisplacementOldAddressingModeImpl ext
@Override @Override
@Nullable @Nullable
public M68kExpr getExpr() { public M68kExpr getDisplacement() {
return PsiTreeUtil.getChildOfType(this, M68kExpr.class); return PsiTreeUtil.getChildOfType(this, M68kExpr.class);
} }
@@ -4,7 +4,10 @@ package de.platon42.intellij.plugins.m68k.psi.impl;
import com.intellij.lang.ASTNode; import com.intellij.lang.ASTNode;
import com.intellij.psi.PsiElementVisitor; import com.intellij.psi.PsiElementVisitor;
import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiTreeUtil;
import de.platon42.intellij.plugins.m68k.psi.*; import de.platon42.intellij.plugins.m68k.psi.M68kExpr;
import de.platon42.intellij.plugins.m68k.psi.M68kIndexRegister;
import de.platon42.intellij.plugins.m68k.psi.M68kProgramCounterIndirectWithIndexNewAddressingMode;
import de.platon42.intellij.plugins.m68k.psi.M68kVisitor;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
@@ -25,21 +28,15 @@ public class M68kProgramCounterIndirectWithIndexNewAddressingModeImpl extends M6
else super.accept(visitor); else super.accept(visitor);
} }
@Override
@Nullable
public M68kDataWidth getDataWidth() {
return PsiTreeUtil.getChildOfType(this, M68kDataWidth.class);
}
@Override @Override
@NotNull @NotNull
public M68kRegister getRegister() { public M68kIndexRegister getIndexRegister() {
return notNullChild(PsiTreeUtil.getChildOfType(this, M68kRegister.class)); return notNullChild(PsiTreeUtil.getChildOfType(this, M68kIndexRegister.class));
} }
@Override @Override
@Nullable @Nullable
public M68kExpr getExpr() { public M68kExpr getDisplacement() {
return PsiTreeUtil.getChildOfType(this, M68kExpr.class); return PsiTreeUtil.getChildOfType(this, M68kExpr.class);
} }
@@ -4,7 +4,10 @@ package de.platon42.intellij.plugins.m68k.psi.impl;
import com.intellij.lang.ASTNode; import com.intellij.lang.ASTNode;
import com.intellij.psi.PsiElementVisitor; import com.intellij.psi.PsiElementVisitor;
import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiTreeUtil;
import de.platon42.intellij.plugins.m68k.psi.*; import de.platon42.intellij.plugins.m68k.psi.M68kExpr;
import de.platon42.intellij.plugins.m68k.psi.M68kIndexRegister;
import de.platon42.intellij.plugins.m68k.psi.M68kProgramCounterIndirectWithIndexOldAddressingMode;
import de.platon42.intellij.plugins.m68k.psi.M68kVisitor;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
@@ -25,21 +28,15 @@ public class M68kProgramCounterIndirectWithIndexOldAddressingModeImpl extends M6
else super.accept(visitor); else super.accept(visitor);
} }
@Override
@Nullable
public M68kDataWidth getDataWidth() {
return PsiTreeUtil.getChildOfType(this, M68kDataWidth.class);
}
@Override @Override
@NotNull @NotNull
public M68kRegister getRegister() { public M68kIndexRegister getIndexRegister() {
return notNullChild(PsiTreeUtil.getChildOfType(this, M68kRegister.class)); return notNullChild(PsiTreeUtil.getChildOfType(this, M68kIndexRegister.class));
} }
@Override @Override
@Nullable @Nullable
public M68kExpr getExpr() { public M68kExpr getDisplacement() {
return PsiTreeUtil.getChildOfType(this, M68kExpr.class); return PsiTreeUtil.getChildOfType(this, M68kExpr.class);
} }
@@ -4,12 +4,12 @@ package de.platon42.intellij.plugins.m68k.psi.impl;
import com.intellij.lang.ASTNode; import com.intellij.lang.ASTNode;
import com.intellij.psi.PsiElementVisitor; import com.intellij.psi.PsiElementVisitor;
import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiTreeUtil;
import de.platon42.intellij.plugins.m68k.psi.M68kRegister; import de.platon42.intellij.plugins.m68k.asm.Register;
import de.platon42.intellij.plugins.m68k.psi.M68kRegisterListAddressingMode; import de.platon42.intellij.plugins.m68k.psi.*;
import de.platon42.intellij.plugins.m68k.psi.M68kVisitor;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.util.List; import java.util.List;
import java.util.Set;
public class M68kRegisterListAddressingModeImpl extends M68kAddressingModeImpl implements M68kRegisterListAddressingMode { public class M68kRegisterListAddressingModeImpl extends M68kAddressingModeImpl implements M68kRegisterListAddressingMode {
@@ -34,4 +34,16 @@ public class M68kRegisterListAddressingModeImpl extends M68kAddressingModeImpl i
return PsiTreeUtil.getChildrenOfTypeAsList(this, M68kRegister.class); return PsiTreeUtil.getChildrenOfTypeAsList(this, M68kRegister.class);
} }
@Override
@NotNull
public List<M68kRegisterRange> getRegisterRangeList() {
return PsiTreeUtil.getChildrenOfTypeAsList(this, M68kRegisterRange.class);
}
@Override
@NotNull
public Set<Register> getRegisters() {
return M68kPsiImplUtil.getRegisters(this);
}
} }
@@ -0,0 +1,52 @@
// This is a generated file. Not intended for manual editing.
package de.platon42.intellij.plugins.m68k.psi.impl;
import com.intellij.extapi.psi.ASTWrapperPsiElement;
import com.intellij.lang.ASTNode;
import com.intellij.psi.PsiElementVisitor;
import com.intellij.psi.util.PsiTreeUtil;
import de.platon42.intellij.plugins.m68k.psi.M68kRegister;
import de.platon42.intellij.plugins.m68k.psi.M68kRegisterRange;
import de.platon42.intellij.plugins.m68k.psi.M68kVisitor;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
public class M68kRegisterRangeImpl extends ASTWrapperPsiElement implements M68kRegisterRange {
public M68kRegisterRangeImpl(@NotNull ASTNode node) {
super(node);
}
public void accept(@NotNull M68kVisitor visitor) {
visitor.visitRegisterRange(this);
}
@Override
public void accept(@NotNull PsiElementVisitor visitor) {
if (visitor instanceof M68kVisitor) accept((M68kVisitor) visitor);
else super.accept(visitor);
}
@Override
@NotNull
public List<M68kRegister> getRegisterList() {
return PsiTreeUtil.getChildrenOfTypeAsList(this, M68kRegister.class);
}
@Override
@NotNull
public M68kRegister getStartRegister() {
List<M68kRegister> p1 = getRegisterList();
return p1.get(0);
}
@Override
@Nullable
public M68kRegister getEndRegister() {
List<M68kRegister> p1 = getRegisterList();
return p1.size() < 2 ? null : p1.get(1);
}
}
@@ -10,7 +10,7 @@ class M68kFileElementType private constructor() : ILightStubFileElementType<PsiF
@JvmField @JvmField
val INSTANCE = M68kFileElementType() val INSTANCE = M68kFileElementType()
const val STUB_VERSION = 3 const val STUB_VERSION = 6
const val STUB_EXTERNAL_ID_PREFIX = "MC68000." const val STUB_EXTERNAL_ID_PREFIX = "MC68000."
const val EXTERNAL_ID = STUB_EXTERNAL_ID_PREFIX + "FILE" const val EXTERNAL_ID = STUB_EXTERNAL_ID_PREFIX + "FILE"
} }
@@ -7,5 +7,8 @@ object M68kIcons {
val FILE = IconLoader.getIcon("/icons/FileType_m68k.svg", javaClass) val FILE = IconLoader.getIcon("/icons/FileType_m68k.svg", javaClass)
val LOCAL_LABEL = AllIcons.Nodes.AbstractMethod val LOCAL_LABEL = AllIcons.Nodes.AbstractMethod
val GLOBAL_LABEL = AllIcons.Nodes.Method val GLOBAL_LABEL = AllIcons.Nodes.Method
val SYMBOL_DEF = AllIcons.Nodes.Constant val SYMBOL_DEF = AllIcons.Nodes.ClassInitializer
val MACRO_DEF = AllIcons.Nodes.MultipleTypeDefinitions
val REGISTER = AllIcons.Nodes.DataTables // AllIcons.Nodes.Record only available starting from 2020.1
val MNEMONIC = AllIcons.Nodes.C_protected
} }
@@ -3,46 +3,62 @@ package de.platon42.intellij.plugins.m68k.asm
object AssemblerDirectives { object AssemblerDirectives {
val dataDirectives: Set<String> = setOf( val dataDirectives: Set<String> = setOf(
"section", "pushsection", "popsection", "section", "pushsection", "popsection",
"bss", "bss_c", "bss_f", "bss", "bss_c", "bss_f",
"data", "data_c", "data_f", "data", "data_c", "data_f",
"text", "cseg", "code", "code_c", "code_f", "text", "cseg", "code", "code_c", "code_f",
"offset", "offset",
"abs", "abs",
"db", "dw", "dl", "db", "dw", "dl",
"dr.b", "dr.w", "dr.l", "dr.b", "dr.w", "dr.l",
"dc", "dc.b", "dc.w", "dc.l", "dcb", "dcb.b", "dcb.w", "dcb.l", "dc", "dc.b", "dc.w", "dc.l", "dcb", "dcb.b", "dcb.w", "dcb.l",
"blk.b", "blk.w", "blk.l", "blk.b", "blk.w", "blk.l",
"ds", "ds.b", "ds.w", "ds.l", "ds", "ds.b", "ds.w", "ds.l",
"align", "even", "odd", "cnop", "long", "dphrase", "phrase", "qphrase", "align", "even", "odd", "cnop", "long", "dphrase", "phrase", "qphrase",
"cargs", "comm", "comment", "cargs", "comm", "comment",
"rsset", "clrfo", "clrso", "setfo", "setso" "rsset", "clrfo", "clrso", "setfo", "setso"
) )
val otherDirective: Set<String> = setOf( val plainDirectives: Set<String> = setOf(
"if", "incdir", "include", "incbin", "output", "idnt",
"ifeq", "ifne", "ifgt", "ifge", "iflt", "ifle", "ifb", "ifnb", "ifc", "ifnc",
"ifd", "ifnd", "ifmacrod", "ifmacrond",
//"iif" // not supported
"else", "endif", "endc",
"macro", "exitm", "mexit", "endm", "printt", "echo", "fail",
"extern", "nref", "xdef", "xref", "globl", "public", "weak", "opt"
)
"reg", "equr", "equrl", val otherDirectives: Set<String> = setOf(
"if",
"ifeq", "ifne", "ifgt", "ifge", "iflt", "ifle", "ifb", "ifnb", "ifc", "ifnc",
"ifd", "ifnd", "ifmacrod", "ifmacrond",
//"iif" // not supported
"else", "endif", "endc",
"incdir", "include", "incbin", "output", "rept", "endr",
"list", "nlist", "nolist", "llen", "nopage", "page", "spc", "macro", "exitm", "mexit", "endm",
"org",
"assert", "fail", "print", "printt", "printv", "echo", "extern", "nref", "xdef", "xref", "globl", "public", "weak",
"inline", "einline", "reg", "equr", "equrl",
"rem", "erem" "freg", "fequr", "fequrl",
"list", "nlist", "nolist", "llen", "nopage", "page", "spc",
"org",
"assert", "printv",
"inline", "einline",
"rem", "erem",
"machine", "mc68000", "mc68010", "mc68020", "mc68030", "mc68040", "mc68060",
"fpu",
"basereg", "endb", "far", "near", "initnear",
"end"
) )
} }
@@ -0,0 +1,198 @@
package de.platon42.intellij.plugins.m68k.asm
const val CC_X_CLEAR = 0x10000
const val CC_X_SET = 0x20000
const val CC_X_UNDEF = 0x30000
const val CC_X_RES = 0x40000
const val CC_X_AND = 0x50000
const val CC_X_OR = 0x60000
const val CC_X_CARRY = 0x70000
const val CC_X_TST = 0xf0000
const val CC_N_CLEAR = 0x01000
const val CC_N_SET = 0x02000
const val CC_N_UNDEF = 0x03000
const val CC_N_RES = 0x04000
const val CC_N_AND = 0x05000
const val CC_N_OR = 0x06000
const val CC_N_TST = 0x0f000
const val CC_Z_CLEAR = 0x00100
const val CC_Z_SET = 0x00200
const val CC_Z_UNDEF = 0x00300
const val CC_Z_RES = 0x00400
const val CC_Z_AND = 0x00500
const val CC_Z_OR = 0x00600
const val CC_Z_TST = 0x00f00
const val CC_V_CLEAR = 0x00010
const val CC_V_SET = 0x00020
const val CC_V_UNDEF = 0x00030
const val CC_V_RES = 0x00040
const val CC_V_AND = 0x00050
const val CC_V_OR = 0x00060
const val CC_V_TST = 0x000f0
const val CC_C_CLEAR = 0x00001
const val CC_C_SET = 0x00002
const val CC_C_UNDEF = 0x00003
const val CC_C_RES = 0x00004
const val CC_C_AND = 0x00005
const val CC_C_OR = 0x00006
const val CC_C_TST = 0x0000f
private const val CC_NOT_AFFECTED_STR = "Not affected"
private const val CC_ALWAYS_CLEAR_STR = "Always cleared"
private const val CC_ALWAYS_SET_STR = "Always set"
private const val CC_UNDEFINED_STR = "Undefined"
private const val CC_RES_STR = "From result"
private const val CC_AND_STR = "And'ed: Only cleared for zero bit"
private const val CC_OR_STR = "Or'ed: Only set for one bit"
fun getCcInfo(cc: Int): Map<String, Pair<String, String>> {
val xnzvcMap = LinkedHashMap<String, Pair<String, String>>(5)
xnzvcMap["X"] = when (cc and CC_X_TST) {
0 -> "-" to CC_NOT_AFFECTED_STR
CC_X_SET -> "1" to CC_ALWAYS_SET_STR
CC_X_CLEAR -> "0" to CC_ALWAYS_CLEAR_STR
CC_X_UNDEF -> "U" to CC_UNDEFINED_STR
CC_X_AND -> "*" to CC_AND_STR
CC_X_OR -> "*" to CC_OR_STR
CC_X_CARRY -> "*" to "Set the same as the carry bit"
else -> "*" to "$CC_RES_STR (usually the bit shifted out)"
}
xnzvcMap["N"] = when (cc and CC_N_TST) {
0 -> "-" to CC_NOT_AFFECTED_STR
CC_N_SET -> "1" to CC_ALWAYS_SET_STR
CC_N_CLEAR -> "0" to CC_ALWAYS_CLEAR_STR
CC_N_UNDEF -> "U" to CC_UNDEFINED_STR
CC_N_AND -> "*" to CC_AND_STR
CC_N_OR -> "*" to CC_OR_STR
else -> "*" to "$CC_RES_STR (usually if negative)"
}
xnzvcMap["Z"] = when (cc and CC_Z_TST) {
0 -> "-" to CC_NOT_AFFECTED_STR
CC_Z_SET -> "1" to CC_ALWAYS_SET_STR
CC_Z_CLEAR -> "0" to CC_ALWAYS_CLEAR_STR
CC_Z_UNDEF -> "U" to CC_UNDEFINED_STR
CC_Z_AND -> "*" to CC_AND_STR
CC_Z_OR -> "*" to CC_OR_STR
else -> "*" to "$CC_RES_STR (usually if zero)"
}
xnzvcMap["V"] = when (cc and CC_V_TST) {
0 -> "-" to CC_NOT_AFFECTED_STR
CC_V_SET -> "1" to CC_ALWAYS_SET_STR
CC_V_CLEAR -> "0" to CC_ALWAYS_CLEAR_STR
CC_V_UNDEF -> "U" to CC_UNDEFINED_STR
CC_V_AND -> "*" to CC_AND_STR
CC_V_OR -> "*" to CC_OR_STR
else -> "*" to "$CC_RES_STR (usually for overflows)"
}
xnzvcMap["C"] = when (cc and CC_V_TST) {
0 -> "-" to CC_NOT_AFFECTED_STR
CC_V_SET -> "1" to CC_ALWAYS_SET_STR
CC_V_CLEAR -> "0" to CC_ALWAYS_CLEAR_STR
CC_V_UNDEF -> "U" to CC_UNDEFINED_STR
CC_V_AND -> "*" to CC_AND_STR
CC_V_OR -> "*" to CC_OR_STR
else -> "*" to "$CC_RES_STR (usually carry/borrow)"
}
return xnzvcMap
}
fun cc(xnzvc: String): Int {
var result = 0
result += when (xnzvc[0]) {
'-' -> 0
'0' -> CC_X_CLEAR
'1' -> CC_X_SET
'U' -> CC_X_UNDEF
'*' -> CC_X_RES
'A' -> CC_X_AND
'O' -> CC_X_OR
'C' -> CC_X_CARRY
'?' -> CC_X_TST
else -> throw IllegalArgumentException("Syntax Error")
}
result += when (xnzvc[1]) {
'-' -> 0
'0' -> CC_N_CLEAR
'1' -> CC_N_SET
'U' -> CC_N_UNDEF
'*' -> CC_N_RES
'A' -> CC_N_AND
'O' -> CC_N_OR
'?' -> CC_N_TST
else -> throw IllegalArgumentException("Syntax Error")
}
result += when (xnzvc[2]) {
'-' -> 0
'0' -> CC_Z_CLEAR
'1' -> CC_Z_SET
'U' -> CC_Z_UNDEF
'*' -> CC_Z_RES
'A' -> CC_Z_AND
'O' -> CC_Z_OR
'?' -> CC_Z_TST
else -> throw IllegalArgumentException("Syntax Error")
}
result += when (xnzvc[3]) {
'-' -> 0
'0' -> CC_V_CLEAR
'1' -> CC_V_SET
'U' -> CC_V_UNDEF
'*' -> CC_V_RES
'A' -> CC_V_AND
'O' -> CC_V_OR
'?' -> CC_V_TST
else -> throw IllegalArgumentException("Syntax Error")
}
result += when (xnzvc[4]) {
'-' -> 0
'0' -> CC_C_CLEAR
'1' -> CC_C_SET
'U' -> CC_C_UNDEF
'*' -> CC_C_RES
'A' -> CC_C_AND
'O' -> CC_C_OR
'?' -> CC_C_TST
else -> throw IllegalArgumentException("Syntax Error")
}
return result
}
enum class ConditionCode(val cc: String, val testedCc: Int) {
TRUE("t", cc("-----")),
FALSE("f", cc("-----")),
HI("hi", cc("--?-?")),
LS("ls", cc("--?-?")),
CC("cc", cc("----?")),
HS("hs", cc("----?")), // same as CC
CS("cs", cc("----?")),
LO("lo", cc("----?")), // same as CS
NE("ne", cc("--?--")),
EQ("eq", cc("--?--")),
VC("vc", cc("---?-")),
VS("vs", cc("---?-")),
PL("pl", cc("-?---")),
MI("mi", cc("-?---")),
GE("ge", cc("-?-?-")),
LT("lt", cc("-?-?-")),
GT("gt", cc("-???-")),
LE("le", cc("-???-"));
companion object {
private val NAME_TO_CC_MAP = values().associateBy { it.cc }
fun getCcFromName(cc: String) = NAME_TO_CC_MAP[cc.lowercase()]!!
fun getCcFromMnemonic(originalMnemonic: String, mnemonic: String) =
// handle special case for dbra
if (mnemonic.equals("dbra", ignoreCase = true)) {
FALSE
} else {
NAME_TO_CC_MAP[mnemonic.removePrefix(originalMnemonic.removeSuffix("CC")).lowercase()]!!
}
}
}
File diff suppressed because it is too large Load Diff
@@ -4,13 +4,20 @@ import com.intellij.codeInsight.completion.*
import com.intellij.codeInsight.lookup.LookupElementBuilder import com.intellij.codeInsight.lookup.LookupElementBuilder
import com.intellij.patterns.PlatformPatterns import com.intellij.patterns.PlatformPatterns
import com.intellij.util.ProcessingContext import com.intellij.util.ProcessingContext
import de.platon42.intellij.plugins.m68k.M68kIcons
import de.platon42.intellij.plugins.m68k.psi.M68kTypes import de.platon42.intellij.plugins.m68k.psi.M68kTypes
class M68kMnemonicCompletionContributor : CompletionContributor() { class M68kMnemonicCompletionContributor : CompletionContributor() {
companion object {
val MNEMONICS = M68kIsa.mnemonics
.map { PrioritizedLookupElement.withPriority(LookupElementBuilder.create(it).withIcon(M68kIcons.MNEMONIC), 10.0) }
}
init { init {
extend(CompletionType.BASIC, PlatformPatterns.psiElement(M68kTypes.MACRO_INVOKATION), object : CompletionProvider<CompletionParameters>() { extend(CompletionType.BASIC, PlatformPatterns.psiElement(M68kTypes.MACRO_INVOCATION), object : CompletionProvider<CompletionParameters>() {
override fun addCompletions(parameters: CompletionParameters, context: ProcessingContext, resultSet: CompletionResultSet) { override fun addCompletions(parameters: CompletionParameters, context: ProcessingContext, resultSet: CompletionResultSet) {
resultSet.addAllElements(M68kIsa.mnemonics.map(LookupElementBuilder::create)) resultSet.addAllElements(MNEMONICS)
} }
}) })
} }
@@ -0,0 +1,47 @@
package de.platon42.intellij.plugins.m68k.documentation
import com.intellij.lang.documentation.AbstractDocumentationProvider
import com.intellij.lang.documentation.DocumentationMarkup
import com.intellij.openapi.util.text.StringUtil
import com.intellij.psi.PsiComment
import com.intellij.psi.PsiElement
import com.intellij.psi.util.PsiTreeUtil
import com.intellij.util.SmartList
import de.platon42.intellij.plugins.m68k.psi.M68kGlobalLabel
import de.platon42.intellij.plugins.m68k.psi.M68kStatement
class M68kGlobalLabelDocumentationProvider : AbstractDocumentationProvider() {
override fun getQuickNavigateInfo(element: PsiElement, originalElement: PsiElement?): String? {
return generateDoc(element, originalElement)
}
override fun generateDoc(element: PsiElement, originalElement: PsiElement?): String? {
return if (element is M68kGlobalLabel) {
// TODO find out how we can generate inner links for more symbol references inside the expression (DocumentationManagerUtil)
val statement = element.parent as M68kStatement
var preprocessorDirective = statement.preprocessorDirective
if ((preprocessorDirective == null) && (statement.asmInstruction == null) && (statement.macroCall == null)) {
val nextLineStatement = PsiTreeUtil.skipWhitespacesAndCommentsForward(PsiTreeUtil.skipWhitespacesAndCommentsForward(statement))
as? M68kStatement
preprocessorDirective = nextLineStatement?.preprocessorDirective
}
val content = if (preprocessorDirective != null)
DocumentationMarkup.CONTENT_START + StringUtil.escapeXmlEntities(preprocessorDirective.text) + DocumentationMarkup.CONTENT_END
else ""
val comments = SmartList<String>()
var prevToken: PsiElement? = statement
do {
prevToken = PsiTreeUtil.skipWhitespacesBackward(prevToken)
if (prevToken !is PsiComment) break
comments.add(prevToken.text)
} while (true)
val commentpart =
if (comments.isNotEmpty()) comments.asReversed().joinToString("<br>", DocumentationMarkup.GRAYED_START, DocumentationMarkup.GRAYED_END) else ""
commentpart +
DocumentationMarkup.DEFINITION_START + StringUtil.escapeXmlEntities(element.name!!) + DocumentationMarkup.DEFINITION_END +
content
} else null
}
}
@@ -0,0 +1,147 @@
package de.platon42.intellij.plugins.m68k.documentation
import com.intellij.lang.documentation.AbstractDocumentationProvider
import com.intellij.lang.documentation.DocumentationMarkup
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.util.text.HtmlBuilder
import com.intellij.openapi.util.text.HtmlChunk
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiFile
import de.platon42.intellij.plugins.m68k.asm.AddressMode
import de.platon42.intellij.plugins.m68k.asm.IsaData
import de.platon42.intellij.plugins.m68k.asm.M68kIsa
import de.platon42.intellij.plugins.m68k.asm.getCcInfo
import de.platon42.intellij.plugins.m68k.psi.M68kAsmInstruction
import de.platon42.intellij.plugins.m68k.psi.M68kAsmOp
import de.platon42.intellij.plugins.m68k.psi.M68kOperandSize
import de.platon42.intellij.plugins.m68k.utils.M68kIsaUtil.findExactIsaDataForInstruction
import de.platon42.intellij.plugins.m68k.utils.M68kIsaUtil.findOpSizeDescriptions
class M68kInstructionDocumentationProvider : AbstractDocumentationProvider() {
override fun generateDoc(element: PsiElement, originalElement: PsiElement?): String? {
if (element is M68kAsmInstruction) {
val builder = HtmlBuilder()
val isaData = findExactIsaDataForInstruction(element)
if (isaData == null) {
M68kIsa.findMatchingInstructions(element.asmOp.mnemonic).forEach { buildDocForIsaData(it, builder) }
} else {
buildDocForIsaData(isaData, builder)
}
return builder.toString()
}
return null
}
private fun buildDocForIsaData(isaData: IsaData, builder: HtmlBuilder) {
val defBuilder = createDefinition(isaData)
builder.append(defBuilder.wrapWith(DocumentationMarkup.DEFINITION_ELEMENT))
val hasSameCcsForEverything = isaData.modes.map { it.affectedCc }.distinct().count() == 1
var alreadyShownCcsOnce = false
val mnemonicInfoRows = HtmlBuilder()
mnemonicInfoRows.appendWithSeparators(HtmlChunk.tag("tr").child(HtmlChunk.hr().wrapWith(DocumentationMarkup.SECTION_CONTENT_CELL).attr("colspan", "3")),
isaData.modes.map { allowedAdrMode ->
val addressModeInfoRows = HtmlBuilder()
val headerCells = if (allowedAdrMode.op2 != null) {
listOf(
HtmlChunk.text("Mnemonic / CCs").wrapWith(DocumentationMarkup.SECTION_HEADER_CELL),
HtmlChunk.text("Operand 1").wrapWith(DocumentationMarkup.SECTION_HEADER_CELL),
HtmlChunk.text("Operand 2").wrapWith(DocumentationMarkup.SECTION_HEADER_CELL)
)
} else if (allowedAdrMode.op1 != null) {
listOf(
HtmlChunk.text("Mnemonic / CCs").wrapWith(DocumentationMarkup.SECTION_HEADER_CELL),
HtmlChunk.text("Operand").wrapWith(DocumentationMarkup.SECTION_HEADER_CELL)
)
} else {
listOf(HtmlChunk.text("Mnemonic / CCs").wrapWith(DocumentationMarkup.SECTION_HEADER_CELL))
}
addressModeInfoRows.append(HtmlChunk.tag("tr").children(headerCells))
val contentBuilder = HtmlBuilder()
val mnemonics = findOpSizeDescriptions(allowedAdrMode.size)
.map { HtmlChunk.text(isaData.mnemonic + it) }
contentBuilder.appendWithSeparators(HtmlChunk.br(), mnemonics)
contentBuilder.append(HtmlChunk.hr())
if (alreadyShownCcsOnce && hasSameCcsForEverything) {
contentBuilder.append(HtmlChunk.text("Condition Codes: Same as above"))
} else {
alreadyShownCcsOnce = true
contentBuilder.append(HtmlChunk.text("Condition Codes: "))
contentBuilder.append(HtmlChunk.br())
if (allowedAdrMode.affectedCc == 0) {
contentBuilder.append(HtmlChunk.text("Not affected."))
} else {
val ccMap = getCcInfo(allowedAdrMode.affectedCc)
val ccShortTableRows = HtmlBuilder()
ccShortTableRows.append(
HtmlChunk.tag("tr").children(ccMap.keys.map { HtmlChunk.text(it).wrapWith(DocumentationMarkup.SECTION_HEADER_CELL) })
)
ccShortTableRows.append(
HtmlChunk.tag("tr").children(ccMap.values.map {
HtmlChunk.text(it.first).wrapWith(DocumentationMarkup.SECTION_CONTENT_CELL)
})
)
contentBuilder.append(ccShortTableRows.wrapWith(DocumentationMarkup.SECTIONS_TABLE))
contentBuilder.appendWithSeparators(HtmlChunk.br(), ccMap.map {
HtmlChunk.text(it.key + " - " + it.value.second)
})
}
}
val cellsPerRow = ArrayList<HtmlChunk>(3)
cellsPerRow.add(contentBuilder.toFragment())
if (allowedAdrMode.op1 != null) cellsPerRow.add(collectAddressModes(allowedAdrMode.op1, allowedAdrMode.specialReg))
if (allowedAdrMode.op1 != null) cellsPerRow.add(collectAddressModes(allowedAdrMode.op2, allowedAdrMode.specialReg))
addressModeInfoRows.append(HtmlChunk.tag("tr").children(cellsPerRow.map { it.wrapWith(DocumentationMarkup.SECTION_CONTENT_CELL) }))
addressModeInfoRows.toFragment()
})
val contentBuilder = HtmlBuilder()
contentBuilder.append(mnemonicInfoRows.wrapWith(DocumentationMarkup.SECTIONS_TABLE))
builder.append(contentBuilder.wrapWith(DocumentationMarkup.CONTENT_ELEMENT))
}
override fun generateHoverDoc(element: PsiElement, originalElement: PsiElement?): String? {
if (element is M68kAsmInstruction) {
val isaData = findExactIsaDataForInstruction(element) ?: return null
val defBuilder = createDefinition(isaData)
val builder = HtmlBuilder()
builder.append(defBuilder.wrapWith(DocumentationMarkup.DEFINITION_ELEMENT))
return builder.toString()
}
return null
}
private fun createDefinition(isaData: IsaData): HtmlBuilder {
val defBuilder = HtmlBuilder()
defBuilder.append(HtmlChunk.text(isaData.description).bold().wrapWith("pre"))
if (isaData.isPrivileged) {
defBuilder.append(HtmlChunk.font("red").addText("(privileged)").wrapWith(HtmlChunk.p()))
}
return defBuilder
}
private fun collectAddressModes(addressModes: Set<AddressMode>?, specialReg: String?): HtmlChunk {
if (addressModes == null) return HtmlChunk.text("")
val modes = HtmlBuilder()
addressModes.sortedBy(AddressMode::ordinal)
.map { if (it == AddressMode.SPECIAL_REGISTER_DIRECT) specialReg!! else it.syntax }
.forEach { modes.append(HtmlChunk.text(it).wrapWith(HtmlChunk.div())) }
return modes.toFragment()
}
override fun getCustomDocumentationElement(editor: Editor, file: PsiFile, contextElement: PsiElement?, targetOffset: Int): PsiElement? {
if (contextElement == null) return null
if (contextElement is M68kAsmInstruction) return contextElement
val parent = contextElement.parent ?: return null
if (parent is M68kAsmInstruction) return parent
if (parent is M68kAsmOp) return parent.parent
if (parent is M68kOperandSize) return parent.parent.parent
return null
}
}
@@ -0,0 +1,214 @@
package de.platon42.intellij.plugins.m68k.documentation
import com.intellij.lang.documentation.AbstractDocumentationProvider
import com.intellij.lang.documentation.DocumentationMarkup
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.util.text.HtmlBuilder
import com.intellij.openapi.util.text.HtmlChunk
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiFile
import com.intellij.psi.util.PsiTreeUtil
import com.intellij.ui.ColorUtil
import com.intellij.ui.JBColor
import de.platon42.intellij.plugins.m68k.asm.*
import de.platon42.intellij.plugins.m68k.asm.Register.Companion.getRegFromName
import de.platon42.intellij.plugins.m68k.psi.*
import de.platon42.intellij.plugins.m68k.utils.M68kIsaUtil.checkIfInstructionUsesRegister
import de.platon42.intellij.plugins.m68k.utils.M68kIsaUtil.evaluateRegisterUse
import de.platon42.intellij.plugins.m68k.utils.M68kIsaUtil.findExactIsaDataAndAllowedAdrModeForInstruction
import de.platon42.intellij.plugins.m68k.utils.M68kIsaUtil.getOpSizeOrDefault
import de.platon42.intellij.plugins.m68k.utils.M68kIsaUtil.modifyRwmWithOpsize
class M68kRegisterFlowDocumentationProvider : AbstractDocumentationProvider() {
override fun generateDoc(element: PsiElement, originalElement: PsiElement?): String? {
if (element is M68kDataRegister || element is M68kAddressRegister) {
return createDoc(element as M68kRegister, 100) // TODO make this configurable
}
return null
}
override fun generateHoverDoc(element: PsiElement, originalElement: PsiElement?): String? {
if (element is M68kDataRegister || element is M68kAddressRegister) {
return createDoc(element as M68kRegister, 4) // TODO make this configurable
}
return null
}
private fun createDoc(element: M68kRegister, linesLimit: Int): String? {
val register = getRegFromName(element.text)
val addressingMode = PsiTreeUtil.getParentOfType(element, M68kAddressingMode::class.java) ?: return null
val asmInstruction = PsiTreeUtil.getParentOfType(addressingMode, M68kAsmInstruction::class.java) ?: return null
val (isaData, adrMode) = findExactIsaDataAndAllowedAdrModeForInstruction(asmInstruction) ?: return "unknown instruction"
val cursorInstRwmRegs = evaluateRegisterUse(asmInstruction, adrMode, register)
val opSize = getOpSizeOrDefault(asmInstruction.asmOp.opSize, adrMode)
val rn = register.regname
val thisInfo = cursorInstRwmRegs
.joinToString(separator = ", ", prefix = "${isaData.mnemonic} instruction ") { rwmToDisplayText(it, rn) }
val totalRwm = cursorInstRwmRegs.reduce(Int::or)
val firstOp = asmInstruction.addressingModeList[0] == addressingMode
val cursorRwm = modifyRwmWithOpsize((adrMode.modInfo ushr if (firstOp) RWM_OP1_SHIFT else RWM_OP2_SHIFT) and RWM_OP_MASK, opSize)
val backtrace = ArrayList<HtmlChunk>()
val missingBits = if (cursorRwm and RWM_SET_L != 0) {
if (totalRwm and RWM_SET_L == RWM_SET_L) {
backtrace.add(
HtmlChunk.tag("tr")
.children(
DocumentationMarkup.SECTION_CONTENT_CELL.attr("colspan", "3")
.child(HtmlChunk.text("Register result is fully defined by this instruction."))
)
)
0
} else {
RWM_SIZE_MASK and totalRwm.inv()
}
} else {
RWM_SIZE_MASK and (((cursorRwm and RWM_MODIFY_L) ushr RWM_MODIFY_SHIFT) or ((cursorRwm and RWM_READ_L) ushr RWM_READ_SHIFT))
}
val initialStatement: M68kStatement = asmInstruction.parent as M68kStatement
val localLabelName = PsiTreeUtil.findChildOfType(initialStatement, M68kLocalLabel::class.java)?.name ?: "-->"
backtrace.add(
HtmlChunk.tag("tr")
.children(DocumentationMarkup.SECTION_CONTENT_CELL.child(HtmlChunk.text(localLabelName)))
.children(highlightRegister(asmInstruction, register).bold().wrapWith(DocumentationMarkup.SECTION_CONTENT_CELL))
.children(DocumentationMarkup.SECTION_CONTENT_CELL.child(HtmlChunk.text(" ; <--")))
)
backtrace.addAll(analyseFlow(register, missingBits, true, initialStatement, linesLimit) {
PsiTreeUtil.getPrevSiblingOfType(it, M68kStatement::class.java)
})
backtrace.reverse()
val traceBits = (cursorRwm or (cursorRwm ushr RWM_MODIFY_SHIFT) or (cursorRwm ushr RWM_READ_SHIFT)) and RWM_SIZE_MASK
backtrace.addAll(analyseFlow(register, traceBits, false, initialStatement, linesLimit) {
PsiTreeUtil.getNextSiblingOfType(it, M68kStatement::class.java)
})
val statementRows = HtmlBuilder()
backtrace.forEach(statementRows::append)
val builder = HtmlBuilder()
builder.append(HtmlChunk.text(thisInfo).wrapWith(DocumentationMarkup.DEFINITION_ELEMENT))
builder.append(statementRows.wrapWith(DocumentationMarkup.SECTIONS_TABLE.style("padding-left: 8pt; padding-right: 8pt")))
return builder.toString()
}
private fun analyseFlow(
register: Register,
rwmBits: Int,
globalLabelBreaksOnInitialStatement: Boolean,
startingStatement: M68kStatement,
linesLimit: Int,
direction: (statement: M68kStatement) -> M68kStatement?
): List<HtmlChunk> {
var missingBits = rwmBits
var currStatement = startingStatement
val statementLines = ArrayList<HtmlChunk>()
val rn = register.regname
var addAbbrevDots = false
var lines = 0
while (missingBits > 0) {
val globalLabel = PsiTreeUtil.findChildOfType(currStatement, M68kGlobalLabel::class.java)
if ((globalLabel != null) && (globalLabelBreaksOnInitialStatement || (currStatement !== startingStatement))) {
statementLines.add(
HtmlChunk.tag("tr")
.children(DocumentationMarkup.SECTION_CONTENT_CELL.attr("colspan", "3").child(HtmlChunk.text(globalLabel.name!!).bold()))
)
break
}
currStatement = direction.invoke(currStatement) ?: break
val currAsmInstruction = PsiTreeUtil.getChildOfType(currStatement, M68kAsmInstruction::class.java) ?: continue
if (checkIfInstructionUsesRegister(currAsmInstruction, register)) {
if (addAbbrevDots) {
++lines
statementLines.add(createAbbreviationDots())
}
if (++lines > linesLimit) {
if (!addAbbrevDots) {
statementLines.add(createAbbreviationDots())
}
break
}
addAbbrevDots = false
val (_, currAdrMode) = findExactIsaDataAndAllowedAdrModeForInstruction(currAsmInstruction) ?: continue
val localLabelName = PsiTreeUtil.findChildOfType(currStatement, M68kLocalLabel::class.java)?.name ?: "        "
val currRwms = evaluateRegisterUse(currAsmInstruction, currAdrMode, register)
val currTotalRwm = currRwms.reduce(Int::or)
val lineInfo = currRwms
.map {
val text = HtmlChunk.text(rwmToDisplayText(it, rn))
if ((missingBits and it) > 0) text.wrapWith(HtmlChunk.font("#" + ColorUtil.toHex(JBColor.GREEN))) else text
}
if ((currTotalRwm and RWM_SET_L) > 0) {
missingBits = missingBits and currTotalRwm.inv()
}
val lineBuilder = HtmlBuilder()
lineBuilder.append(" ; ")
lineBuilder.appendWithSeparators(HtmlChunk.text(", "), lineInfo)
.wrapWith(HtmlChunk.div())
statementLines.add(
HtmlChunk.tag("tr")
.children(DocumentationMarkup.SECTION_CONTENT_CELL.child(HtmlChunk.text(localLabelName)))
.children(highlightRegister(currAsmInstruction, register).wrapWith(DocumentationMarkup.SECTION_CONTENT_CELL))
.children(lineBuilder.wrapWith(DocumentationMarkup.SECTION_CONTENT_CELL))
)
} else {
addAbbrevDots = true
}
}
return statementLines
}
private fun highlightRegister(currAsmInstruction: M68kAsmInstruction, register: Register): HtmlChunk {
val builder = HtmlBuilder()
val plainText = currAsmInstruction.text
var startPos = 0
val rn = if (register == Register.A7) listOf(register.regname, "sp") else listOf(register.regname)
do {
val indexPos = plainText.indexOfAny(rn, startPos, ignoreCase = true)
if (indexPos >= 0) {
builder.append(HtmlChunk.text(plainText.substring(startPos until indexPos)))
startPos = indexPos + register.regname.length
builder.append(HtmlChunk.text(plainText.substring(indexPos until startPos)).wrapWith(HtmlChunk.font("#" + ColorUtil.toHex(JBColor.ORANGE))))
} else {
builder.append(HtmlChunk.text(plainText.substring(startPos)))
}
} while (indexPos >= 0)
return builder.toFragment().code()
}
private fun rwmToDisplayText(rwm: Int, rn: String) =
when (rwm) {
RWM_READ_B -> "uses $rn.b"
RWM_READ_W -> "uses $rn.w"
RWM_READ_L -> "uses $rn.l"
RWM_MODIFY_B -> "changes $rn.b"
RWM_MODIFY_W -> "changes $rn.w"
RWM_MODIFY_L -> "changes $rn.l"
RWM_SET_B -> "sets $rn.b"
RWM_SET_W -> "sets $rn.w"
RWM_SET_L -> "sets $rn.l"
else -> "uhm?"
}
private fun createAbbreviationDots() = HtmlChunk.tag("tr")
.children(DocumentationMarkup.SECTION_CONTENT_CELL.child(HtmlChunk.nbsp()))
.children(
DocumentationMarkup.SECTION_CONTENT_CELL.child(
HtmlChunk.text("[...]").wrapWith(HtmlChunk.div().attr("class", "grayed"))
)
)
.children(DocumentationMarkup.SECTION_CONTENT_CELL.child(HtmlChunk.nbsp()))
override fun getCustomDocumentationElement(editor: Editor, file: PsiFile, contextElement: PsiElement?, targetOffset: Int): PsiElement? {
if (contextElement == null) return null
if (contextElement is M68kDataRegister || contextElement is M68kAddressRegister) return contextElement
val parent = contextElement.parent ?: return null
if (parent is M68kDataRegister || parent is M68kAddressRegister) return parent
return null
}
}
@@ -0,0 +1,24 @@
package de.platon42.intellij.plugins.m68k.documentation
import com.intellij.lang.documentation.AbstractDocumentationProvider
import com.intellij.lang.documentation.DocumentationMarkup
import com.intellij.openapi.util.text.StringUtil
import com.intellij.psi.PsiElement
import de.platon42.intellij.plugins.m68k.psi.M68kAssignment
import de.platon42.intellij.plugins.m68k.psi.M68kSymbolDefinition
class M68kSymbolDefinitionDocumentationProvider : AbstractDocumentationProvider() {
override fun getQuickNavigateInfo(element: PsiElement, originalElement: PsiElement?): String? {
return generateDoc(element, originalElement)
}
override fun generateDoc(element: PsiElement, originalElement: PsiElement?): String? {
return if (element is M68kSymbolDefinition) {
// TODO find out how we can generate inner links for more symbol references inside the expression (DocumentationManagerUtil)
val value = (element.parent as M68kAssignment).expr.text
DocumentationMarkup.DEFINITION_START + StringUtil.escapeXmlEntities(element.name!!) + DocumentationMarkup.DEFINITION_END +
DocumentationMarkup.CONTENT_START + StringUtil.escapeXmlEntities(value) + DocumentationMarkup.CONTENT_END
} else null
}
}
@@ -0,0 +1,44 @@
package de.platon42.intellij.plugins.m68k.inspections
import com.intellij.codeInspection.InspectionManager
import com.intellij.codeInspection.LocalInspectionTool
import com.intellij.codeInspection.ProblemDescriptor
import com.intellij.codeInspection.ProblemsHolder
import com.intellij.psi.PsiElementVisitor
import de.platon42.intellij.plugins.m68k.psi.*
abstract class AbstractBaseM68kLocalInspectionTool : LocalInspectionTool() {
protected open fun checkStatement(statement: M68kStatement, manager: InspectionManager, isOnTheFly: Boolean): Array<ProblemDescriptor>? = null
protected open fun checkAsmInstruction(asmInstruction: M68kAsmInstruction, manager: InspectionManager, isOnTheFly: Boolean): Array<ProblemDescriptor>? =
null
protected open fun checkMacroCall(macroCall: M68kMacroCall, manager: InspectionManager, isOnTheFly: Boolean): Array<ProblemDescriptor>? = null
protected open fun checkDirective(directive: M68kPreprocessorDirective, manager: InspectionManager, isOnTheFly: Boolean): Array<ProblemDescriptor>? = null
protected open fun checkRegister(register: M68kRegister, manager: InspectionManager, isOnTheFly: Boolean): Array<ProblemDescriptor>? = null
override fun getGroupDisplayName() = "M68k"
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor {
return object : M68kVisitor() {
override fun visitStatement(statement: M68kStatement) = addDescriptors(checkStatement(statement, holder.manager, isOnTheFly))
override fun visitAsmInstruction(asmInstruction: M68kAsmInstruction) =
addDescriptors(checkAsmInstruction(asmInstruction, holder.manager, isOnTheFly))
override fun visitMacroCall(macroCall: M68kMacroCall) = addDescriptors(checkMacroCall(macroCall, holder.manager, isOnTheFly))
override fun visitPreprocessorDirective(directive: M68kPreprocessorDirective) =
addDescriptors(checkDirective(directive, holder.manager, isOnTheFly))
override fun visitRegister(register: M68kRegister) = addDescriptors(checkRegister(register, holder.manager, isOnTheFly))
private fun addDescriptors(descriptors: Array<ProblemDescriptor>?) {
descriptors?.forEach(holder::registerProblem)
}
}
}
}
@@ -0,0 +1,104 @@
package de.platon42.intellij.plugins.m68k.inspections
import com.intellij.codeInspection.InspectionManager
import com.intellij.codeInspection.ProblemDescriptor
import com.intellij.codeInspection.ProblemHighlightType
import com.intellij.psi.util.PsiTreeUtil
import com.intellij.util.SmartList
import de.platon42.intellij.plugins.m68k.asm.*
import de.platon42.intellij.plugins.m68k.asm.M68kIsa.findMatchingInstructions
import de.platon42.intellij.plugins.m68k.psi.*
import de.platon42.intellij.plugins.m68k.utils.M68kIsaUtil
import de.platon42.intellij.plugins.m68k.utils.M68kIsaUtil.checkIfInstructionUsesRegister
import de.platon42.intellij.plugins.m68k.utils.M68kIsaUtil.evaluateRegisterUse
import de.platon42.intellij.plugins.m68k.utils.M68kIsaUtil.findExactIsaDataAndAllowedAdrModeForInstruction
import de.platon42.intellij.plugins.m68k.utils.M68kIsaUtil.getConcreteTestedCcFromMnemonic
class M68kDeadWriteInspection : AbstractBaseM68kLocalInspectionTool() {
companion object {
private const val DISPLAY_NAME = "Dead writes to registers"
private const val DEAD_WRITE_MSG_TEMPLATE = "Register %s is overwritten later without being used"
private const val POSSIBLY_DEAD_WRITE_MSG_TEMPLATE = "Register %s is overwritten later (only CC evaluated?)"
}
override fun getDisplayName() = DISPLAY_NAME
override fun checkAsmInstruction(asmInstruction: M68kAsmInstruction, manager: InspectionManager, isOnTheFly: Boolean): Array<ProblemDescriptor>? {
val asmOp = asmInstruction.asmOp
if (asmInstruction.addressingModeList.isEmpty()) return emptyArray()
val isaDataCandidates = findMatchingInstructions(asmOp.mnemonic)
if (isaDataCandidates.isEmpty()) return emptyArray()
val (_, adrMode) = findExactIsaDataAndAllowedAdrModeForInstruction(asmInstruction) ?: return emptyArray()
val opSize = M68kIsaUtil.getOpSizeOrDefault(asmInstruction.asmOp.opSize, adrMode)
val rwm1 = M68kIsaUtil.modifyRwmWithOpsize((adrMode.modInfo ushr RWM_OP1_SHIFT) and RWM_OP_MASK, opSize)
val rwm2 = if (asmInstruction.addressingModeList.size > 1) M68kIsaUtil.modifyRwmWithOpsize(
(adrMode.modInfo ushr RWM_OP2_SHIFT) and RWM_OP_MASK, opSize
) else 0
val regsWritten = M68kAddressModeUtil.getReadWriteModifyRegisters(asmInstruction.addressingModeList[0], rwm1).asSequence()
.plus(M68kAddressModeUtil.getReadWriteModifyRegisters(asmInstruction.addressingModeList.getOrNull(1), rwm2))
.plus(M68kAddressModeUtil.getOtherReadWriteModifyRegisters(adrMode.modInfo))
.filter { (it.second and RWM_SET_L) > 0 }
.distinct()
.toList()
val hints = SmartList<ProblemDescriptor>()
for (regPair in regsWritten) {
val register = regPair.first
var rwm = regPair.second
var currStatement = asmInstruction.parent as M68kStatement
var ccModification = adrMode.affectedCc
var ccOverwritten = false
var ccTested = false
var hasModification = false
while (true) {
currStatement = PsiTreeUtil.getNextSiblingOfType(currStatement, M68kStatement::class.java) ?: break
val globalLabel = PsiTreeUtil.findChildOfType(currStatement, M68kGlobalLabel::class.java)
if (globalLabel != null) break
if (PsiTreeUtil.getChildOfType(currStatement, M68kPreprocessorDirective::class.java) != null) break
// as we cannot evaluate macros right now, abort at macros containing the register name (only lower case for simplicity)
val macroCall = PsiTreeUtil.getChildOfType(currStatement, M68kMacroCall::class.java)
if (macroCall?.exprList?.any { it.textMatches(register.regname) } == true) break
val currAsmInstruction = PsiTreeUtil.getChildOfType(currStatement, M68kAsmInstruction::class.java) ?: continue
val (isaData, currAdrMode) = findExactIsaDataAndAllowedAdrModeForInstruction(currAsmInstruction) ?: continue
if (isaData.changesControlFlow) break
val testedCc = getConcreteTestedCcFromMnemonic(currAsmInstruction.asmOp.mnemonic, isaData, currAdrMode)
if (((testedCc and ccModification) > 0) && !ccOverwritten) ccTested = true
if (currAdrMode.affectedCc != 0) ccOverwritten = true
if (checkIfInstructionUsesRegister(currAsmInstruction, register)) {
val totalRwms = evaluateRegisterUse(currAsmInstruction, currAdrMode, register).reduce(Int::or)
if (totalRwms and RWM_READ_L > 0) break
if (totalRwms and RWM_MODIFY_L > 0) {
hasModification = true
ccOverwritten = false
ccModification = ccModification or currAdrMode.affectedCc
rwm = (totalRwms ushr RWM_MODIFY_SHIFT) and RWM_SET_L
}
if (totalRwms and RWM_SET_L >= rwm) {
if (ccTested && hasModification) {
break
}
hints.add(
manager.createProblemDescriptor(
asmInstruction,
asmInstruction,
(if (ccTested) POSSIBLY_DEAD_WRITE_MSG_TEMPLATE else DEAD_WRITE_MSG_TEMPLATE).format(register.regname),
if (ccTested) ProblemHighlightType.WEAK_WARNING else ProblemHighlightType.WARNING,
isOnTheFly
)
)
break
}
}
}
}
return hints.toTypedArray()
}
}
@@ -0,0 +1,83 @@
package de.platon42.intellij.plugins.m68k.inspections
import com.intellij.codeInspection.InspectionSuppressor
import com.intellij.codeInspection.ProblemDescriptor
import com.intellij.codeInspection.SuppressQuickFix
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiComment
import com.intellij.psi.PsiDocumentManager
import com.intellij.psi.PsiElement
import com.intellij.psi.util.PsiTreeUtil
import de.platon42.intellij.plugins.m68k.psi.M68kPsiElement
import de.platon42.intellij.plugins.m68k.psi.M68kStatement
class M68kInspectionSuppressor : InspectionSuppressor {
companion object {
const val MARKER = "suppress "
}
override fun isSuppressedFor(element: PsiElement, toolId: String): Boolean {
if (element !is M68kPsiElement) return false
val statement = PsiTreeUtil.getParentOfType(element, M68kStatement::class.java) ?: return false
val nextToken = PsiTreeUtil.skipWhitespacesForward(statement)
return isSuppressedWithComment(nextToken, toolId) || isSuppressedWithComment(PsiTreeUtil.skipWhitespacesBackward(statement), toolId)
}
override fun getSuppressActions(element: PsiElement?, toolId: String): Array<SuppressQuickFix> {
return arrayOf(LineSuppressQuickFix(toolId))
}
private fun isSuppressedWithComment(nextToken: PsiElement?, toolId: String): Boolean {
return if (nextToken is PsiComment) {
val comment = nextToken.text
comment.contains(MARKER) && comment.contains(toolId)
} else {
false
}
}
class LineSuppressQuickFix(private val toolId: String) : SuppressQuickFix {
override fun getFamilyName() = "Suppress for statement"
override fun applyFix(project: Project, descriptor: ProblemDescriptor) {
val statement = PsiTreeUtil.getParentOfType(descriptor.startElement, M68kStatement::class.java) ?: return
val document = PsiDocumentManager.getInstance(project).getDocument(statement.containingFile) ?: return
val lineNumber = document.getLineNumber(statement.textOffset)
var usePrevLine = false
val nextToken = PsiTreeUtil.skipWhitespacesForward(statement)
if (nextToken is PsiComment) {
val comment = nextToken.text
if (comment.contains(MARKER)) {
if (!comment.contains(toolId)) {
document.insertString(document.getLineEndOffset(lineNumber), " $toolId")
}
return
} else {
usePrevLine = true
}
}
val prevToken = PsiTreeUtil.skipWhitespacesBackward(statement)
if (prevToken is PsiComment) {
val comment = prevToken.text
if (comment.contains(MARKER)) {
if (!comment.contains(toolId)) {
document.insertString(document.getLineEndOffset(document.getLineNumber(prevToken.textOffset)), " $toolId")
}
return
}
}
if (usePrevLine) {
document.insertString(document.getLineStartOffset(lineNumber), "; $MARKER$toolId\n")
} else {
document.insertString(document.getLineEndOffset(lineNumber), "\t; $MARKER$toolId")
}
}
override fun isAvailable(project: Project, context: PsiElement) = true
override fun isSuppressAll() = false
}
}
@@ -0,0 +1,168 @@
package de.platon42.intellij.plugins.m68k.inspections
import com.intellij.codeInspection.InspectionManager
import com.intellij.codeInspection.LocalQuickFix
import com.intellij.codeInspection.ProblemDescriptor
import com.intellij.codeInspection.ProblemHighlightType
import de.platon42.intellij.plugins.m68k.asm.*
import de.platon42.intellij.plugins.m68k.asm.M68kIsa.findMatchingInstructions
import de.platon42.intellij.plugins.m68k.asm.M68kIsa.findMatchingOpMode
import de.platon42.intellij.plugins.m68k.asm.M68kIsa.findMatchingOpModeIgnoringSize
import de.platon42.intellij.plugins.m68k.asm.M68kIsa.findSupportedOpSizes
import de.platon42.intellij.plugins.m68k.psi.M68kAddressModeUtil.getAddressModeForType
import de.platon42.intellij.plugins.m68k.psi.M68kAsmInstruction
import de.platon42.intellij.plugins.m68k.psi.M68kSpecialRegisterDirectAddressingMode
import de.platon42.intellij.plugins.m68k.utils.M68kIsaUtil
class M68kSyntaxInspection : AbstractBaseM68kLocalInspectionTool() {
companion object {
private const val DISPLAY_NAME = "Assembly instruction validity"
private const val INSTRUCTION_NOT_FOUND_MSG = "Instruction '#ref' not supported on selected cpu"
private const val OPERANDS_UNEXPECTED_MSG_TEMPLATE = "No operands expected for '%s'"
private const val SECOND_OP_UNEXPECTED_MSG_TEMPLATE = "Second operand '#ref' unexpected for '%s'"
private const val UNSUPPORTED_ADDRESSING_MODE_MSG_TEMPLATE = "Unsupported addressing mode for '%s'"
private const val UNSUPPORTED_ADDRESSING_MODE_OP1_MSG_TEMPLATE = "Unsupported addressing mode '#ref' for first operand of '%s'"
private const val UNSUPPORTED_ADDRESSING_MODE_OP2_MSG_TEMPLATE = "Unsupported addressing mode '#ref' for second operand of '%s'"
private const val UNSUPPORTED_ADDRESSING_MODE_FLIP_MSG_TEMPLATE = "Unsupported addressing modes for operands in this order for '%s'"
private const val UNSUPPORTED_SIZE_UNSIZED_MSG_TEMPLATE = "Instruction '%s' is unsized"
private const val UNSUPPORTED_SIZE_MSG_TEMPLATE = "Operation size '#ref' unsupported for '%s"
private const val UNSUPPORTED_SIZE_HINT_MSG_TEMPLATE = "Operation size '#ref' unsupported (should be %s)"
}
override fun getDisplayName() = DISPLAY_NAME
override fun checkAsmInstruction(asmInstruction: M68kAsmInstruction, manager: InspectionManager, isOnTheFly: Boolean): Array<ProblemDescriptor>? {
val asmOp = asmInstruction.asmOp
val mnemonicWithSize = asmOp.text
val isaData = findMatchingInstructions(asmOp.mnemonic)
if (isaData.isEmpty()) {
return arrayOf(
manager.createProblemDescriptor(
asmOp,
INSTRUCTION_NOT_FOUND_MSG,
null as LocalQuickFix?,
ProblemHighlightType.ERROR,
isOnTheFly
)
)
}
if (asmInstruction.addressingModeList.isNotEmpty() && isaData.none { it.hasOps }) {
return arrayOf(
manager.createProblemDescriptor(
asmInstruction.addressingModeList.first(),
asmInstruction.addressingModeList.last(),
OPERANDS_UNEXPECTED_MSG_TEMPLATE.format(mnemonicWithSize),
ProblemHighlightType.ERROR,
isOnTheFly
)
)
}
val amOp1 = asmInstruction.addressingModeList.getOrNull(0)
val amOp2 = asmInstruction.addressingModeList.getOrNull(1)
val op1 = getAddressModeForType(amOp1)
val op2 = getAddressModeForType(amOp2)
val specialReg1 = (amOp1 as? M68kSpecialRegisterDirectAddressingMode)?.specialRegister?.text
val specialReg2 = (amOp2 as? M68kSpecialRegisterDirectAddressingMode)?.specialRegister?.text
val specialReg = specialReg1 ?: specialReg2
val opSize = asmOp.opSize
val matchingModeIsaData = findMatchingOpMode(isaData, op1, op2, opSize, specialReg)
if (matchingModeIsaData.isEmpty()) {
val matchingModeIsaDataIgnoringSize = findMatchingOpModeIgnoringSize(isaData, op1, op2, specialReg)
if (matchingModeIsaDataIgnoringSize.isEmpty()) {
val matchingModeIsaDataSwapped = findMatchingOpModeIgnoringSize(isaData, op2, op1, specialReg)
val supportedModesOp1 = isaData.flatMap { it.modes.flatMap { am -> am.op1 ?: emptySet() } }.toSet()
val supportedModesOp2 = isaData.flatMap { it.modes.flatMap { am -> am.op2 ?: emptySet() } }.toSet()
if (matchingModeIsaDataSwapped.isNotEmpty()) {
return arrayOf(
manager.createProblemDescriptor(
asmInstruction,
UNSUPPORTED_ADDRESSING_MODE_FLIP_MSG_TEMPLATE.format(mnemonicWithSize),
null as LocalQuickFix?, // TODO add flipping quickfix
ProblemHighlightType.ERROR,
isOnTheFly
)
)
}
if ((op2 != null)) {
if (supportedModesOp2.isEmpty()) {
return arrayOf(
manager.createProblemDescriptor(
asmInstruction.addressingModeList[1],
SECOND_OP_UNEXPECTED_MSG_TEMPLATE.format(mnemonicWithSize),
null as LocalQuickFix?,
ProblemHighlightType.ERROR,
isOnTheFly
)
)
}
if (supportedModesOp1.contains(op1) && !supportedModesOp2.contains(op2)) {
return arrayOf(
manager.createProblemDescriptor(
asmInstruction.addressingModeList[1],
UNSUPPORTED_ADDRESSING_MODE_OP2_MSG_TEMPLATE.format(mnemonicWithSize),
null as LocalQuickFix?,
ProblemHighlightType.ERROR,
isOnTheFly
)
)
}
if (supportedModesOp2.contains(op2) && !supportedModesOp1.contains(op1)) {
return arrayOf(
manager.createProblemDescriptor(
asmInstruction.addressingModeList[0],
UNSUPPORTED_ADDRESSING_MODE_OP1_MSG_TEMPLATE.format(mnemonicWithSize),
null as LocalQuickFix?,
ProblemHighlightType.ERROR,
isOnTheFly
)
)
}
}
return arrayOf(
manager.createProblemDescriptor(
asmInstruction.addressingModeList.firstOrNull() ?: asmInstruction,
asmInstruction.addressingModeList.lastOrNull() ?: asmInstruction,
UNSUPPORTED_ADDRESSING_MODE_MSG_TEMPLATE.format(mnemonicWithSize),
ProblemHighlightType.ERROR,
isOnTheFly
)
)
}
val supportedOpSizes = findSupportedOpSizes(matchingModeIsaDataIgnoringSize, op1, op2, specialReg)
return arrayOf(
when (supportedOpSizes) {
OP_UNSIZED ->
manager.createProblemDescriptor(
asmOp.operandSize ?: asmOp,
UNSUPPORTED_SIZE_UNSIZED_MSG_TEMPLATE.format(asmOp.mnemonic),
null as LocalQuickFix?, // TODO remove size quickfix?
ProblemHighlightType.ERROR,
isOnTheFly
)
OP_SIZE_B, OP_SIZE_W, OP_SIZE_L, OP_SIZE_WL, OP_SIZE_SBW ->
manager.createProblemDescriptor(
asmOp.operandSize ?: asmOp,
UNSUPPORTED_SIZE_HINT_MSG_TEMPLATE.format(M68kIsaUtil.findOpSizeDescription(supportedOpSizes)),
null as LocalQuickFix?, // TODO change size to .b?
ProblemHighlightType.ERROR,
isOnTheFly
)
else ->
manager.createProblemDescriptor(
asmOp.operandSize ?: asmOp,
UNSUPPORTED_SIZE_MSG_TEMPLATE.format(asmOp.mnemonic),
null as LocalQuickFix?, // TODO remove size quickfix?
ProblemHighlightType.ERROR,
isOnTheFly
)
}
)
}
return emptyArray()
}
}
@@ -0,0 +1,54 @@
package de.platon42.intellij.plugins.m68k.inspections
import com.intellij.codeInspection.InspectionManager
import com.intellij.codeInspection.ProblemDescriptor
import com.intellij.codeInspection.ProblemHighlightType
import com.intellij.psi.util.PsiTreeUtil
import de.platon42.intellij.plugins.m68k.asm.M68kIsa.findMatchingInstructions
import de.platon42.intellij.plugins.m68k.psi.*
import de.platon42.intellij.plugins.m68k.utils.M68kIsaUtil
import de.platon42.intellij.plugins.m68k.utils.M68kIsaUtil.findExactIsaDataAndAllowedAdrModeForInstruction
class M68kUnexpectedConditionalInstructionInspection : AbstractBaseM68kLocalInspectionTool() {
companion object {
private const val DISPLAY_NAME = "Unaffected condition codes before conditional instruction"
private const val UNAFFECTED_CONDITION_CODES_MSG_TEMPLATE = "Condition codes unaffected by instruction (%s - %s)"
}
override fun getDisplayName() = DISPLAY_NAME
override fun checkAsmInstruction(asmInstruction: M68kAsmInstruction, manager: InspectionManager, isOnTheFly: Boolean): Array<ProblemDescriptor>? {
val asmOp = asmInstruction.asmOp
if (asmInstruction.addressingModeList.isEmpty()) return emptyArray()
val isaDataCandidates = findMatchingInstructions(asmOp.mnemonic)
if (isaDataCandidates.isEmpty()) return emptyArray()
val (isaData, adrMode) = findExactIsaDataAndAllowedAdrModeForInstruction(asmInstruction) ?: return emptyArray()
if ((adrMode.affectedCc > 0) || (adrMode.testedCc > 0) || isaData.changesControlFlow) return emptyArray()
var currStatement = asmInstruction.parent as M68kStatement
while (true) {
currStatement = PsiTreeUtil.getNextSiblingOfType(currStatement, M68kStatement::class.java) ?: break
val globalLabel = PsiTreeUtil.findChildOfType(currStatement, M68kGlobalLabel::class.java)
if (globalLabel != null) break
if (PsiTreeUtil.findChildOfAnyType(currStatement, M68kMacroCall::class.java, M68kPreprocessorDirective::class.java) != null) break
val currAsmInstruction = PsiTreeUtil.getChildOfType(currStatement, M68kAsmInstruction::class.java) ?: continue
val (currIsaData, currAdrMode) = findExactIsaDataAndAllowedAdrModeForInstruction(currAsmInstruction) ?: break
val testedCc = M68kIsaUtil.getConcreteTestedCcFromMnemonic(currAsmInstruction.asmOp.mnemonic, currIsaData, currAdrMode)
if (testedCc == 0) break
return arrayOf(
manager.createProblemDescriptor(
asmInstruction,
asmInstruction,
UNAFFECTED_CONDITION_CODES_MSG_TEMPLATE.format(isaData.mnemonic, isaData.description),
ProblemHighlightType.WARNING,
isOnTheFly
)
)
}
return emptyArray()
}
}
@@ -0,0 +1,48 @@
package de.platon42.intellij.plugins.m68k.inspections
import com.intellij.codeInspection.LocalInspectionToolSession
import com.intellij.codeInspection.ProblemHighlightType
import com.intellij.codeInspection.ProblemsHolder
import com.intellij.psi.PsiElementVisitor
import com.intellij.psi.PsiPolyVariantReference
import de.platon42.intellij.plugins.m68k.psi.M68kMacroCall
import de.platon42.intellij.plugins.m68k.psi.M68kSymbolReference
import de.platon42.intellij.plugins.m68k.psi.M68kVisitor
import de.platon42.intellij.plugins.m68k.refs.M68kGlobalLabelSymbolReference
class M68kUnresolvedReferenceInspection : AbstractBaseM68kLocalInspectionTool() {
companion object {
private const val DISPLAY_NAME = "Unresolved label/symbol/macro reference"
}
override fun getDisplayName() = DISPLAY_NAME
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean, session: LocalInspectionToolSession): PsiElementVisitor {
return object : M68kVisitor() {
override fun visitMacroCall(macroCall: M68kMacroCall) {
val reference = macroCall.reference as? PsiPolyVariantReference ?: return
val resolve = reference.multiResolve(false)
if (resolve.isEmpty()) {
holder.registerProblem(reference)
}
}
override fun visitSymbolReference(symbolReference: M68kSymbolReference) {
val references = symbolReference.references ?: return
if (references.isEmpty()) return
val resolve = references.mapNotNull { it as? PsiPolyVariantReference }
.firstNotNullOfOrNull { it.multiResolve(false).ifEmpty { null } }
if (resolve == null) {
// TODO currently, because macro invocations are not evaluated, mark missing symbols only as weak warning
val makeWeak = references.any { it is M68kGlobalLabelSymbolReference }
if (makeWeak) {
holder.registerProblem(references.first(), ProblemHighlightType.WEAK_WARNING)
} else {
holder.registerProblem(references.first())
}
}
}
}
}
}
@@ -4,10 +4,12 @@ import com.intellij.psi.TokenType
import com.intellij.psi.tree.IElementType import com.intellij.psi.tree.IElementType
import de.platon42.intellij.plugins.m68k.asm.AssemblerDirectives import de.platon42.intellij.plugins.m68k.asm.AssemblerDirectives
import de.platon42.intellij.plugins.m68k.asm.M68kIsa.mnemonics import de.platon42.intellij.plugins.m68k.asm.M68kIsa.mnemonics
import de.platon42.intellij.plugins.m68k.psi.M68kTypes
object LexerUtil { object LexerUtil {
private val ASSIGNMENT_SEPARATORS = charArrayOf(' ', '\t', '=', ':') private val ASSIGNMENT_SEPARATORS = charArrayOf(' ', '\t', '=', ':')
private val TOKEN_SEPARATORS = charArrayOf(' ', '\t', ':')
@JvmStatic @JvmStatic
fun isAsmMnemonic(text: CharSequence) = mnemonics.contains(text.toString().lowercase()) fun isAsmMnemonic(text: CharSequence) = mnemonics.contains(text.toString().lowercase())
@@ -17,17 +19,28 @@ object LexerUtil {
&& text.dropLast(1).endsWith('.') && text.dropLast(1).endsWith('.')
&& mnemonics.contains(text.dropLast(2).toString().lowercase()) && mnemonics.contains(text.dropLast(2).toString().lowercase())
@JvmStatic
fun isEndDirective(text: CharSequence) = text.contentEquals("end", ignoreCase = true)
@JvmStatic @JvmStatic
fun isDataDirective(text: CharSequence) = AssemblerDirectives.dataDirectives.contains(text.toString().lowercase()) fun isDataDirective(text: CharSequence) = AssemblerDirectives.dataDirectives.contains(text.toString().lowercase())
@JvmStatic @JvmStatic
fun isOtherDirective(text: CharSequence) = AssemblerDirectives.otherDirective.contains(text.toString().lowercase()) fun isPlainDirective(text: CharSequence) = AssemblerDirectives.plainDirectives.contains(text.toString().lowercase())
@JvmStatic
fun isOtherDirective(text: CharSequence) = AssemblerDirectives.otherDirectives.contains(text.toString().lowercase())
@JvmStatic @JvmStatic
fun pushbackAssignment(text: CharSequence): Int { fun pushbackAssignment(text: CharSequence): Int {
return text.length - text.indexOfAny(ASSIGNMENT_SEPARATORS) return text.length - text.indexOfAny(ASSIGNMENT_SEPARATORS)
} }
@JvmStatic
fun pushbackAfterFirstToken(text: CharSequence): Int {
return text.length - text.indexOfAny(TOKEN_SEPARATORS)
}
@JvmStatic @JvmStatic
fun pushbackLabelColons(text: CharSequence): Int { fun pushbackLabelColons(text: CharSequence): Int {
return text.count { it == ':' } return text.count { it == ':' }
@@ -38,7 +51,37 @@ object LexerUtil {
if (!lexer.eatOneWhitespace && lexer.lexerPrefs.spaceIntroducesComment) { if (!lexer.eatOneWhitespace && lexer.lexerPrefs.spaceIntroducesComment) {
lexer.yybegin(_M68kLexer.WAITEOL) lexer.yybegin(_M68kLexer.WAITEOL)
} }
lexer.eatOneWhitespace = false; lexer.eatOneWhitespace = false
return TokenType.WHITE_SPACE return TokenType.WHITE_SPACE
} }
@JvmStatic
fun handleMacroMode(lexer: _M68kLexer): IElementType {
if (lexer.lexerPrefs.macroParametersUnparsed) {
lexer.yybegin(_M68kLexer.PLAINPARAMS)
} else {
lexer.yybegin(_M68kLexer.ASMOPS)
}
lexer.eatOneWhitespace = true
return M68kTypes.MACRO_INVOCATION
}
@JvmStatic
fun handleMacroLineEol(lexer: _M68kLexer): IElementType {
if (++lexer.macroLines > lexer.lexerPrefs.maxLinesPerMacro) {
lexer.yybegin(_M68kLexer.YYINITIAL)
return TokenType.BAD_CHARACTER
}
lexer.yybegin(_M68kLexer.MACROLINE)
return TokenType.WHITE_SPACE
}
fun unquoteString(string: String) = string.run {
when {
startsWith('"') -> removeSurrounding("\"")
startsWith('\'') -> removeSurrounding("'")
startsWith('<') -> removeSurrounding("<", ">")
else -> this
}
}
} }
@@ -2,7 +2,7 @@ package de.platon42.intellij.plugins.m68k.lexer
data class M68kLexerPrefs( data class M68kLexerPrefs(
var spaceIntroducesComment: Boolean = false, var spaceIntroducesComment: Boolean = false,
var maxLinesPerMacro: Int = 50, var maxLinesPerMacro: Int = 250,
var macroSectionUnparsed: Boolean = false, var macroSectionUnparsed: Boolean = false,
var macroParametersUnparsed: Boolean = true var macroParametersUnparsed: Boolean = true
) )
@@ -13,6 +13,9 @@ import static de.platon42.intellij.plugins.m68k.lexer.LexerUtil.*;
%{ %{
private M68kLexerPrefs lexerPrefs; private M68kLexerPrefs lexerPrefs;
boolean eatOneWhitespace = false; boolean eatOneWhitespace = false;
int macroLines = 0;
int exprState = 0;
int exprOpState = 0;
public M68kLexerPrefs getLexerPrefs() public M68kLexerPrefs getLexerPrefs()
{ {
@@ -23,6 +26,12 @@ import static de.platon42.intellij.plugins.m68k.lexer.LexerUtil.*;
this((java.io.Reader)null); this((java.io.Reader)null);
this.lexerPrefs = lexerPrefs; this.lexerPrefs = lexerPrefs;
} }
private void startExpr(int newExprState, int newExprOpState) {
exprState = newExprState;
exprOpState = newExprOpState;
yybegin(exprState);
}
%} %}
%public %public
@@ -38,10 +47,12 @@ WHITE_SPACE=\p{Blank}+
AREG=(a[0-6]) AREG=(a[0-6])
DREG=(d[0-7]) DREG=(d[0-7])
ASSIGNMENT=(([:letter:]|_)(([:letter:]|[:digit:])|_)*:?((\p{Blank}+equ\p{Blank}+)|(\p{Blank}+set\p{Blank}+)|\p{Blank}*=\p{Blank}*)) ASSIGNMENT=(([:letter:]|_)(([:letter:]|[:digit:])|_)*:?((\p{Blank}+equ\p{Blank}+)|(\p{Blank}+set\p{Blank}+)|\p{Blank}*=\p{Blank}*))
LOCAL_LABEL=(\.([:letter:]|_)(([:letter:]|[:digit:])|_)*:?)|(([:letter:]|_)(([:letter:]|[:digit:])|_)*\$:?) LOCAL_LABEL=(\.([:letter:]|_)([:letter:]|[:digit:]|_)*:?)|(([:letter:]|_)([:letter:]|[:digit:]|_)*\$:?)
LOCAL_LABEL_WC=(\.([:letter:]|_)(([:letter:]|[:digit:])|_)*:)|(([:letter:]|_)(([:letter:]|[:digit:])|_)*\$:) LOCAL_LABEL_WC=(\.([:letter:]|_)([:letter:]|[:digit:]|_)*:)|(([:letter:]|_)([:letter:]|[:digit:]|_)*\$:)
GLOBAL_LABEL=(([:letter:]|_)(([:letter:]|[:digit:])|_)*:?:?) GLOBAL_LABEL=(([:letter:]|_)([:letter:]|[:digit:]|_)*:?:?)
GLOBAL_LABEL_WC=(([:letter:]|_)(([:letter:]|[:digit:])|_)*::?) GLOBAL_LABEL_WC=(([:letter:]|_)([:letter:]|[:digit:]|_)*::?)
MACRO_DEF_LEFT=(([:letter:]|_)(([:letter:]|[:digit:]|_))*)(\p{Blank}+|:\p{Blank}*)macro\p{Blank}*
MACRO_END_TAG=\p{Blank}+endm\p{Blank}*[^;\r\n]*
//MNEMONIC=(([:letter:])+) //MNEMONIC=(([:letter:])+)
SYMBOL=(([:letter:]|_|\.)(([:letter:]|[:digit:]|[_\$]))*) SYMBOL=(([:letter:]|_|\.)(([:letter:]|[:digit:]|[_\$]))*)
BONUSSYMBOL=(([:letter:]|_|\.)(([:letter:]|[:digit:]|[_\$\.\\]))*) BONUSSYMBOL=(([:letter:]|_|\.)(([:letter:]|[:digit:]|[_\$\.\\]))*)
@@ -51,7 +62,7 @@ OPSIZE_BS=(\.[bs])
OPSIZE_W=(\.w) OPSIZE_W=(\.w)
OPSIZE_L=(\.l) OPSIZE_L=(\.l)
BINARY=(%[01]+) BINARY=(%[01]+)
HEXADECIMAL=(\$[0-9a-f]+) HEXADECIMAL=(\$[0-9a-fA-F]+)
OCTAL=(@[0-7]+) OCTAL=(@[0-7]+)
DECIMAL=([0-9]+) DECIMAL=([0-9]+)
STRINGLIT=(`([^`\\\r\n]|\\.)*`|'([^'\\\r\n]|\\.)*'|\"([^\"\\\r\n]|\\.)*\") STRINGLIT=(`([^`\\\r\n]|\\.)*`|'([^'\\\r\n]|\\.)*'|\"([^\"\\\r\n]|\\.)*\")
@@ -59,227 +70,162 @@ PLAINPARAM=(`([^`\\\r\n]|\\.)*`|'([^'\\\r\n]|\\.)*'|\"([^\"\\\r\n]|\\.)*\")|<([^
COMMENT=([;].*+) COMMENT=([;].*+)
HASH_COMMENT=([#;*].*+) HASH_COMMENT=([#;*].*+)
SKIP_TO_EOL=[^\r\n]+ SKIP_TO_EOL=[^\r\n]+
PLAIN_MACRO_LINE=[^;\r\n]+
%state NOSOL,INSTRPART,ASMINSTR,ASMOPS,ASMOPS_OP,ASSIGNMENT,EXPR,EXPR_OP,MACROCALL,WAITEOL %state NOSOL,INSTRPART,ASMINSTR,ASMOPS,ASMOPS_OP,ASSIGNMENT,EXPR,EXPR_OP,PLAINPARAMS,WAITEOL,MACRODEF,MACROLINE,MACROTERMINATION,MACROWAITEOL
%% %%
<YYINITIAL> { <YYINITIAL, NOSOL>
{WHITE_SPACE} { yybegin(NOSOL); eatOneWhitespace = false; return WHITE_SPACE; } {
{EOL} { return WHITE_SPACE; }
{ASSIGNMENT} { yybegin(ASSIGNMENT); eatOneWhitespace = true; yypushback(pushbackAssignment(yytext())); return SYMBOLDEF; }
{LOCAL_LABEL} { yybegin(INSTRPART); eatOneWhitespace = false; yypushback(pushbackLabelColons(yytext())); return LOCAL_LABEL_DEF; }
{GLOBAL_LABEL} { yybegin(INSTRPART); eatOneWhitespace = false; yypushback(pushbackLabelColons(yytext())); return GLOBAL_LABEL_DEF; }
{HASH_COMMENT} { return COMMENT; }
}
<NOSOL> {
{WHITE_SPACE} { return WHITE_SPACE; }
{EOL} { yybegin(YYINITIAL); return WHITE_SPACE; } {EOL} { yybegin(YYINITIAL); return WHITE_SPACE; }
{LOCAL_LABEL_WC} { yybegin(INSTRPART); yypushback(pushbackLabelColons(yytext())); return LOCAL_LABEL_DEF; }
{GLOBAL_LABEL_WC} { yybegin(INSTRPART); yypushback(pushbackLabelColons(yytext())); return GLOBAL_LABEL_DEF; }
{DIRECTIVE_KEYWORD} {
if(isAsmMnemonicWithSize(yytext())) { yybegin(ASMINSTR); yypushback(2); return MNEMONIC; }
if(isAsmMnemonic(yytext())) { yybegin(ASMINSTR); return MNEMONIC; }
if(isDataDirective(yytext())) { yybegin(EXPR); return DATA_DIRECTIVE; }
if(isOtherDirective(yytext())) { yybegin(EXPR); return OTHER_DIRECTIVE; }
yybegin(MACROCALL); eatOneWhitespace = true; return MACRO_INVOKATION;
}
// {MNEMONIC} { if(isAsmMnemonic(yytext())) { yybegin(ASMINSTR); return MNEMONIC; } else { yybegin(INSTRPART); return SYMBOL; } }
{MACRONAME} { yybegin(MACROCALL); eatOneWhitespace = true; return MACRO_INVOKATION; }
{HASH_COMMENT} { yybegin(YYINITIAL); return COMMENT; } {HASH_COMMENT} { yybegin(YYINITIAL); return COMMENT; }
} }
<INSTRPART> { <INSTRPART,ASMINSTR,PLAINPARAMS,ASSIGNMENT,EXPR,EXPR_OP,ASMOPS,ASMOPS_OP>
{WHITE_SPACE} { return WHITE_SPACE; } {
{EOL} { yybegin(YYINITIAL); return EOL; } {EOL} { yybegin(YYINITIAL); return EOL; }
":" { return COLON; }
{DIRECTIVE_KEYWORD} {
if(isAsmMnemonicWithSize(yytext())) { yybegin(ASMINSTR); yypushback(2); return MNEMONIC; }
if(isAsmMnemonic(yytext())) { yybegin(ASMINSTR); return MNEMONIC; }
if(isDataDirective(yytext())) { yybegin(EXPR); return DATA_DIRECTIVE; }
if(isOtherDirective(yytext())) { yybegin(EXPR); return OTHER_DIRECTIVE; }
yybegin(MACROCALL); eatOneWhitespace = true; return MACRO_INVOKATION;
}
// {MNEMONIC} { if(isAsmMnemonic(yytext())) { yybegin(ASMINSTR); return MNEMONIC; } else { return SYMBOL; } }
{MACRONAME} { yybegin(MACROCALL); eatOneWhitespace = true; return MACRO_INVOKATION; }
{COMMENT} { yybegin(WAITEOL); return COMMENT; } {COMMENT} { yybegin(WAITEOL); return COMMENT; }
} }
<NOSOL, INSTRPART, ASSIGNMENT>
{
{WHITE_SPACE} { return WHITE_SPACE; }
}
<PLAINPARAMS, EXPR, EXPR_OP, ASMOPS, ASMOPS_OP> {
{WHITE_SPACE} { return handleEolCommentWhitespace(this); }
}
<YYINITIAL> {
{WHITE_SPACE} { yybegin(NOSOL); eatOneWhitespace = false; return WHITE_SPACE; }
{ASSIGNMENT} { yybegin(ASSIGNMENT); eatOneWhitespace = true; yypushback(pushbackAssignment(yytext())); return SYMBOLDEF; }
{MACRO_DEF_LEFT} { yybegin(MACRODEF); yypushback(pushbackAfterFirstToken(yytext())); return MACRO_NAME; }
{LOCAL_LABEL} { yybegin(INSTRPART); eatOneWhitespace = false; yypushback(pushbackLabelColons(yytext())); return LOCAL_LABEL_DEF; }
{GLOBAL_LABEL} { yybegin(INSTRPART); eatOneWhitespace = false; yypushback(pushbackLabelColons(yytext())); return GLOBAL_LABEL_DEF; }
"." { yybegin(INSTRPART); eatOneWhitespace = false; return LOCAL_LABEL_DEF; }
}
<NOSOL> {
"macro" { yybegin(MACRODEF); return MACRO_TAG; }
{LOCAL_LABEL_WC} { yybegin(INSTRPART); yypushback(pushbackLabelColons(yytext())); return LOCAL_LABEL_DEF; }
{GLOBAL_LABEL_WC} { yybegin(INSTRPART); yypushback(pushbackLabelColons(yytext())); return GLOBAL_LABEL_DEF; }
// {MNEMONIC} { if(isAsmMnemonic(yytext())) { yybegin(ASMINSTR); return MNEMONIC; } else { yybegin(INSTRPART); return SYMBOL; } }
}
<NOSOL, INSTRPART>
{
{DIRECTIVE_KEYWORD} {
if(isAsmMnemonicWithSize(yytext())) { yybegin(ASMINSTR); yypushback(2); return MNEMONIC; }
if(isAsmMnemonic(yytext())) { yybegin(ASMINSTR); return MNEMONIC; }
//if(isEndDirective(yytext())) { yybegin(YYINITIAL); zzAtEOF = true; return null; }
if(isDataDirective(yytext())) { startExpr(EXPR, EXPR_OP); return DATA_DIRECTIVE; }
if(isPlainDirective(yytext())) { yybegin(PLAINPARAMS); return OTHER_DIRECTIVE; }
if(isOtherDirective(yytext())) { startExpr(EXPR, EXPR_OP); return OTHER_DIRECTIVE; }
return handleMacroMode(this);
}
{MACRONAME} { return handleMacroMode(this); }
}
<INSTRPART,MACRODEF> {
":" { return COLON; }
// {MNEMONIC} { if(isAsmMnemonic(yytext())) { yybegin(ASMINSTR); return MNEMONIC; } else { return SYMBOL; } }
}
<ASMINSTR> { <ASMINSTR> {
{WHITE_SPACE} { yybegin(ASMOPS); return WHITE_SPACE; } {WHITE_SPACE} { startExpr(ASMOPS, ASMOPS_OP); return WHITE_SPACE; }
{EOL} { yybegin(YYINITIAL); return EOL; }
{OPSIZE_BS} { return OPSIZE_BS; } {OPSIZE_BS} { return OPSIZE_BS; }
{OPSIZE_W} { return OPSIZE_W; } {OPSIZE_W} { return OPSIZE_W; }
{OPSIZE_L} { return OPSIZE_L; } {OPSIZE_L} { return OPSIZE_L; }
{COMMENT} { yybegin(WAITEOL); return COMMENT; }
} }
<MACROCALL> { <PLAINPARAMS> {
{WHITE_SPACE} { return handleEolCommentWhitespace(this); }
{EOL} { yybegin(YYINITIAL); return EOL; }
{COMMENT} { yybegin(WAITEOL); return COMMENT; }
"," { return SEPARATOR; } "," { return SEPARATOR; }
{PLAINPARAM} { return STRINGLIT; } {PLAINPARAM} { return STRINGLIT; }
} }
<ASSIGNMENT> { <ASSIGNMENT> {
{WHITE_SPACE} { return WHITE_SPACE; } "equ"|"set" { startExpr(EXPR, EXPR_OP); return EQU; }
{EOL} { yybegin(YYINITIAL); return EOL; }
"equ"|"set" { yybegin(EXPR); return EQU; }
":" { return COLON; } ":" { return COLON; }
"=" { yybegin(EXPR); return OP_ASSIGN; } "=" { startExpr(EXPR, EXPR_OP); return OP_ASSIGN; }
}
<EXPR, ASMOPS> {
{BINARY} { yybegin(exprOpState); return BINARY; }
{HEXADECIMAL} { yybegin(exprOpState); return HEXADECIMAL; }
{OCTAL} { yybegin(exprOpState); return OCTAL; }
{DECIMAL} { yybegin(exprOpState); return DECIMAL; }
{STRINGLIT} { yybegin(exprOpState); return STRINGLIT; }
"^" { return OP_BITWISE_XOR; }
"," { return SEPARATOR; }
"(" { return ROUND_L; }
")" { yybegin(exprOpState); return ROUND_R; }
"!" { return OP_UNARY_NOT; }
"~" { return OP_UNARY_COMPL; }
"+" { return OP_PLUS; }
"-" { return OP_MINUS; }
"*" { yybegin(exprOpState); return CURRENT_PC_SYMBOL; }
{COMMENT} { yybegin(WAITEOL); return COMMENT; }
} }
<EXPR> { <EXPR> {
{WHITE_SPACE} { return handleEolCommentWhitespace(this); } {BONUSSYMBOL} { yybegin(exprOpState); return SYMBOL; }
{EOL} { yybegin(YYINITIAL); return EOL; }
{BINARY} { yybegin(EXPR_OP); return BINARY; }
{HEXADECIMAL} { yybegin(EXPR_OP); return HEXADECIMAL; }
{OCTAL} { yybegin(EXPR_OP); return OCTAL; }
{DECIMAL} { yybegin(EXPR_OP); return DECIMAL; }
{STRINGLIT} { yybegin(EXPR_OP); return STRINGLIT; }
"^" { return OP_BITWISE_XOR; }
"," { return SEPARATOR; }
"(" { return ROUND_L; }
")" { yybegin(EXPR_OP); return ROUND_R; }
"!" { return OP_UNARY_NOT; }
"~" { return OP_UNARY_COMPL; }
"+" { return OP_PLUS; }
"-" { return OP_MINUS; }
"*" { yybegin(EXPR_OP); return CURRENT_PC_SYMBOL; }
{BONUSSYMBOL} { yybegin(EXPR_OP); return SYMBOL; }
{COMMENT} { yybegin(WAITEOL); return COMMENT; }
} }
<EXPR_OP> { <EXPR_OP, ASMOPS_OP> {
{WHITE_SPACE} { return handleEolCommentWhitespace(this); } "<<" { yybegin(exprState); return OP_AR_SHIFT_L; }
{EOL} { yybegin(YYINITIAL); return EOL; } ">>" { yybegin(exprState); return OP_AR_SHIFT_R; }
"&&" { yybegin(exprState); return OP_LOGICAL_AND; }
"||" { yybegin(exprState); return OP_LOGICAL_OR; }
"=="|"=" { yybegin(exprState); return OP_CMP_EQ; }
"<>"|"!=" { yybegin(exprState); return OP_CMP_NOT_EQ; }
">=" { yybegin(exprState); return OP_CMP_GT_EQ; }
"<=" { yybegin(exprState); return OP_CMP_LT_EQ; }
"<" { yybegin(exprState); return OP_CMP_LT; }
">" { yybegin(exprState); return OP_CMP_GT; }
"&" { yybegin(exprState); return OP_BITWISE_AND; }
"|"|"!" { yybegin(exprState); return OP_BITWISE_OR; }
"^" { yybegin(exprState); return OP_BITWISE_XOR; }
"<<" { yybegin(EXPR); return OP_AR_SHIFT_L; }
">>" { yybegin(EXPR); return OP_AR_SHIFT_R; }
"&&" { yybegin(EXPR); return OP_LOGICAL_AND; }
"||" { yybegin(EXPR); return OP_LOGICAL_OR; }
"=="|"=" { yybegin(EXPR); return OP_CMP_EQ; }
"<>"|"!=" { yybegin(EXPR); return OP_CMP_NOT_EQ; }
">=" { yybegin(EXPR); return OP_CMP_GT_EQ; }
"<=" { yybegin(EXPR); return OP_CMP_LT_EQ; }
"<" { yybegin(EXPR); return OP_CMP_LT; }
">" { yybegin(EXPR); return OP_CMP_GT; }
"&" { yybegin(EXPR); return OP_BITWISE_AND; }
"|"|"!" { yybegin(EXPR); return OP_BITWISE_OR; }
"^" { yybegin(EXPR); return OP_BITWISE_XOR; }
// ":" { return COLON; } // ":" { return COLON; }
// ";" { return SEMICOLON; } // ";" { return SEMICOLON; }
// "[" { return SQUARE_L; } // "[" { return SQUARE_L; }
// "]" { return SQUARE_R; } // "]" { return SQUARE_R; }
"," { yybegin(EXPR); return SEPARATOR; } "," { yybegin(exprState); return SEPARATOR; }
"(" { yybegin(EXPR); return ROUND_L; } "(" { yybegin(exprState); return ROUND_L; }
")" { return ROUND_R; } ")" { return ROUND_R; }
// "." { return DOT; } // "." { return DOT; }
// "$" { return DOLLAR; } // "$" { return DOLLAR; }
"~" { yybegin(EXPR); return OP_UNARY_COMPL; } "~" { yybegin(exprState); return OP_UNARY_COMPL; }
"+" { yybegin(EXPR); return OP_PLUS; } "+" { yybegin(exprState); return OP_PLUS; }
"-" { yybegin(EXPR); return OP_MINUS; } "-" { yybegin(exprState); return OP_MINUS; }
"*" { yybegin(EXPR); return OP_AR_MUL; } "*" { yybegin(exprState); return OP_AR_MUL; }
"%"|"//" { yybegin(EXPR); return OP_AR_MOD; } "%"|"//" { yybegin(exprState); return OP_AR_MOD; }
"/" { yybegin(EXPR); return OP_AR_DIV; } "/" { yybegin(exprState); return OP_AR_DIV; }
{COMMENT} { yybegin(WAITEOL); return COMMENT; }
} }
<ASMOPS> { <ASMOPS> {
{WHITE_SPACE} { return handleEolCommentWhitespace(this); } {AREG} { yybegin(exprOpState); return AREG; }
{EOL} { yybegin(YYINITIAL); return EOL; } {DREG} { yybegin(exprOpState); return DREG; }
"sp"|"a7" { yybegin(exprOpState); return REG_SP; }
{BINARY} { yybegin(ASMOPS_OP); return BINARY; } "pc" { yybegin(exprOpState); return PC; }
{HEXADECIMAL} { yybegin(ASMOPS_OP); return HEXADECIMAL; } "ccr" { yybegin(exprOpState); return REG_CCR; }
{OCTAL} { yybegin(ASMOPS_OP); return OCTAL; } "sr" { yybegin(exprOpState); return REG_SR; }
{DECIMAL} { yybegin(ASMOPS_OP); return DECIMAL; } "usp" { yybegin(exprOpState); return REG_USP; }
{STRINGLIT} { yybegin(ASMOPS_OP); return STRINGLIT; } "vbr" { yybegin(exprOpState); return REG_VBR; }
{AREG} { yybegin(ASMOPS_OP); return AREG; }
{DREG} { yybegin(ASMOPS_OP); return DREG; }
"sp"|"a7" { yybegin(ASMOPS_OP); return REG_SP; }
"pc" { yybegin(ASMOPS_OP); return PC; }
"ccr" { yybegin(ASMOPS_OP); return REG_CCR; }
"sr" { yybegin(ASMOPS_OP); return REG_SR; }
"usp" { yybegin(ASMOPS_OP); return REG_USP; }
"vbr" { yybegin(ASMOPS_OP); return REG_VBR; }
"^" { return OP_BITWISE_XOR; }
"," { return SEPARATOR; }
"(" { return ROUND_L; }
")" { yybegin(ASMOPS_OP); return ROUND_R; }
"!" { return OP_UNARY_NOT; }
"~" { return OP_UNARY_COMPL; }
"+" { return OP_PLUS; }
"-" { return OP_MINUS; }
"*" { yybegin(ASMOPS_OP); return CURRENT_PC_SYMBOL; }
"#" { return HASH; } "#" { return HASH; }
{SYMBOL} { yybegin(ASMOPS_OP); return SYMBOL; } {SYMBOL} { yybegin(exprOpState); return SYMBOL; }
{COMMENT} { yybegin(WAITEOL); return COMMENT; }
} }
<ASMOPS_OP> { <ASMOPS_OP> {
{WHITE_SPACE} { return handleEolCommentWhitespace(this); }
{EOL} { yybegin(YYINITIAL); return EOL; }
{OPSIZE_BS} { return OPSIZE_BS; } {OPSIZE_BS} { return OPSIZE_BS; }
{OPSIZE_W} { return OPSIZE_W; } {OPSIZE_W} { return OPSIZE_W; }
{OPSIZE_L} { return OPSIZE_L; } {OPSIZE_L} { return OPSIZE_L; }
"<<" { yybegin(ASMOPS); return OP_AR_SHIFT_L; }
">>" { yybegin(ASMOPS); return OP_AR_SHIFT_R; }
"&&" { yybegin(ASMOPS); return OP_LOGICAL_AND; }
"||" { yybegin(ASMOPS); return OP_LOGICAL_OR; }
"=="|"=" { yybegin(ASMOPS); return OP_CMP_EQ; }
"<>"|"!=" { yybegin(ASMOPS); return OP_CMP_NOT_EQ; }
">=" { yybegin(ASMOPS); return OP_CMP_GT_EQ; }
"<=" { yybegin(ASMOPS); return OP_CMP_LT_EQ; }
"<" { yybegin(ASMOPS); return OP_CMP_LT; }
">" { yybegin(ASMOPS); return OP_CMP_GT; }
"&" { yybegin(ASMOPS); return OP_BITWISE_AND; }
"|"|"!" { yybegin(ASMOPS); return OP_BITWISE_OR; }
"^" { yybegin(ASMOPS); return OP_BITWISE_XOR; }
// ":" { return COLON; }
// ";" { return SEMICOLON; }
// "[" { return SQUARE_L; }
// "]" { return SQUARE_R; }
"," { yybegin(ASMOPS); return SEPARATOR; }
"(" { yybegin(ASMOPS); return ROUND_L; }
")" { return ROUND_R; }
// "." { return DOT; }
// "$" { return DOLLAR; }
"~" { yybegin(ASMOPS); return OP_UNARY_COMPL; }
"+" { yybegin(ASMOPS); return OP_PLUS; }
"-" { yybegin(ASMOPS); return OP_MINUS; }
"*" { yybegin(ASMOPS); return OP_AR_MUL; }
"%"|"//" { yybegin(ASMOPS); return OP_AR_MOD; }
"/" { yybegin(ASMOPS); return OP_AR_DIV; }
{SYMBOL} { return SYMBOL; }
{COMMENT} { yybegin(WAITEOL); return COMMENT; }
} }
<WAITEOL> <WAITEOL>
@@ -288,4 +234,35 @@ SKIP_TO_EOL=[^\r\n]+
{SKIP_TO_EOL} { return COMMENT; } {SKIP_TO_EOL} { return COMMENT; }
} }
// The macro mess starts here
<MACRODEF> {
{WHITE_SPACE} { return WHITE_SPACE; }
{EOL} { yybegin(MACROLINE); macroLines = 0; return WHITE_SPACE; }
"macro" { return MACRO_TAG; }
{MACRONAME} { return MACRO_NAME; }
{COMMENT} { yybegin(MACROWAITEOL); return COMMENT; }
}
<MACROLINE> {
{EOL} { return handleMacroLineEol(this); }
{MACRO_END_TAG} { yybegin(MACROTERMINATION); return MACRO_END_TAG; }
{PLAIN_MACRO_LINE} { return MACRO_LINE; }
{COMMENT} { yybegin(MACROWAITEOL); return COMMENT; }
}
<MACROTERMINATION> {
{WHITE_SPACE} { return WHITE_SPACE; }
{EOL} { yybegin(YYINITIAL); return EOL; }
{COMMENT} { yybegin(WAITEOL); return COMMENT; }
}
<MACROWAITEOL>
{
{EOL} { return handleMacroLineEol(this); }
{SKIP_TO_EOL} { return COMMENT; }
}
[^] { return BAD_CHARACTER; } [^] { return BAD_CHARACTER; }
@@ -118,14 +118,13 @@
M68kFile ::= line* M68kFile ::= line*
private line ::= !<<eof>> statement (<<eof>>|EOL) private line ::= !<<eof>> (MacroDefinition | statement) (<<eof>>|EOL)
statement ::= (Assignment statement ::= (Assignment
| PreprocessorDirective
| LabelInsts) | LabelInsts)
{pin=1 recoverWhile=statement_recover}; {pin = 1 recoverWhile = statement_recover}
private statement_recover ::= !(EOL) private statement_recover ::= !(EOL) { consumeTokenMethod = "consumeTokenFast" }
SymbolDefinition ::= SYMBOLDEF { SymbolDefinition ::= SYMBOLDEF {
implements = "de.platon42.intellij.plugins.m68k.psi.M68kNamedElement" implements = "de.platon42.intellij.plugins.m68k.psi.M68kNamedElement"
@@ -140,8 +139,8 @@ Assignment ::= SymbolDefinition COLON? (OP_ASSIGN|EQU) expr
private LabelInsts ::= LabelWithInstruction | LabelOnly | InstructionOnly private LabelInsts ::= LabelWithInstruction | LabelOnly | InstructionOnly
private LabelOnly ::= Label private LabelOnly ::= Label
private LabelWithInstruction ::= Label Instruction private LabelWithInstruction ::= Label (Instruction|PreprocessorDirective)
private InstructionOnly ::= Instruction private InstructionOnly ::= (Instruction|PreprocessorDirective)
LocalLabel ::= LOCAL_LABEL_DEF COLON? { LocalLabel ::= LOCAL_LABEL_DEF COLON? {
name = "local label" name = "local label"
@@ -161,16 +160,43 @@ GlobalLabel ::= GLOBAL_LABEL_DEF COLON* {
private Label ::= LocalLabel | GlobalLabel private Label ::= LocalLabel | GlobalLabel
OperandSize ::= (OPSIZE_BS|OPSIZE_W|OPSIZE_L) { name = ".s|.b|.w|.l" } OperandSize ::= (OPSIZE_BS|OPSIZE_W|OPSIZE_L) {
name = ".s|.b|.w|.l"
methods = [getSize]
}
AddressSize ::= (OPSIZE_W|OPSIZE_L) { name = ".w|.l" } AddressSize ::= (OPSIZE_W|OPSIZE_L) { name = ".w|.l" }
DataWidth ::= (OPSIZE_W|OPSIZE_L) { name = ".w|.l" } DataWidth ::= (OPSIZE_W|OPSIZE_L) { name = ".w|.l" }
AsmOp ::= MNEMONIC OperandSize? AsmOp ::= MNEMONIC OperandSize? {
name = "mnemonic"
methods = [getMnemonic getOpSize]
}
PreprocessorDirective ::= Label? (DATA_DIRECTIVE | OTHER_DIRECTIVE) PreprocessorKeyword ::= (DATA_DIRECTIVE | OTHER_DIRECTIVE)
PreprocessorOperands?
PreprocessorDirective ::= PreprocessorKeyword PreprocessorOperands? {
mixin = "de.platon42.intellij.plugins.m68k.psi.M68kPreprocessorDirectiveMixin"
}
MacroPlainLine ::= MACRO_LINE
MacroNameDefinition ::= MACRO_NAME
MacroDefinition ::= ((MacroNameDefinition COLON? MACRO_TAG)|(MACRO_TAG MacroNameDefinition)) MacroPlainLine* MACRO_END_TAG {
pin = 1
name = "macro definition"
implements = "de.platon42.intellij.plugins.m68k.psi.M68kNamedElement"
mixin = "de.platon42.intellij.plugins.m68k.psi.M68kMacroDefinitionMixin"
elementTypeFactory = "de.platon42.intellij.plugins.m68k.stubs.M68kStubElementTypeFactory.stubFactory"
stubClass = "de.platon42.intellij.plugins.m68k.stubs.M68kMacroDefinitionStub"
methods = [getName setName getNameIdentifier]
}
MacroCall ::= MACRO_INVOCATION PlainOperands? {
mixin = "de.platon42.intellij.plugins.m68k.psi.M68kMacroCallMixin"
methods = [getMacroName]
}
MacroCall ::= MACRO_INVOKATION PlainOperands?
AsmInstruction ::= AsmOp AsmOperands? AsmInstruction ::= AsmOp AsmOperands?
private Instruction ::= AsmInstruction | MacroCall private Instruction ::= AsmInstruction | MacroCall
//external Instruction ::= parseMacroCallOrAsmInstruction //external Instruction ::= parseMacroCallOrAsmInstruction
@@ -180,7 +206,7 @@ private AsmOperands ::= AddressingMode (SEPARATOR AddressingMode)?
private PreprocessorOperands ::= PreprocessorOperand (SEPARATOR PreprocessorOperand)* private PreprocessorOperands ::= PreprocessorOperand (SEPARATOR PreprocessorOperand)*
private PreprocessorOperand ::= expr private PreprocessorOperand ::= expr
private PlainOperands ::= STRINGLIT (SEPARATOR STRINGLIT)* private PlainOperands ::= (expr|AddressingMode) (SEPARATOR (expr|AddressingMode))*
// TODO This should probably be a ILazyParseableElementType, no idea how to implement that yet // TODO This should probably be a ILazyParseableElementType, no idea how to implement that yet
SymbolReference ::= SYMBOL { SymbolReference ::= SYMBOL {
@@ -210,6 +236,14 @@ Register ::= DataRegister | AddressRegister | SpecialRegister
private DataOrAddressRegister ::= DataRegister | AddressRegister { name = "data or address register"} private DataOrAddressRegister ::= DataRegister | AddressRegister { name = "data or address register"}
IndexRegister ::= DataOrAddressRegister DataWidth?
{
name = "index register"
methods = [
isLongWidth
]
}
AddressingMode ::= ImmediateData AddressingMode ::= ImmediateData
| AddressRegisterIndirectPreDecAddressingMode | AddressRegisterIndirectPreDecAddressingMode
| AddressRegisterIndirectPostIncAddressingMode | AddressRegisterIndirectPostIncAddressingMode
@@ -231,20 +265,108 @@ AddressingMode ::= ImmediateData
SpecialRegisterDirectAddressingMode ::= SpecialRegister SpecialRegisterDirectAddressingMode ::= SpecialRegister
DataRegisterDirectAddressingMode ::= DataRegister !(OP_MINUS|OP_AR_DIV) DataRegisterDirectAddressingMode ::= DataRegister !(OP_MINUS|OP_AR_DIV)
AddressRegisterDirectAddressingMode ::= AddressRegister !(OP_MINUS|OP_AR_DIV) AddressRegisterDirectAddressingMode ::= AddressRegister !(OP_MINUS|OP_AR_DIV)
AddressRegisterIndirectAddressingMode ::= ROUND_L AddressRegister ROUND_R !OP_PLUS AddressRegisterIndirectAddressingMode ::= ROUND_L AddressRegister ROUND_R !OP_PLUS { implements = "de.platon42.intellij.plugins.m68k.psi.M68kWithAddressRegisterIndirect" }
AddressRegisterIndirectPostIncAddressingMode ::= ROUND_L AddressRegister ROUND_R OP_PLUS AddressRegisterIndirectPostIncAddressingMode ::= ROUND_L AddressRegister ROUND_R OP_PLUS { implements = "de.platon42.intellij.plugins.m68k.psi.M68kWithAddressRegisterIndirect" }
AddressRegisterIndirectPreDecAddressingMode ::= OP_MINUS ROUND_L AddressRegister ROUND_R AddressRegisterIndirectPreDecAddressingMode ::= OP_MINUS ROUND_L AddressRegister ROUND_R { implements = "de.platon42.intellij.plugins.m68k.psi.M68kWithAddressRegisterIndirect" }
AddressRegisterIndirectWithDisplacementOldAddressingMode ::= expr ROUND_L AddressRegister ROUND_R AddressRegisterIndirectWithDisplacementOldAddressingMode ::= expr ROUND_L AddressRegister ROUND_R
{
implements = [
"de.platon42.intellij.plugins.m68k.psi.M68kWithAddressRegisterIndirect"
"de.platon42.intellij.plugins.m68k.psi.M68kWithDisplacement"
]
methods = [
displacement = "expr"
]
}
AddressRegisterIndirectWithDisplacementNewAddressingMode ::= ROUND_L expr SEPARATOR AddressRegister ROUND_R AddressRegisterIndirectWithDisplacementNewAddressingMode ::= ROUND_L expr SEPARATOR AddressRegister ROUND_R
AddressRegisterIndirectWithIndexOldAddressingMode ::= expr? ROUND_L AddressRegister SEPARATOR DataOrAddressRegister DataWidth? ROUND_R {
AddressRegisterIndirectWithIndexNewAddressingMode ::= ROUND_L (expr SEPARATOR)? AddressRegister SEPARATOR DataOrAddressRegister DataWidth? ROUND_R implements = [
"de.platon42.intellij.plugins.m68k.psi.M68kWithAddressRegisterIndirect"
"de.platon42.intellij.plugins.m68k.psi.M68kWithDisplacement"
]
methods = [
displacement = "expr"
]
}
AddressRegisterIndirectWithIndexOldAddressingMode ::= expr? ROUND_L AddressRegister SEPARATOR IndexRegister ROUND_R
{
implements = [
"de.platon42.intellij.plugins.m68k.psi.M68kWithAddressRegisterIndirect"
"de.platon42.intellij.plugins.m68k.psi.M68kWithDisplacement"
"de.platon42.intellij.plugins.m68k.psi.M68kWithIndexRegister"
]
methods = [
displacement = "expr"
]
}
AddressRegisterIndirectWithIndexNewAddressingMode ::= ROUND_L (expr SEPARATOR)? AddressRegister SEPARATOR IndexRegister ROUND_R
{
implements = [
"de.platon42.intellij.plugins.m68k.psi.M68kWithAddressRegisterIndirect"
"de.platon42.intellij.plugins.m68k.psi.M68kWithDisplacement"
"de.platon42.intellij.plugins.m68k.psi.M68kWithIndexRegister"
]
methods = [
displacement = "expr"
]
}
ProgramCounterIndirectWithDisplacementOldAddressingMode ::= (ROUND_L PC ROUND_R) | (expr ROUND_L PC ROUND_R) ProgramCounterIndirectWithDisplacementOldAddressingMode ::= (ROUND_L PC ROUND_R) | (expr ROUND_L PC ROUND_R)
{
implements = ["de.platon42.intellij.plugins.m68k.psi.M68kWithDisplacement"]
methods = [
displacement = "expr"
]
}
ProgramCounterIndirectWithDisplacementNewAddressingMode ::= ROUND_L expr SEPARATOR PC ROUND_R ProgramCounterIndirectWithDisplacementNewAddressingMode ::= ROUND_L expr SEPARATOR PC ROUND_R
ProgramCounterIndirectWithIndexOldAddressingMode ::= expr? ROUND_L PC SEPARATOR DataOrAddressRegister DataWidth? ROUND_R {
ProgramCounterIndirectWithIndexNewAddressingMode ::= ROUND_L (expr SEPARATOR)? PC SEPARATOR DataOrAddressRegister DataWidth? ROUND_R implements = ["de.platon42.intellij.plugins.m68k.psi.M68kWithDisplacement"]
methods = [
displacement = "expr"
]
}
ProgramCounterIndirectWithIndexOldAddressingMode ::= expr? ROUND_L PC SEPARATOR IndexRegister ROUND_R
{
implements = [
"de.platon42.intellij.plugins.m68k.psi.M68kWithDisplacement"
"de.platon42.intellij.plugins.m68k.psi.M68kWithIndexRegister"
]
methods = [
displacement = "expr"
]
}
ProgramCounterIndirectWithIndexNewAddressingMode ::= ROUND_L (expr SEPARATOR)? PC SEPARATOR IndexRegister ROUND_R
{
implements = [
"de.platon42.intellij.plugins.m68k.psi.M68kWithDisplacement"
"de.platon42.intellij.plugins.m68k.psi.M68kWithIndexRegister"
]
methods = [
displacement = "expr"
]
}
AbsoluteAddressAddressingMode ::= expr AddressSize? !ROUND_L AbsoluteAddressAddressingMode ::= expr AddressSize? !ROUND_L
private RegisterRange ::= (DataOrAddressRegister OP_MINUS DataOrAddressRegister)
RegisterListAddressingMode ::= (DataOrAddressRegister|RegisterRange) ((OP_AR_DIV|OP_MINUS) (DataOrAddressRegister|RegisterRange))* RegisterRange ::= (DataRegister OP_MINUS DataRegister) | (AddressRegister OP_MINUS AddressRegister) | (DataRegister OP_MINUS AddressRegister) {
name = "register range"
methods = [
startRegister = "Register[0]"
endRegister = "Register[1]"
]
}
RegisterListAddressingMode ::= (RegisterRange|DataOrAddressRegister) (OP_AR_DIV (RegisterRange|DataOrAddressRegister))*
{
name = "register list"
methods = [ getRegisters ]
}
ImmediateData ::= HASH expr { ImmediateData ::= HASH expr {
name = "immediate data" name = "immediate data"
extends = AddressingMode extends = AddressingMode
@@ -0,0 +1,65 @@
package de.platon42.intellij.plugins.m68k.psi
import de.platon42.intellij.plugins.m68k.asm.*
object M68kAddressModeUtil {
fun getAddressModeForType(addressingMode: M68kAddressingMode?): AddressMode? {
if (addressingMode == null) return null
return when (addressingMode) {
is M68kImmediateData -> AddressMode.IMMEDIATE_DATA
is M68kAddressRegisterIndirectAddressingMode -> AddressMode.ADDRESS_REGISTER_INDIRECT
is M68kAddressRegisterIndirectPostIncAddressingMode -> AddressMode.ADDRESS_REGISTER_INDIRECT_POST_INC
is M68kAddressRegisterIndirectPreDecAddressingMode -> AddressMode.ADDRESS_REGISTER_INDIRECT_PRE_DEC
is M68kAddressRegisterIndirectWithDisplacementNewAddressingMode -> AddressMode.ADDRESS_REGISTER_INDIRECT_WITH_DISPLACEMENT
is M68kAddressRegisterIndirectWithDisplacementOldAddressingMode -> AddressMode.ADDRESS_REGISTER_INDIRECT_WITH_DISPLACEMENT
is M68kAddressRegisterIndirectWithIndexNewAddressingMode -> AddressMode.ADDRESS_REGISTER_INDIRECT_WITH_INDEX
is M68kAddressRegisterIndirectWithIndexOldAddressingMode -> AddressMode.ADDRESS_REGISTER_INDIRECT_WITH_INDEX
is M68kProgramCounterIndirectWithDisplacementNewAddressingMode -> AddressMode.PROGRAM_COUNTER_INDIRECT_WITH_DISPLACEMENT
is M68kProgramCounterIndirectWithDisplacementOldAddressingMode -> AddressMode.PROGRAM_COUNTER_INDIRECT_WITH_DISPLACEMENT
is M68kProgramCounterIndirectWithIndexNewAddressingMode -> AddressMode.PROGRAM_COUNTER_INDIRECT_WITH_INDEX
is M68kProgramCounterIndirectWithIndexOldAddressingMode -> AddressMode.PROGRAM_COUNTER_INDIRECT_WITH_INDEX
is M68kSpecialRegisterDirectAddressingMode -> AddressMode.SPECIAL_REGISTER_DIRECT
is M68kDataRegisterDirectAddressingMode -> AddressMode.DATA_REGISTER_DIRECT
is M68kAddressRegisterDirectAddressingMode -> AddressMode.ADDRESS_REGISTER_DIRECT
is M68kRegisterListAddressingMode -> AddressMode.REGISTER_LIST
is M68kAbsoluteAddressAddressingMode -> AddressMode.ABSOLUTE_ADDRESS
else -> throw IllegalArgumentException("Unknown addressing mode $addressingMode")
}
}
fun getOtherReadWriteModifyRegisters(rwm: Int): List<Pair<Register, Int>> {
if (rwm and RWM_MODIFY_STACK > 0) {
return listOf(Register.A7 to RWM_MODIFY_L)
}
return emptyList()
}
fun getReadWriteModifyRegisters(addressingMode: M68kAddressingMode?, rwm: Int): List<Pair<Register, Int>> {
if (addressingMode == null) return emptyList()
return when (addressingMode) {
is M68kImmediateData,
is M68kSpecialRegisterDirectAddressingMode,
is M68kProgramCounterIndirectWithDisplacementNewAddressingMode,
is M68kProgramCounterIndirectWithDisplacementOldAddressingMode,
is M68kAbsoluteAddressAddressingMode -> emptyList()
is M68kAddressRegisterIndirectPostIncAddressingMode -> listOf(Register.getRegFromName(addressingMode.addressRegister.text) to (RWM_READ_L or RWM_MODIFY_L))
is M68kAddressRegisterIndirectPreDecAddressingMode -> listOf(Register.getRegFromName(addressingMode.addressRegister.text) to (RWM_READ_L or RWM_MODIFY_L))
is M68kWithAddressRegisterIndirect -> {
if (addressingMode is M68kWithIndexRegister) {
listOf(
Register.getRegFromName(addressingMode.addressRegister.text) to RWM_READ_L,
Register.getRegFromName(addressingMode.indexRegister.register.text) to if (addressingMode.indexRegister.isLongWidth) RWM_READ_L else RWM_READ_W
)
} else {
listOf(Register.getRegFromName(addressingMode.addressRegister.text) to RWM_READ_L)
}
}
is M68kWithIndexRegister -> listOf(Register.getRegFromName(addressingMode.indexRegister.register.text) to if (addressingMode.indexRegister.isLongWidth) RWM_READ_L else RWM_READ_W)
is M68kDataRegisterDirectAddressingMode -> listOf(Register.getRegFromName(addressingMode.dataRegister.text) to rwm)
is M68kAddressRegisterDirectAddressingMode -> listOf(Register.getRegFromName(addressingMode.addressRegister.text) to rwm)
is M68kRegisterListAddressingMode -> addressingMode.registers.map { it to rwm }
else -> throw IllegalArgumentException("Unknown addressing mode $addressingMode")
}
}
}
@@ -27,6 +27,21 @@ object M68kElementFactory {
return PsiTreeUtil.findChildOfType(file, M68kSymbolReference::class.java)!! return PsiTreeUtil.findChildOfType(file, M68kSymbolReference::class.java)!!
} }
fun createMacroDefinition(project: Project, name: String): M68kMacroDefinition {
val file = createFile(project, "$name macro\nendm\n")
return PsiTreeUtil.findChildOfType(file, M68kMacroDefinition::class.java)!!
}
fun createMacroCall(project: Project, name: String): M68kMacroCall {
val file = createFile(project, " $name\n")
return PsiTreeUtil.findChildOfType(file, M68kMacroCall::class.java)!!
}
fun createIncludeStatement(project: Project, path: String): M68kPreprocessorDirective {
val file = createFile(project, " include \"$path\"\n")
return PsiTreeUtil.findChildOfType(file, M68kPreprocessorDirective::class.java)!!
}
fun createFile(project: Project, content: String): M68kFile { fun createFile(project: Project, content: String): M68kFile {
return PsiFileFactory.getInstance(project).createFileFromText("dummy.m68k", INSTANCE, content) as M68kFile return PsiFileFactory.getInstance(project).createFileFromText("dummy.m68k", INSTANCE, content) as M68kFile
} }
@@ -2,21 +2,13 @@ package de.platon42.intellij.plugins.m68k.psi
import com.intellij.extapi.psi.ASTWrapperPsiElement import com.intellij.extapi.psi.ASTWrapperPsiElement
import com.intellij.lang.ASTNode import com.intellij.lang.ASTNode
import de.platon42.intellij.plugins.m68k.lexer.LexerUtil
abstract class M68kLiteralExprMixin(node: ASTNode) : ASTWrapperPsiElement(node), M68kLiteralExpr { abstract class M68kLiteralExprMixin(node: ASTNode) : ASTWrapperPsiElement(node), M68kLiteralExpr {
override fun getValue(): Any? { override fun getValue(): Any? {
val childNode = firstChild.node val childNode = firstChild.node
when (childNode.elementType) { when (childNode.elementType) {
M68kTypes.STRINGLIT -> { M68kTypes.STRINGLIT -> LexerUtil.unquoteString(childNode.text)
return text.run {
when {
startsWith('"') -> removeSurrounding("\"")
startsWith('\'') -> removeSurrounding("'")
startsWith('<') -> removeSurrounding(">")
else -> this
}
}
}
M68kTypes.DECIMAL -> { M68kTypes.DECIMAL -> {
try { try {
return childNode.text.toInt() return childNode.text.toInt()
@@ -46,6 +38,6 @@ abstract class M68kLiteralExprMixin(node: ASTNode) : ASTWrapperPsiElement(node),
} }
} }
} }
return text return childNode.text
} }
} }
@@ -5,12 +5,13 @@ import com.intellij.psi.search.GlobalSearchScope
import com.intellij.psi.stubs.StubIndex import com.intellij.psi.stubs.StubIndex
import com.intellij.psi.util.PsiTreeUtil import com.intellij.psi.util.PsiTreeUtil
import de.platon42.intellij.plugins.m68k.stubs.M68kGlobalLabelStubIndex import de.platon42.intellij.plugins.m68k.stubs.M68kGlobalLabelStubIndex
import de.platon42.intellij.plugins.m68k.stubs.M68kMacroDefinitionStubIndex
import de.platon42.intellij.plugins.m68k.stubs.M68kSymbolDefinitionStubIndex import de.platon42.intellij.plugins.m68k.stubs.M68kSymbolDefinitionStubIndex
object M68kLookupUtil { object M68kLookupUtil {
fun findAllGlobalLabels(project: Project): List<M68kGlobalLabel> { fun findAllGlobalLabels(project: Project): List<M68kGlobalLabel> {
val results: MutableList<M68kGlobalLabel> = ArrayList() val results = ArrayList<M68kGlobalLabel>()
StubIndex.getInstance().processAllKeys(M68kGlobalLabelStubIndex.KEY, project) StubIndex.getInstance().processAllKeys(M68kGlobalLabelStubIndex.KEY, project)
{ {
results.addAll(StubIndex.getElements(M68kGlobalLabelStubIndex.KEY, it, project, GlobalSearchScope.allScope(project), M68kGlobalLabel::class.java)) results.addAll(StubIndex.getElements(M68kGlobalLabelStubIndex.KEY, it, project, GlobalSearchScope.allScope(project), M68kGlobalLabel::class.java))
@@ -20,7 +21,7 @@ object M68kLookupUtil {
} }
fun findAllGlobalLabels(file: M68kFile): List<M68kGlobalLabel> { fun findAllGlobalLabels(file: M68kFile): List<M68kGlobalLabel> {
val results: MutableList<M68kGlobalLabel> = ArrayList() val results = ArrayList<M68kGlobalLabel>()
StubIndex.getInstance().processAllKeys( StubIndex.getInstance().processAllKeys(
M68kGlobalLabelStubIndex.KEY, M68kGlobalLabelStubIndex.KEY,
{ {
@@ -43,7 +44,7 @@ object M68kLookupUtil {
fun findAllLocalLabels(globalLabel: M68kGlobalLabel): List<M68kLocalLabel> { fun findAllLocalLabels(globalLabel: M68kGlobalLabel): List<M68kLocalLabel> {
val statement = PsiTreeUtil.getStubOrPsiParentOfType(globalLabel, M68kStatement::class.java)!! val statement = PsiTreeUtil.getStubOrPsiParentOfType(globalLabel, M68kStatement::class.java)!!
val results: MutableList<M68kLocalLabel> = ArrayList() val results = ArrayList<M68kLocalLabel>()
var currentStatement = PsiTreeUtil.getNextSiblingOfType(statement, M68kStatement::class.java) var currentStatement = PsiTreeUtil.getNextSiblingOfType(statement, M68kStatement::class.java)
while (currentStatement != null) { while (currentStatement != null) {
val child = currentStatement.firstChild val child = currentStatement.firstChild
@@ -55,7 +56,7 @@ object M68kLookupUtil {
} }
fun findAllSymbolDefinitions(project: Project): List<M68kSymbolDefinition> { fun findAllSymbolDefinitions(project: Project): List<M68kSymbolDefinition> {
val results: MutableList<M68kSymbolDefinition> = ArrayList() val results = ArrayList<M68kSymbolDefinition>()
StubIndex.getInstance().processAllKeys(M68kSymbolDefinitionStubIndex.KEY, project) StubIndex.getInstance().processAllKeys(M68kSymbolDefinitionStubIndex.KEY, project)
{ {
results.addAll( results.addAll(
@@ -73,7 +74,7 @@ object M68kLookupUtil {
} }
fun findAllSymbolDefinitions(file: M68kFile): List<M68kSymbolDefinition> { fun findAllSymbolDefinitions(file: M68kFile): List<M68kSymbolDefinition> {
val results: MutableList<M68kSymbolDefinition> = ArrayList() val results = ArrayList<M68kSymbolDefinition>()
StubIndex.getInstance().processAllKeys( StubIndex.getInstance().processAllKeys(
M68kSymbolDefinitionStubIndex.KEY, M68kSymbolDefinitionStubIndex.KEY,
{ {
@@ -93,4 +94,45 @@ object M68kLookupUtil {
} }
fun findAllSymbolDefinitionNames(project: Project): Collection<String> = StubIndex.getInstance().getAllKeys(M68kSymbolDefinitionStubIndex.KEY, project) fun findAllSymbolDefinitionNames(project: Project): Collection<String> = StubIndex.getInstance().getAllKeys(M68kSymbolDefinitionStubIndex.KEY, project)
fun findAllMacroDefinitions(project: Project): List<M68kMacroDefinition> {
val results = ArrayList<M68kMacroDefinition>()
StubIndex.getInstance().processAllKeys(M68kMacroDefinitionStubIndex.KEY, project)
{
results.addAll(
StubIndex.getElements(
M68kMacroDefinitionStubIndex.KEY,
it,
project,
GlobalSearchScope.allScope(project),
M68kMacroDefinition::class.java
)
)
true
}
return results
}
fun findAllMacroDefinitions(file: M68kFile): List<M68kMacroDefinition> {
val results = ArrayList<M68kMacroDefinition>()
StubIndex.getInstance().processAllKeys(
M68kMacroDefinitionStubIndex.KEY,
{
results.addAll(
StubIndex.getElements(
M68kMacroDefinitionStubIndex.KEY,
it,
file.project,
GlobalSearchScope.fileScope(file),
M68kMacroDefinition::class.java
)
)
true
}, GlobalSearchScope.fileScope(file), null
)
return results
}
fun findAllMacroDefinitionNames(project: Project): Collection<String> = StubIndex.getInstance().getAllKeys(M68kMacroDefinitionStubIndex.KEY, project)
} }
@@ -0,0 +1,17 @@
package de.platon42.intellij.plugins.m68k.psi
import com.intellij.extapi.psi.ASTWrapperPsiElement
import com.intellij.lang.ASTNode
import com.intellij.psi.PsiReference
import com.intellij.psi.impl.source.resolve.reference.ReferenceProvidersRegistry
abstract class M68kMacroCallMixin(node: ASTNode) : ASTWrapperPsiElement(node), M68kMacroCall {
override fun getReference(): PsiReference? {
return references.firstOrNull()
}
override fun getReferences(): Array<PsiReference> {
return ReferenceProvidersRegistry.getReferencesFromProviders(this)
}
}
@@ -0,0 +1,29 @@
package de.platon42.intellij.plugins.m68k.psi
import com.intellij.extapi.psi.StubBasedPsiElementBase
import com.intellij.ide.projectView.PresentationData
import com.intellij.lang.ASTNode
import com.intellij.navigation.ItemPresentation
import com.intellij.psi.stubs.IStubElementType
import de.platon42.intellij.plugins.m68k.M68kIcons
import de.platon42.intellij.plugins.m68k.stubs.M68kMacroDefinitionStub
import javax.swing.Icon
abstract class M68kMacroDefinitionMixin : StubBasedPsiElementBase<M68kMacroDefinitionStub>, M68kMacroDefinition {
constructor(node: ASTNode) : super(node)
constructor(stub: M68kMacroDefinitionStub, nodeType: IStubElementType<*, *>) : super(stub, nodeType)
override fun getPresentation(): ItemPresentation? {
return PresentationData(name, containingFile.name, getIcon(0), null)
}
override fun getIcon(flags: Int): Icon? {
return M68kIcons.MACRO_DEF
}
override fun toString(): String {
return javaClass.simpleName + "(MACRO_DEFINITION)"
}
}
@@ -0,0 +1,17 @@
package de.platon42.intellij.plugins.m68k.psi
import com.intellij.extapi.psi.ASTWrapperPsiElement
import com.intellij.lang.ASTNode
import com.intellij.psi.PsiReference
import com.intellij.psi.impl.source.resolve.reference.ReferenceProvidersRegistry
abstract class M68kPreprocessorDirectiveMixin(node: ASTNode) : ASTWrapperPsiElement(node), M68kPreprocessorDirective {
override fun getReference(): PsiReference? {
return references.firstOrNull()
}
override fun getReferences(): Array<PsiReference> {
return ReferenceProvidersRegistry.getReferencesFromProviders(this)
}
}
@@ -2,8 +2,10 @@ package de.platon42.intellij.plugins.m68k.psi
import com.intellij.psi.PsiElement import com.intellij.psi.PsiElement
import com.intellij.util.IncorrectOperationException import com.intellij.util.IncorrectOperationException
import de.platon42.intellij.plugins.m68k.asm.*
import de.platon42.intellij.plugins.m68k.psi.M68kElementFactory.createGlobalLabel import de.platon42.intellij.plugins.m68k.psi.M68kElementFactory.createGlobalLabel
import de.platon42.intellij.plugins.m68k.psi.M68kElementFactory.createLocalLabel import de.platon42.intellij.plugins.m68k.psi.M68kElementFactory.createLocalLabel
import de.platon42.intellij.plugins.m68k.psi.M68kElementFactory.createMacroDefinition
import de.platon42.intellij.plugins.m68k.psi.M68kElementFactory.createSymbolDefinition import de.platon42.intellij.plugins.m68k.psi.M68kElementFactory.createSymbolDefinition
object M68kPsiImplUtil { object M68kPsiImplUtil {
@@ -27,7 +29,7 @@ object M68kPsiImplUtil {
// Local Label // Local Label
@JvmStatic @JvmStatic
fun getName(element: M68kLocalLabel): String? = element.firstChild.text fun getName(element: M68kLocalLabel): String? = element.firstChild?.text
@JvmStatic @JvmStatic
fun setName(element: M68kLocalLabel, name: String): PsiElement { fun setName(element: M68kLocalLabel, name: String): PsiElement {
@@ -71,4 +73,71 @@ object M68kPsiImplUtil {
val text = element.firstChild.text val text = element.firstChild.text
return text.startsWith('.') || text.endsWith('$') return text.startsWith('.') || text.endsWith('$')
} }
}
// Macro Definition
@JvmStatic
fun getName(element: M68kMacroDefinition): String? = element.macroNameDefinition.firstChild.text
@JvmStatic
fun setName(element: M68kMacroDefinition, name: String): PsiElement {
val nameNode = element.macroNameDefinition
val newMacroDefinition = createMacroDefinition(element.project, name)
nameNode.replace(newMacroDefinition.firstChild)
return element
}
@JvmStatic
fun getNameIdentifier(element: M68kMacroDefinition): PsiElement = element.firstChild
// Macro Call
@JvmStatic
fun getMacroName(element: M68kMacroCall): String = element.firstChild.text
// AsmOp
@JvmStatic
fun getMnemonic(element: M68kAsmOp): String = element.firstChild.text
@JvmStatic
fun getOpSize(element: M68kAsmOp): Int = element.operandSize?.size ?: OP_UNSIZED
// OperandSize
@JvmStatic
fun getSize(element: M68kOperandSize): Int =
when (element.text) {
null -> OP_UNSIZED
".w" -> OP_SIZE_W
".l" -> OP_SIZE_L
".b" -> OP_SIZE_B
".s" -> OP_SIZE_S
else -> throw IllegalArgumentException("Unknown op size ${element.text}")
}
// RegisterListAddressingMode
@JvmStatic
fun getRegisters(element: M68kRegisterListAddressingMode): Set<Register> {
val registers = HashSet<Register>()
element.registerList.forEach { registers.add(Register.getRegFromName(it.text)) }
element.registerRangeList.forEach {
var startReg = Register.getRegFromName(it.startRegister.text)
val endReg = Register.getRegFromName(it.endRegister!!.text)
registers.add(startReg)
while ((startReg.num < endReg.num) || (startReg.regname.dropLast(1) != endReg.regname.dropLast(1))) {
startReg = if (startReg.num < 7) {
Register.getRegFromName(startReg.regname.dropLast(1) + (startReg.num + 1))
} else {
Register.A0 // handle wrap around from d7->a0
}
registers.add(startReg)
}
}
return registers
}
// IndexRegister
@JvmStatic
fun isLongWidth(element: M68kIndexRegister): Boolean {
return element.dataWidth?.text.equals(".l", ignoreCase = true)
}
}
@@ -13,12 +13,13 @@ class M68kRenameInputValidator : RenameInputValidator {
override fun getPattern(): ElementPattern<out PsiElement?> = StandardPatterns.or( override fun getPattern(): ElementPattern<out PsiElement?> = StandardPatterns.or(
PlatformPatterns.psiElement(M68kGlobalLabel::class.java), PlatformPatterns.psiElement(M68kGlobalLabel::class.java),
PlatformPatterns.psiElement(M68kLocalLabel::class.java), PlatformPatterns.psiElement(M68kLocalLabel::class.java),
PlatformPatterns.psiElement(M68kSymbolDefinition::class.java) PlatformPatterns.psiElement(M68kSymbolDefinition::class.java),
PlatformPatterns.psiElement(M68kMacroDefinition::class.java)
) )
override fun isInputValid(newName: String, element: PsiElement, context: ProcessingContext): Boolean { override fun isInputValid(newName: String, element: PsiElement, context: ProcessingContext): Boolean {
return when (element) { return when (element) {
is M68kGlobalLabel, is M68kSymbolDefinition -> SYMBOL_PATTERN.matcher(newName).matches() is M68kGlobalLabel, is M68kSymbolDefinition, is M68kMacroDefinition -> SYMBOL_PATTERN.matcher(newName).matches()
is M68kLocalLabel -> LOCAL_LABEL_PATTERN.matcher(newName).matches() is M68kLocalLabel -> LOCAL_LABEL_PATTERN.matcher(newName).matches()
else -> false else -> false
} }
@@ -7,6 +7,10 @@ import com.intellij.psi.impl.source.resolve.reference.ReferenceProvidersRegistry
abstract class M68kSymbolReferenceMixin(node: ASTNode) : ASTWrapperPsiElement(node), M68kSymbolReference { abstract class M68kSymbolReferenceMixin(node: ASTNode) : ASTWrapperPsiElement(node), M68kSymbolReference {
override fun getReference(): PsiReference? {
return references.firstOrNull()
}
override fun getReferences(): Array<PsiReference> { override fun getReferences(): Array<PsiReference> {
return ReferenceProvidersRegistry.getReferencesFromProviders(this) return ReferenceProvidersRegistry.getReferencesFromProviders(this)
} }
@@ -0,0 +1,6 @@
package de.platon42.intellij.plugins.m68k.psi
interface M68kWithAddressRegisterIndirect : M68kAddressingMode {
val addressRegister: M68kAddressRegister
}
@@ -0,0 +1,6 @@
package de.platon42.intellij.plugins.m68k.psi
interface M68kWithDisplacement : M68kAddressingMode {
val displacement: M68kExpr?
}
@@ -0,0 +1,6 @@
package de.platon42.intellij.plugins.m68k.psi
interface M68kWithIndexRegister : M68kAddressingMode {
val indexRegister: M68kIndexRegister
}
@@ -1,8 +1,7 @@
package de.platon42.intellij.plugins.m68k.refs package de.platon42.intellij.plugins.m68k.refs
import com.intellij.navigation.ChooseByNameContributorEx2 import com.intellij.navigation.ChooseByNameContributorEx
import com.intellij.navigation.NavigationItem import com.intellij.navigation.NavigationItem
import com.intellij.openapi.project.Project
import com.intellij.psi.search.GlobalSearchScope import com.intellij.psi.search.GlobalSearchScope
import com.intellij.psi.stubs.StubIndex import com.intellij.psi.stubs.StubIndex
import com.intellij.util.Processor import com.intellij.util.Processor
@@ -13,17 +12,17 @@ import de.platon42.intellij.plugins.m68k.psi.M68kSymbolDefinition
import de.platon42.intellij.plugins.m68k.stubs.M68kGlobalLabelStubIndex import de.platon42.intellij.plugins.m68k.stubs.M68kGlobalLabelStubIndex
import de.platon42.intellij.plugins.m68k.stubs.M68kSymbolDefinitionStubIndex import de.platon42.intellij.plugins.m68k.stubs.M68kSymbolDefinitionStubIndex
class M68kChooseByNameContributor : ChooseByNameContributorEx2 { class M68kChooseByNameContributor : ChooseByNameContributorEx {
override fun processNames(processor: Processor<in String>, parameters: FindSymbolParameters) { // override fun processNames(processor: Processor<in String>, parameters: FindSymbolParameters) {
processNames(processor, parameters.searchScope, parameters.idFilter) // processNames(processor, parameters.searchScope, parameters.idFilter)
} // }
override fun getItemsByName(name: String, pattern: String, project: Project, includeNonProjectItems: Boolean): Array<NavigationItem> { // override fun getItemsByName(name: String, pattern: String, project: Project, includeNonProjectItems: Boolean): Array<NavigationItem> {
val result: MutableList<NavigationItem> = ArrayList() // val result = ArrayList<NavigationItem>()
processElementsWithName(name, result::add, FindSymbolParameters.wrap(pattern, project, includeNonProjectItems)) // processElementsWithName(name, result::add, FindSymbolParameters.wrap(pattern, project, includeNonProjectItems))
return result.toTypedArray() // return result.toTypedArray()
} // }
override fun processNames(processor: Processor<in String>, scope: GlobalSearchScope, filter: IdFilter?) { override fun processNames(processor: Processor<in String>, scope: GlobalSearchScope, filter: IdFilter?) {
StubIndex.getInstance().processAllKeys(M68kGlobalLabelStubIndex.KEY, processor, scope, filter) StubIndex.getInstance().processAllKeys(M68kGlobalLabelStubIndex.KEY, processor, scope, filter)
@@ -3,9 +3,9 @@ package de.platon42.intellij.plugins.m68k.refs
import com.intellij.codeInsight.completion.* import com.intellij.codeInsight.completion.*
import com.intellij.codeInsight.lookup.LookupElement import com.intellij.codeInsight.lookup.LookupElement
import com.intellij.codeInsight.lookup.LookupElementBuilder import com.intellij.codeInsight.lookup.LookupElementBuilder
import com.intellij.icons.AllIcons
import com.intellij.patterns.PlatformPatterns import com.intellij.patterns.PlatformPatterns
import com.intellij.util.ProcessingContext import com.intellij.util.ProcessingContext
import de.platon42.intellij.plugins.m68k.M68kIcons
import de.platon42.intellij.plugins.m68k.psi.M68kLookupUtil import de.platon42.intellij.plugins.m68k.psi.M68kLookupUtil
import de.platon42.intellij.plugins.m68k.psi.M68kTypes import de.platon42.intellij.plugins.m68k.psi.M68kTypes
@@ -18,7 +18,7 @@ class M68kGlobalLabelSymbolCompletionContributor : CompletionContributor() {
"a0", "a1", "a2", "a3", "a4", "a5", "a6", "sp", "a0", "a1", "a2", "a3", "a4", "a5", "a6", "sp",
"pc" "pc"
) )
.map { PrioritizedLookupElement.withPriority(LookupElementBuilder.create(it).withIcon(AllIcons.Nodes.Record).withBoldness(true), 2.0) } .map { PrioritizedLookupElement.withPriority(LookupElementBuilder.create(it).withIcon(M68kIcons.REGISTER).withBoldness(true), 2.0) }
} }
init { init {
@@ -7,12 +7,14 @@ import com.intellij.psi.PsiPolyVariantReferenceBase
import com.intellij.psi.ResolveResult import com.intellij.psi.ResolveResult
import com.intellij.psi.impl.source.resolve.ResolveCache import com.intellij.psi.impl.source.resolve.ResolveCache
import com.intellij.psi.search.GlobalSearchScope import com.intellij.psi.search.GlobalSearchScope
import com.intellij.psi.search.PsiSearchHelper import com.intellij.psi.stubs.StubIndex
import com.intellij.psi.search.UsageSearchContext
import com.intellij.util.SmartList import com.intellij.util.SmartList
import de.platon42.intellij.plugins.m68k.psi.M68kGlobalLabel import de.platon42.intellij.plugins.m68k.psi.M68kGlobalLabel
import de.platon42.intellij.plugins.m68k.psi.M68kNamedElement
import de.platon42.intellij.plugins.m68k.psi.M68kSymbolDefinition import de.platon42.intellij.plugins.m68k.psi.M68kSymbolDefinition
import de.platon42.intellij.plugins.m68k.psi.M68kSymbolReference import de.platon42.intellij.plugins.m68k.psi.M68kSymbolReference
import de.platon42.intellij.plugins.m68k.stubs.M68kGlobalLabelStubIndex
import de.platon42.intellij.plugins.m68k.stubs.M68kSymbolDefinitionStubIndex
class M68kGlobalLabelSymbolReference(element: M68kSymbolReference) : class M68kGlobalLabelSymbolReference(element: M68kSymbolReference) :
PsiPolyVariantReferenceBase<M68kSymbolReference>(element, TextRange(0, element.textLength)) { PsiPolyVariantReferenceBase<M68kSymbolReference>(element, TextRange(0, element.textLength)) {
@@ -24,18 +26,23 @@ class M68kGlobalLabelSymbolReference(element: M68kSymbolReference) :
class Resolver : ResolveCache.PolyVariantResolver<M68kGlobalLabelSymbolReference> { class Resolver : ResolveCache.PolyVariantResolver<M68kGlobalLabelSymbolReference> {
override fun resolve(ref: M68kGlobalLabelSymbolReference, incompleteCode: Boolean): Array<ResolveResult> { override fun resolve(ref: M68kGlobalLabelSymbolReference, incompleteCode: Boolean): Array<ResolveResult> {
val refName = ref.element.symbolName val refName = ref.element.symbolName
val project = ref.element.project val project = ref.element.project
val targets: MutableList<PsiElement> = SmartList()
PsiSearchHelper.getInstance(project).processElementsWithWord( val targets = SmartList<M68kNamedElement>()
{ elem, _ -> StubIndex.getInstance()
when (elem) { .processElements(M68kGlobalLabelStubIndex.KEY, refName, project, GlobalSearchScope.allScope(project), M68kGlobalLabel::class.java)
is M68kGlobalLabel, is M68kSymbolDefinition -> targets.add(elem) {
} targets.add(it)
true true
}, GlobalSearchScope.allScope(project), }
refName, UsageSearchContext.IN_CODE, true
) StubIndex.getInstance()
.processElements(M68kSymbolDefinitionStubIndex.KEY, refName, project, GlobalSearchScope.allScope(project), M68kSymbolDefinition::class.java)
{
targets.add(it)
true
}
return targets return targets
.map(::PsiElementResolveResult) .map(::PsiElementResolveResult)
.toTypedArray() .toTypedArray()
@@ -0,0 +1,46 @@
package de.platon42.intellij.plugins.m68k.refs
import com.intellij.psi.*
import com.intellij.psi.impl.source.resolve.ResolveCache
import com.intellij.psi.search.FileTypeIndex
import com.intellij.psi.search.GlobalSearchScope
import de.platon42.intellij.plugins.m68k.M68kFileType
import de.platon42.intellij.plugins.m68k.lexer.LexerUtil
import de.platon42.intellij.plugins.m68k.psi.M68kPreprocessorDirective
class M68kIncludeFileReference(element: M68kPreprocessorDirective) : PsiPolyVariantReferenceBase<M68kPreprocessorDirective>(element, true) {
companion object {
val INSTANCE = Resolver()
}
class Resolver : ResolveCache.PolyVariantResolver<M68kIncludeFileReference> {
override fun resolve(ref: M68kIncludeFileReference, incompleteCode: Boolean): Array<ResolveResult> {
val project = ref.element.project
val allFiles = FileTypeIndex.getFiles(M68kFileType.INSTANCE, GlobalSearchScope.allScope(project))
val pathName = LexerUtil.unquoteString(ref.element.exprList.first().text).replace('\\', '/')
val fileMatched = ((allFiles.firstOrNull { it.path.equals(pathName, ignoreCase = true) }
?: allFiles.firstOrNull { it.path.endsWith(pathName.removePrefix("../"), ignoreCase = true) })
?: allFiles.firstOrNull { it.path.endsWith(pathName.substringAfterLast('/'), ignoreCase = true) }) ?: return emptyArray()
return PsiElementResolveResult.createResults(PsiManager.getInstance(project).findFile(fileMatched))
}
}
override fun multiResolve(incompleteCode: Boolean): Array<ResolveResult> =
ResolveCache.getInstance(element.project)
.resolveWithCaching(this, INSTANCE, false, incompleteCode)
override fun resolve(): PsiElement? = multiResolve(false).singleOrNull()?.element
override fun getVariants(): Array<Any> = emptyArray()
// override fun getRangeInElement(): TextRange {
// val unquoted = LexerUtil.unquoteString(element.text)
//
// val path = element.exprList.first()
// return TextRange.from(
// path.textRange.startOffset + path.text.indexOf(unquoted), unquoted.length
// )
// }
}
@@ -0,0 +1,68 @@
package de.platon42.intellij.plugins.m68k.refs
import com.intellij.codeInsight.completion.*
import com.intellij.codeInsight.lookup.LookupElementBuilder
import com.intellij.patterns.PlatformPatterns
import com.intellij.psi.PsiElement
import com.intellij.psi.util.PsiTreeUtil
import com.intellij.util.ProcessingContext
import de.platon42.intellij.plugins.m68k.psi.*
class M68kLocalLabelDefCompletionContributor : CompletionContributor() {
init {
extend(
CompletionType.BASIC,
PlatformPatterns.or(PlatformPatterns.psiElement(M68kTypes.LOCAL_LABEL_DEF), PlatformPatterns.psiElement(M68kTypes.GLOBAL_LABEL_DEF)),
object : CompletionProvider<CompletionParameters>() {
override fun addCompletions(parameters: CompletionParameters, context: ProcessingContext, resultSet: CompletionResultSet) {
var topLevelElement = parameters.originalFile.findElementAt(parameters.offset)
while (topLevelElement?.parent !is M68kFile) {
topLevelElement = topLevelElement?.parent ?: return
}
// TODO find out if we can cache this somehow
val affectedStatements = ArrayList<M68kStatement>()
val definedLocalLabels = HashSet<String>()
val referencedLocalLabels = HashSet<String>()
findUndefinedLocalLabels(topLevelElement, affectedStatements, definedLocalLabels, referencedLocalLabels) {
PsiTreeUtil.getNextSiblingOfType(it, M68kStatement::class.java)
}
findUndefinedLocalLabels(topLevelElement, affectedStatements, definedLocalLabels, referencedLocalLabels) {
PsiTreeUtil.getPrevSiblingOfType(it, M68kStatement::class.java)
}
referencedLocalLabels.removeAll(definedLocalLabels)
resultSet.addAllElements(
if (parameters.originalPosition?.text == ".") {
referencedLocalLabels.map { LookupElementBuilder.create(it.removePrefix(".")) }
} else {
referencedLocalLabels.map(LookupElementBuilder::create)
}
)
}
private fun findUndefinedLocalLabels(
topLevelElement: PsiElement,
affectedStatements: MutableList<M68kStatement>,
definedLocalLabels: MutableSet<String>,
referencedLocalLabels: MutableSet<String>,
direction: (topLevelElement: PsiElement) -> M68kStatement?
) {
var currStatement = topLevelElement
while (true) {
currStatement = direction.invoke(currStatement) ?: break
val globalLabel = PsiTreeUtil.findChildOfType(currStatement, M68kGlobalLabel::class.java)
if (globalLabel != null) break
affectedStatements.add(currStatement)
val localLabel = PsiTreeUtil.findChildOfType(currStatement, M68kLocalLabel::class.java)
if (localLabel != null) definedLocalLabels.add(localLabel.name!!)
val symbolReferences = PsiTreeUtil.findChildrenOfAnyType(currStatement, M68kSymbolReference::class.java)
if (symbolReferences.isNotEmpty()) {
referencedLocalLabels.addAll(
symbolReferences.filter(M68kSymbolReference::isLocalLabelRef).map(M68kSymbolReference::getSymbolName)
)
}
}
}
})
}
}
@@ -1,5 +1,6 @@
package de.platon42.intellij.plugins.m68k.refs package de.platon42.intellij.plugins.m68k.refs
import com.intellij.codeInsight.daemon.EmptyResolveMessageProvider
import com.intellij.codeInsight.lookup.LookupElementBuilder import com.intellij.codeInsight.lookup.LookupElementBuilder
import com.intellij.openapi.util.TextRange import com.intellij.openapi.util.TextRange
import com.intellij.psi.PsiElement import com.intellij.psi.PsiElement
@@ -14,14 +15,18 @@ import de.platon42.intellij.plugins.m68k.psi.M68kLocalLabel
import de.platon42.intellij.plugins.m68k.psi.M68kStatement import de.platon42.intellij.plugins.m68k.psi.M68kStatement
import de.platon42.intellij.plugins.m68k.psi.M68kSymbolReference import de.platon42.intellij.plugins.m68k.psi.M68kSymbolReference
class M68kLocalLabelReference(element: M68kSymbolReference) : PsiPolyVariantReferenceBase<M68kSymbolReference>(element, TextRange(0, element.textLength)) { class M68kLocalLabelReference(element: M68kSymbolReference) :
PsiPolyVariantReferenceBase<M68kSymbolReference>(element, TextRange(0, element.textLength)),
EmptyResolveMessageProvider {
companion object { companion object {
val INSTANCE = Resolver() val INSTANCE = Resolver()
private const val UNRESOLVED_MESSAGE_PATTERN = "Cannot resolve local label ''{0}''"
fun findLocalLabels(element: M68kSymbolReference, predicate: (M68kLocalLabel) -> Boolean): List<M68kLocalLabel> { fun findLocalLabels(element: M68kSymbolReference, predicate: (M68kLocalLabel) -> Boolean): List<M68kLocalLabel> {
val statement = PsiTreeUtil.getStubOrPsiParentOfType(element, M68kStatement::class.java)!! val statement = PsiTreeUtil.getStubOrPsiParentOfType(element, M68kStatement::class.java)!!
val results: MutableList<M68kLocalLabel> = SmartList() val results = SmartList<M68kLocalLabel>()
// go backward // go backward
var currentStatement = PsiTreeUtil.getPrevSiblingOfType(statement, M68kStatement::class.java) var currentStatement = PsiTreeUtil.getPrevSiblingOfType(statement, M68kStatement::class.java)
while (currentStatement != null) { while (currentStatement != null) {
@@ -42,6 +47,8 @@ class M68kLocalLabelReference(element: M68kSymbolReference) : PsiPolyVariantRefe
} }
} }
override fun getUnresolvedMessagePattern() = UNRESOLVED_MESSAGE_PATTERN
class Resolver : ResolveCache.PolyVariantResolver<M68kLocalLabelReference> { class Resolver : ResolveCache.PolyVariantResolver<M68kLocalLabelReference> {
override fun resolve(ref: M68kLocalLabelReference, incompleteCode: Boolean): Array<ResolveResult> { override fun resolve(ref: M68kLocalLabelReference, incompleteCode: Boolean): Array<ResolveResult> {
val refName = ref.element.symbolName val refName = ref.element.symbolName
@@ -0,0 +1,19 @@
package de.platon42.intellij.plugins.m68k.refs
import com.intellij.codeInsight.completion.*
import com.intellij.codeInsight.lookup.LookupElementBuilder
import com.intellij.patterns.PlatformPatterns
import com.intellij.util.ProcessingContext
import de.platon42.intellij.plugins.m68k.psi.M68kLookupUtil
import de.platon42.intellij.plugins.m68k.psi.M68kTypes
class M68kMacroCallCompletionContributor : CompletionContributor() {
init {
extend(CompletionType.BASIC, PlatformPatterns.psiElement(M68kTypes.MACRO_INVOCATION), object : CompletionProvider<CompletionParameters>() {
override fun addCompletions(parameters: CompletionParameters, context: ProcessingContext, resultSet: CompletionResultSet) {
resultSet.addAllElements(M68kLookupUtil.findAllMacroDefinitions(parameters.originalFile.project).map(LookupElementBuilder::createWithIcon))
}
})
}
}
@@ -0,0 +1,17 @@
package de.platon42.intellij.plugins.m68k.refs
import com.intellij.openapi.util.TextRange
import com.intellij.psi.AbstractElementManipulator
import com.intellij.util.IncorrectOperationException
import de.platon42.intellij.plugins.m68k.psi.M68kElementFactory
import de.platon42.intellij.plugins.m68k.psi.M68kMacroCall
class M68kMacroCallElementManipulator : AbstractElementManipulator<M68kMacroCall>() {
@Throws(IncorrectOperationException::class)
override fun handleContentChange(element: M68kMacroCall, range: TextRange, newContent: String): M68kMacroCall {
val newMacroCall = M68kElementFactory.createMacroCall(element.project, newContent)
element.firstChild.replace(newMacroCall.firstChild)
return element
}
}
@@ -0,0 +1,54 @@
package de.platon42.intellij.plugins.m68k.refs
import com.intellij.codeInsight.daemon.EmptyResolveMessageProvider
import com.intellij.openapi.util.TextRange
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiElementResolveResult
import com.intellij.psi.PsiPolyVariantReferenceBase
import com.intellij.psi.ResolveResult
import com.intellij.psi.impl.source.resolve.ResolveCache
import com.intellij.psi.search.GlobalSearchScope
import com.intellij.psi.stubs.StubIndex
import com.intellij.util.SmartList
import de.platon42.intellij.plugins.m68k.psi.M68kMacroCall
import de.platon42.intellij.plugins.m68k.psi.M68kMacroDefinition
import de.platon42.intellij.plugins.m68k.stubs.M68kMacroDefinitionStubIndex
class M68kMacroReference(element: M68kMacroCall) :
PsiPolyVariantReferenceBase<M68kMacroCall>(element, TextRange(0, element.macroName.length)), EmptyResolveMessageProvider {
companion object {
val INSTANCE = Resolver()
private const val UNRESOLVED_MESSAGE_PATTERN = "Cannot resolve macro ''{0}''"
}
override fun getUnresolvedMessagePattern() = UNRESOLVED_MESSAGE_PATTERN
class Resolver : ResolveCache.PolyVariantResolver<M68kMacroReference> {
override fun resolve(ref: M68kMacroReference, incompleteCode: Boolean): Array<ResolveResult> {
val macroName = ref.element.macroName
val project = ref.element.project
val targets = SmartList<M68kMacroDefinition>()
StubIndex.getInstance()
.processElements(M68kMacroDefinitionStubIndex.KEY, macroName, project, GlobalSearchScope.allScope(project), M68kMacroDefinition::class.java)
{
targets.add(it)
true
}
return targets
.map(::PsiElementResolveResult)
.toTypedArray()
}
}
override fun multiResolve(incompleteCode: Boolean): Array<ResolveResult> =
ResolveCache.getInstance(element.project)
.resolveWithCaching(this, INSTANCE, false, incompleteCode)
override fun resolve(): PsiElement? = multiResolve(false).singleOrNull()?.element
override fun getVariants(): Array<Any> = emptyArray()
}
@@ -0,0 +1,34 @@
package de.platon42.intellij.plugins.m68k.refs
import com.intellij.history.core.Paths
import com.intellij.openapi.util.TextRange
import com.intellij.psi.AbstractElementManipulator
import com.intellij.psi.util.PsiTreeUtil
import com.intellij.util.IncorrectOperationException
import de.platon42.intellij.plugins.m68k.lexer.LexerUtil
import de.platon42.intellij.plugins.m68k.psi.M68kElementFactory
import de.platon42.intellij.plugins.m68k.psi.M68kLiteralExpr
import de.platon42.intellij.plugins.m68k.psi.M68kPreprocessorDirective
class M68kPreprocessorDirectiveElementManipulator : AbstractElementManipulator<M68kPreprocessorDirective>() {
@Throws(IncorrectOperationException::class)
override fun handleContentChange(element: M68kPreprocessorDirective, range: TextRange, newContent: String): M68kPreprocessorDirective {
val oldPath = LexerUtil.unquoteString(element.exprList.first().text)
.replace('\\', '/')
.substringBeforeLast('/', missingDelimiterValue = "")
val newIncludeStatement = M68kElementFactory.createIncludeStatement(element.project, Paths.appended(oldPath, newContent))
PsiTreeUtil.findChildOfType(element, M68kLiteralExpr::class.java)!!.replace(newIncludeStatement.exprList.first())
return element
}
override fun getRangeInElement(element: M68kPreprocessorDirective): TextRange {
val pathExpr = element.exprList.first()
val unquotedPath = LexerUtil.unquoteString(pathExpr.text)
return if (unquotedPath.length < pathExpr.textLength) {
TextRange.from(pathExpr.startOffsetInParent + 1, unquotedPath.length)
} else {
pathExpr.textRangeInParent
}
}
}
@@ -3,6 +3,9 @@ package de.platon42.intellij.plugins.m68k.refs
import com.intellij.patterns.PlatformPatterns import com.intellij.patterns.PlatformPatterns
import com.intellij.psi.* import com.intellij.psi.*
import com.intellij.util.ProcessingContext import com.intellij.util.ProcessingContext
import de.platon42.intellij.plugins.m68k.psi.M68kLiteralExpr
import de.platon42.intellij.plugins.m68k.psi.M68kMacroCall
import de.platon42.intellij.plugins.m68k.psi.M68kPreprocessorDirective
import de.platon42.intellij.plugins.m68k.psi.M68kSymbolReference import de.platon42.intellij.plugins.m68k.psi.M68kSymbolReference
class M68kReferenceContributor : PsiReferenceContributor() { class M68kReferenceContributor : PsiReferenceContributor() {
@@ -10,11 +13,15 @@ class M68kReferenceContributor : PsiReferenceContributor() {
companion object { companion object {
val localLabelReferenceProvider = LocalLabelReferenceProvider() val localLabelReferenceProvider = LocalLabelReferenceProvider()
val globalLabelReferenceProvider = GlobalLabelSymbolReferenceProvider() val globalLabelReferenceProvider = GlobalLabelSymbolReferenceProvider()
val macroReferenceProvider = MacroReferenceProvider()
val includeFileReferenceProvider = IncludeFileReferenceProvider()
} }
override fun registerReferenceProviders(registrar: PsiReferenceRegistrar) { override fun registerReferenceProviders(registrar: PsiReferenceRegistrar) {
registrar.registerReferenceProvider(PlatformPatterns.psiElement(M68kSymbolReference::class.java), localLabelReferenceProvider) registrar.registerReferenceProvider(PlatformPatterns.psiElement(M68kSymbolReference::class.java), localLabelReferenceProvider)
registrar.registerReferenceProvider(PlatformPatterns.psiElement(M68kSymbolReference::class.java), globalLabelReferenceProvider) registrar.registerReferenceProvider(PlatformPatterns.psiElement(M68kSymbolReference::class.java), globalLabelReferenceProvider)
registrar.registerReferenceProvider(PlatformPatterns.psiElement(M68kMacroCall::class.java), macroReferenceProvider)
registrar.registerReferenceProvider(PlatformPatterns.psiElement(M68kPreprocessorDirective::class.java), includeFileReferenceProvider)
} }
class LocalLabelReferenceProvider : PsiReferenceProvider() { class LocalLabelReferenceProvider : PsiReferenceProvider() {
@@ -32,4 +39,21 @@ class M68kReferenceContributor : PsiReferenceContributor() {
return arrayOf(M68kGlobalLabelSymbolReference(symbolReference)) return arrayOf(M68kGlobalLabelSymbolReference(symbolReference))
} }
} }
class MacroReferenceProvider : PsiReferenceProvider() {
override fun getReferencesByElement(element: PsiElement, context: ProcessingContext): Array<PsiReference> =
arrayOf(M68kMacroReference(element as M68kMacroCall))
}
class IncludeFileReferenceProvider : PsiReferenceProvider() {
override fun getReferencesByElement(element: PsiElement, context: ProcessingContext): Array<PsiReference> {
val directive = element as M68kPreprocessorDirective
if (directive.exprList.firstOrNull() !is M68kLiteralExpr) return emptyArray()
return if (directive.preprocessorKeyword.text.equals("include", ignoreCase = true)) {
arrayOf(M68kIncludeFileReference(directive))
} else {
emptyArray()
}
}
}
} }
@@ -1,5 +1,6 @@
package de.platon42.intellij.plugins.m68k.scanner package de.platon42.intellij.plugins.m68k.scanner
import com.intellij.lang.HelpID
import com.intellij.lang.cacheBuilder.DefaultWordsScanner import com.intellij.lang.cacheBuilder.DefaultWordsScanner
import com.intellij.lang.cacheBuilder.WordsScanner import com.intellij.lang.cacheBuilder.WordsScanner
import com.intellij.lang.findUsages.FindUsagesProvider import com.intellij.lang.findUsages.FindUsagesProvider
@@ -16,22 +17,29 @@ class M68kFindUsagesProvider : FindUsagesProvider {
override fun getWordsScanner(): WordsScanner = override fun getWordsScanner(): WordsScanner =
DefaultWordsScanner( DefaultWordsScanner(
M68kLexer(M68kLexerPrefs()), // FIXME Oh no! More Prefs! M68kLexer(M68kLexerPrefs()), // FIXME Oh no! More Prefs!
TokenSet.create(M68kTypes.SYMBOLDEF, M68kTypes.GLOBAL_LABEL_DEF, M68kTypes.LOCAL_LABEL_DEF, M68kTypes.SYMBOL), TokenSet.create(M68kTypes.SYMBOLDEF, M68kTypes.GLOBAL_LABEL_DEF, M68kTypes.LOCAL_LABEL_DEF, M68kTypes.MACRO_NAME),
TokenSet.create(M68kTypes.COMMENT), TokenSet.create(M68kTypes.COMMENT),
TokenSet.create(M68kTypes.STRINGLIT, M68kTypes.DECIMAL, M68kTypes.HEXADECIMAL, M68kTypes.OCTAL, M68kTypes.BINARY), TokenSet.create(M68kTypes.STRINGLIT, M68kTypes.DECIMAL, M68kTypes.HEXADECIMAL, M68kTypes.OCTAL, M68kTypes.BINARY),
TokenSet.EMPTY TokenSet.EMPTY
) )
override fun canFindUsagesFor(psiElement: PsiElement): Boolean = psiElement is M68kNamedElement override fun canFindUsagesFor(psiElement: PsiElement): Boolean =
when (psiElement) {
is M68kNamedElement, is M68kSymbolReference, is M68kMacroCall, is M68kFile, is M68kRegister -> true
else -> false
}
override fun getHelpId(psiElement: PsiElement): @NonNls String? = null override fun getHelpId(psiElement: PsiElement): @NonNls String = HelpID.FIND_OTHER_USAGES
override fun getType(element: PsiElement): @Nls String { override fun getType(element: PsiElement): @Nls String {
return when (element) { return when (element) {
is M68kGlobalLabel -> "global label" is M68kGlobalLabel -> "global label"
is M68kLocalLabel -> "local label" is M68kLocalLabel -> "local label"
is M68kPreprocessorDirective -> "preprocessor directive"
is M68kSymbolDefinition -> "symbol definition" is M68kSymbolDefinition -> "symbol definition"
is M68kSymbolReference -> "symbol reference" is M68kSymbolReference -> "symbol reference"
is M68kMacroDefinition -> "macro definition"
is M68kMacroCall -> "macro call"
is M68kRegister -> "register" is M68kRegister -> "register"
is M68kRefExpr -> "reference expression" is M68kRefExpr -> "reference expression"
else -> "" else -> ""
@@ -42,8 +50,11 @@ class M68kFindUsagesProvider : FindUsagesProvider {
return when (element) { return when (element) {
is M68kGlobalLabel -> element.name!! is M68kGlobalLabel -> element.name!!
is M68kLocalLabel -> element.name!! is M68kLocalLabel -> element.name!!
is M68kPreprocessorDirective -> element.text
is M68kSymbolDefinition -> element.parent.text is M68kSymbolDefinition -> element.parent.text
is M68kSymbolReference -> element.symbolName is M68kSymbolReference -> element.symbolName
is M68kMacroDefinition -> element.macroNameDefinition.text
is M68kMacroCall -> element.macroName
is M68kRefExpr -> element.symbolReference?.symbolName ?: "" is M68kRefExpr -> element.symbolReference?.symbolName ?: ""
is M68kRegister -> element.text is M68kRegister -> element.text
else -> "" else -> ""
@@ -0,0 +1,59 @@
package de.platon42.intellij.plugins.m68k.scanner
import com.intellij.openapi.fileTypes.FileType
import com.intellij.openapi.fileTypes.FileTypeRegistry
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.psi.impl.include.FileIncludeInfo
import com.intellij.psi.impl.include.FileIncludeProvider
import com.intellij.psi.impl.source.tree.LightTreeUtil
import com.intellij.util.Consumer
import com.intellij.util.PathUtilRt
import com.intellij.util.indexing.FileContent
import com.intellij.util.indexing.PsiDependentFileContent
import de.platon42.intellij.plugins.m68k.M68kFileType.Companion.INSTANCE
import de.platon42.intellij.plugins.m68k.lexer.LexerUtil
import de.platon42.intellij.plugins.m68k.psi.M68kTypes
class M68kIncludeFileProvider : FileIncludeProvider() {
override fun getId(): String {
return "mc68000_include"
}
override fun acceptFile(file: VirtualFile): Boolean {
return FileTypeRegistry.getInstance().isFileOfType(file, INSTANCE)
}
override fun registerFileTypesUsedForIndexing(fileTypeSink: Consumer<in FileType?>) {
fileTypeSink.consume(INSTANCE)
}
override fun getIncludeInfos(content: FileContent): Array<FileIncludeInfo> {
if (content.contentAsText.indexOfAny(listOf("include", "incbin"), ignoreCase = true) < 0) return emptyArray()
val tree = (content as PsiDependentFileContent).lighterAST
val statements = LightTreeUtil.getChildrenOfType(tree, tree.root, M68kTypes.STATEMENT).asSequence()
.mapNotNull { LightTreeUtil.firstChildOfType(tree, it, M68kTypes.PREPROCESSOR_DIRECTIVE) }
.mapNotNull {
val keywordNode = LightTreeUtil.firstChildOfType(tree, it, M68kTypes.PREPROCESSOR_KEYWORD) ?: return@mapNotNull null
val keyword = LightTreeUtil.toFilteredString(tree, keywordNode, null)
if (keyword.equals("include", true) || keyword.equals("incbin", true)) {
keyword to it
} else {
null
}
}
.mapNotNull {
val pathNode = LightTreeUtil.firstChildOfType(tree, it.second, M68kTypes.LITERAL_EXPR) ?: return@mapNotNull null
val path = LexerUtil.unquoteString(LightTreeUtil.toFilteredString(tree, pathNode, null)).replace('\\', '/')
if (it.first.equals("include", true)) {
FileIncludeInfo(path)
} else {
FileIncludeInfo(PathUtilRt.getFileName(path), path, 0, true)
}
}
.toList()
return statements.toTypedArray()
}
}
@@ -4,7 +4,6 @@ import com.intellij.ide.structureView.StructureViewTreeElement
import com.intellij.ide.util.treeView.smartTree.TreeElement import com.intellij.ide.util.treeView.smartTree.TreeElement
import com.intellij.navigation.ItemPresentation import com.intellij.navigation.ItemPresentation
import com.intellij.psi.NavigatablePsiElement import com.intellij.psi.NavigatablePsiElement
import com.intellij.refactoring.suggested.startOffset
import de.platon42.intellij.plugins.m68k.psi.M68kFile import de.platon42.intellij.plugins.m68k.psi.M68kFile
import de.platon42.intellij.plugins.m68k.psi.M68kGlobalLabel import de.platon42.intellij.plugins.m68k.psi.M68kGlobalLabel
import de.platon42.intellij.plugins.m68k.psi.M68kLookupUtil import de.platon42.intellij.plugins.m68k.psi.M68kLookupUtil
@@ -19,8 +18,9 @@ class M68kStructureViewElement(private val myElement: NavigatablePsiElement) : S
return when (myElement) { return when (myElement) {
is M68kFile -> { is M68kFile -> {
listOf( listOf(
M68kLookupUtil.findAllSymbolDefinitions(myElement).sortedBy { it.startOffset }, M68kLookupUtil.findAllSymbolDefinitions(myElement).sortedBy { it.textRange.startOffset },
M68kLookupUtil.findAllGlobalLabels(myElement).sortedBy { it.startOffset }, M68kLookupUtil.findAllMacroDefinitions(myElement).sortedBy { it.textRange.startOffset },
M68kLookupUtil.findAllGlobalLabels(myElement).sortedBy { it.textRange.startOffset },
// M68kLookupUtil.findAllSymbolDefinitions(myElement).sortedWith(compareBy(String.CASE_INSENSITIVE_ORDER) { it.name!! }), // M68kLookupUtil.findAllSymbolDefinitions(myElement).sortedWith(compareBy(String.CASE_INSENSITIVE_ORDER) { it.name!! }),
// M68kLookupUtil.findAllGlobalLabels(myElement).sortedWith(compareBy(String.CASE_INSENSITIVE_ORDER) { it.name!! }) // M68kLookupUtil.findAllGlobalLabels(myElement).sortedWith(compareBy(String.CASE_INSENSITIVE_ORDER) { it.name!! })
) )
@@ -3,23 +3,77 @@ package de.platon42.intellij.plugins.m68k.structureview
import com.intellij.ide.structureView.StructureViewModel.ElementInfoProvider import com.intellij.ide.structureView.StructureViewModel.ElementInfoProvider
import com.intellij.ide.structureView.StructureViewModelBase import com.intellij.ide.structureView.StructureViewModelBase
import com.intellij.ide.structureView.StructureViewTreeElement import com.intellij.ide.structureView.StructureViewTreeElement
import com.intellij.ide.util.treeView.smartTree.Sorter import com.intellij.ide.util.treeView.smartTree.*
import com.intellij.openapi.editor.Editor import com.intellij.openapi.editor.Editor
import com.intellij.psi.PsiFile import com.intellij.psi.PsiFile
import de.platon42.intellij.plugins.m68k.M68kIcons
import de.platon42.intellij.plugins.m68k.psi.M68kGlobalLabel
import de.platon42.intellij.plugins.m68k.psi.M68kLocalLabel import de.platon42.intellij.plugins.m68k.psi.M68kLocalLabel
import de.platon42.intellij.plugins.m68k.psi.M68kMacroDefinition
import de.platon42.intellij.plugins.m68k.psi.M68kSymbolDefinition
class M68kStructureViewModel(psiFile: PsiFile, editor: Editor?) : class M68kStructureViewModel(psiFile: PsiFile, editor: Editor?) :
StructureViewModelBase(psiFile, editor, M68kStructureViewElement(psiFile)), ElementInfoProvider { StructureViewModelBase(psiFile, editor, M68kStructureViewElement(psiFile)), ElementInfoProvider {
override fun isAlwaysShowsPlus(element: StructureViewTreeElement): Boolean { companion object {
return false val FILTERS = arrayOf(SymbolsFilter(), MacrosFilter(), GlobalLabelFilter(), LocalLabelFilter())
const val SYMBOLS_FILTER_ID = "SHOW_SYMBOLS"
const val MACROS_FILTER_ID = "SHOW_MACROS"
const val GLOBAL_LABEL_FILTER_ID = "SHOW_GLOBAL_LABELS"
const val LOCAL_LABEL_FILTER_ID = "SHOW_LOCAL_LABELS"
} }
override fun isAlwaysShowsPlus(element: StructureViewTreeElement): Boolean = false
override fun isAlwaysLeaf(element: StructureViewTreeElement): Boolean { override fun isAlwaysLeaf(element: StructureViewTreeElement): Boolean {
return element.value is M68kLocalLabel return when (element.value) {
is M68kLocalLabel, is M68kMacroDefinition, is M68kSymbolDefinition -> true
else -> false
}
} }
override fun getSorters(): Array<Sorter> { override fun getSorters(): Array<Sorter> = arrayOf(Sorter.ALPHA_SORTER)
return arrayOf(Sorter.ALPHA_SORTER)
override fun getFilters(): Array<Filter> = FILTERS
class SymbolsFilter : Filter {
override fun getPresentation(): ActionPresentation = ActionPresentationData("Show Symbols", null, M68kIcons.SYMBOL_DEF)
override fun getName(): String = SYMBOLS_FILTER_ID
override fun isVisible(treeNode: TreeElement?) = (treeNode as? StructureViewTreeElement)?.value !is M68kSymbolDefinition
override fun isReverted() = true
}
class MacrosFilter : Filter {
override fun getPresentation(): ActionPresentation = ActionPresentationData("Show Macros", null, M68kIcons.MACRO_DEF)
override fun getName(): String = MACROS_FILTER_ID
override fun isVisible(treeNode: TreeElement?) = (treeNode as? StructureViewTreeElement)?.value !is M68kMacroDefinition
override fun isReverted() = true
}
class GlobalLabelFilter : Filter {
override fun getPresentation(): ActionPresentation = ActionPresentationData("Show Global Labels", null, M68kIcons.GLOBAL_LABEL)
override fun getName(): String = GLOBAL_LABEL_FILTER_ID
override fun isVisible(treeNode: TreeElement?) = (treeNode as? StructureViewTreeElement)?.value !is M68kGlobalLabel
override fun isReverted() = true
}
class LocalLabelFilter : Filter {
override fun getPresentation(): ActionPresentation = ActionPresentationData("Show Local Labels", null, M68kIcons.LOCAL_LABEL)
override fun getName(): String = LOCAL_LABEL_FILTER_ID
override fun isVisible(treeNode: TreeElement?) = (treeNode as? StructureViewTreeElement)?.value !is M68kLocalLabel
override fun isReverted() = true
} }
} }
@@ -8,11 +8,14 @@ import com.intellij.psi.stubs.*
import com.intellij.psi.tree.ILightStubFileElementType import com.intellij.psi.tree.ILightStubFileElementType
import de.platon42.intellij.plugins.m68k.MC68000Language.Companion.INSTANCE import de.platon42.intellij.plugins.m68k.MC68000Language.Companion.INSTANCE
import de.platon42.intellij.plugins.m68k.psi.M68kGlobalLabel import de.platon42.intellij.plugins.m68k.psi.M68kGlobalLabel
import de.platon42.intellij.plugins.m68k.psi.M68kMacroDefinition
import de.platon42.intellij.plugins.m68k.psi.M68kSymbolDefinition import de.platon42.intellij.plugins.m68k.psi.M68kSymbolDefinition
import de.platon42.intellij.plugins.m68k.psi.M68kTypes import de.platon42.intellij.plugins.m68k.psi.M68kTypes
import de.platon42.intellij.plugins.m68k.psi.impl.M68kGlobalLabelImpl import de.platon42.intellij.plugins.m68k.psi.impl.M68kGlobalLabelImpl
import de.platon42.intellij.plugins.m68k.psi.impl.M68kMacroDefinitionImpl
import de.platon42.intellij.plugins.m68k.psi.impl.M68kSymbolDefinitionImpl import de.platon42.intellij.plugins.m68k.psi.impl.M68kSymbolDefinitionImpl
import de.platon42.intellij.plugins.m68k.stubs.impl.M68kGlobalLabelStubImpl import de.platon42.intellij.plugins.m68k.stubs.impl.M68kGlobalLabelStubImpl
import de.platon42.intellij.plugins.m68k.stubs.impl.M68kMacroDefinitionStubImpl
import de.platon42.intellij.plugins.m68k.stubs.impl.M68kSymbolDefinitionStubImpl import de.platon42.intellij.plugins.m68k.stubs.impl.M68kSymbolDefinitionStubImpl
import java.io.IOException import java.io.IOException
@@ -67,5 +70,28 @@ interface M68kElementTypes {
override fun indexStub(stub: M68kSymbolDefinitionStub, sink: IndexSink) = sink.occurrence(M68kSymbolDefinitionStubIndex.KEY, stub.name!!) override fun indexStub(stub: M68kSymbolDefinitionStub, sink: IndexSink) = sink.occurrence(M68kSymbolDefinitionStubIndex.KEY, stub.name!!)
} }
@JvmField
val MACRO_DEFINITION: IStubElementType<M68kMacroDefinitionStub, M68kMacroDefinition> =
object : M68kStubElementType<M68kMacroDefinitionStub, M68kMacroDefinition>("MACRO_DEFINITION") {
override fun createPsi(stub: M68kMacroDefinitionStub): M68kMacroDefinition = M68kMacroDefinitionImpl(stub, this)
override fun createStub(psi: M68kMacroDefinition, parentStub: StubElement<out PsiElement>): M68kMacroDefinitionStub =
M68kMacroDefinitionStubImpl(parentStub, this, psi.name!!)
override fun createStub(tree: LighterAST, node: LighterASTNode, parentStub: StubElement<*>): M68kMacroDefinitionStub {
val idNode = LightTreeUtil.requiredChildOfType(tree, node, M68kTypes.MACRO_NAME_DEFINITION)
return M68kMacroDefinitionStubImpl(parentStub, this, LightTreeUtil.toFilteredString(tree, idNode, null))
}
@Throws(IOException::class)
override fun serialize(stub: M68kMacroDefinitionStub, dataStream: StubOutputStream) = dataStream.writeName(stub.name)
@Throws(IOException::class)
override fun deserialize(dataStream: StubInputStream, parentStub: StubElement<*>): M68kMacroDefinitionStub =
M68kMacroDefinitionStubImpl(parentStub, this, dataStream.readName()!!)
override fun indexStub(stub: M68kMacroDefinitionStub, sink: IndexSink) = sink.occurrence(M68kMacroDefinitionStubIndex.KEY, stub.name!!)
}
} }
} }
@@ -0,0 +1,6 @@
package de.platon42.intellij.plugins.m68k.stubs
import com.intellij.psi.stubs.NamedStub
import de.platon42.intellij.plugins.m68k.psi.M68kMacroDefinition
interface M68kMacroDefinitionStub : NamedStub<M68kMacroDefinition>

Some files were not shown because too many files have changed in this diff Show More