Reworked label handling: Colons are no longer part of the label definition itself. Added PsiNamedElement for Labels.

This commit is contained in:
2021-07-17 10:18:36 +02:00
parent 14dd7de763
commit 63c38f68c3
30 changed files with 520 additions and 250 deletions
@@ -25,4 +25,9 @@ object LexerUtil {
fun pushbackAssignment(text: CharSequence): Int {
return text.length - text.indexOfAny(ASSIGNMENT_SEPARATORS)
}
@JvmStatic
fun pushbackLabelColons(text: CharSequence): Int {
return text.count { it == ':' }
}
}
@@ -57,8 +57,8 @@ HASH_COMMENT=([#;*].*+)
{WHITE_SPACE} { yybegin(NOSOL); return WHITE_SPACE; }
{EOL} { return WHITE_SPACE; }
{ASSIGNMENT} { yybegin(ASSIGNMENT); yypushback(pushbackAssignment(yytext())); return SYMBOLDEF; }
{LOCAL_LABEL} { yybegin(INSTRPART); return LOCAL_LABEL_DEF; }
{GLOBAL_LABEL} { yybegin(INSTRPART); return GLOBAL_LABEL_DEF; }
{LOCAL_LABEL} { yybegin(INSTRPART); yypushback(pushbackLabelColons(yytext())); return LOCAL_LABEL_DEF; }
{GLOBAL_LABEL} { yybegin(INSTRPART); yypushback(pushbackLabelColons(yytext())); return GLOBAL_LABEL_DEF; }
{HASH_COMMENT} { return COMMENT; }
}
@@ -66,8 +66,8 @@ HASH_COMMENT=([#;*].*+)
<NOSOL> {
{WHITE_SPACE} { return WHITE_SPACE; }
{EOL} { yybegin(YYINITIAL); return WHITE_SPACE; }
{LOCAL_LABEL_WC} { yybegin(INSTRPART); return LOCAL_LABEL_DEF; }
{GLOBAL_LABEL_WC} { yybegin(INSTRPART); return GLOBAL_LABEL_DEF; }
{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; }
@@ -84,6 +84,8 @@ HASH_COMMENT=([#;*].*+)
{WHITE_SPACE} { return WHITE_SPACE; }
{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; }
@@ -3,11 +3,11 @@
parserUtilClass="de.platon42.intellij.plugins.m68k.parser.M68kParserUtilBase"
extends="com.intellij.extapi.psi.ASTWrapperPsiElement"
psiClassPrefix="M68k"
psiImplClassSuffix="Impl"
psiPackage="de.platon42.intellij.plugins.m68k.psi"
psiImplPackage="de.platon42.intellij.plugins.m68k.psi.impl"
psiImplUtilClass="de.platon42.intellij.plugins.m68k.psi.M68kPsiImplUtil"
// elementTypeFactory="de.platon42.intellij.plugins.m68k.parser.M68kParserDefinition.createType"
// tokenTypeFactory="de.platon42.intellij.plugins.m68k.parser.M68kParserDefinition.createTokenType"
@@ -134,13 +134,27 @@ private LabelOnly ::= Label
private LabelWithInstruction ::= Label Instruction
private InstructionOnly ::= Instruction
LocalLabel ::= LOCAL_LABEL_DEF {extends=Label}
GlobalLabel ::= GLOBAL_LABEL_DEF {extends=Label}
LocalLabel ::= LOCAL_LABEL_DEF COLON? {
name = "local label"
extends = Label
implements = "de.platon42.intellij.plugins.m68k.psi.M68kNamedElement"
mixin = "de.platon42.intellij.plugins.m68k.psi.M68kLocalLabelMixin"
methods = [getName setName getNameIdentifier]
}
GlobalLabel ::= GLOBAL_LABEL_DEF COLON* {
name = "global label"
extends = Label
implements = "de.platon42.intellij.plugins.m68k.psi.M68kNamedElement"
mixin = "de.platon42.intellij.plugins.m68k.psi.M68kGlobalLabelMixin"
methods = [getName setName getNameIdentifier]
}
Label ::= LocalLabel | GlobalLabel
OperandSize ::= (OPSIZE_BS|OPSIZE_W|OPSIZE_L)
AddressSize ::= (OPSIZE_W|OPSIZE_L)
DataWidth ::= (OPSIZE_W|OPSIZE_L)
OperandSize ::= (OPSIZE_BS|OPSIZE_W|OPSIZE_L) { name = ".s|.b|.w|.l" }
AddressSize ::= (OPSIZE_W|OPSIZE_L) { name = ".w|.l" }
DataWidth ::= (OPSIZE_W|OPSIZE_L) { name = ".w|.l" }
AsmOp ::= MNEMONIC OperandSize?
@@ -159,13 +173,24 @@ private PreprocessorOperand ::= expr
private PlainOperands ::= STRINGLIT (SEPARATOR STRINGLIT)*
DataRegister ::= DREG {extends=Register}
AddressRegister ::= AREG {extends=Register}
SpecialRegister ::= REG_CCR | REG_SR | REG_USP | REG_VBR {extends=Register}
DataRegister ::= DREG {
name = "data register"
extends = Register
}
AddressRegister ::= AREG {
name = "address register"
extends = Register
}
SpecialRegister ::= REG_CCR | REG_SR | REG_USP | REG_VBR {
name = "special register"
extends = Register
}
Register ::= DataRegister | AddressRegister | SpecialRegister
private DataOrAddressRegister ::= DataRegister | AddressRegister
private DataOrAddressRegister ::= DataRegister | AddressRegister { name = "data or address register"}
AddressingMode ::= ImmediateData
| AddressRegisterIndirectPreDecAddressingMode
@@ -202,7 +227,10 @@ ProgramCounterIndirectWithIndexNewAddressingMode ::= ROUND_L (expr SEPARATOR)? P
AbsoluteAddressAddressingMode ::= expr AddressSize? !ROUND_L
private RegisterRange ::= (DataOrAddressRegister OP_MINUS DataOrAddressRegister)
RegisterListAddressingMode ::= (DataOrAddressRegister|RegisterRange) ((OP_AR_DIV|OP_MINUS) (DataOrAddressRegister|RegisterRange))*
ImmediateData ::= HASH expr {extends=AddressingMode}
ImmediateData ::= HASH expr {
name = "immediate data"
extends = AddressingMode
}
expr ::= binary_logical_or_expr
| binary_logical_and_expr
@@ -215,7 +243,7 @@ expr ::= binary_logical_or_expr
| binary_bitwise_and_expr
| binary_shift_group
| unary_group
| primary_group
| primary_group { name = "expression" }
// | macrobrace_expr
// private rules to define operators with the same priority
@@ -247,11 +275,13 @@ binary_cmp_gt_expr ::= expr OP_CMP_GT expr
binary_cmp_ge_expr ::= expr OP_CMP_GT_EQ expr
binary_cmp_eq_expr ::= expr OP_CMP_EQ expr
binary_cmp_ne_expr ::= expr OP_CMP_NOT_EQ expr
//binary_cmp_ne_expr ::= expr (OP_CMP_NOT_EQ|OP_CMP_NOT_EQ2) expr
binary_logical_and_expr ::= expr OP_LOGICAL_AND expr
binary_logical_or_expr ::= expr OP_LOGICAL_OR expr
//macrobrace_expr ::= OP_CMP_LT expr OP_CMP_GT
paren_expr ::= ROUND_L expr ROUND_R //{pin=1 recoverWhile=statement_recover}
ref_expr ::= SYMBOL|CURRENT_PC_SYMBOL
literal_expr ::= BINARY|DECIMAL|HEXADECIMAL|OCTAL|STRINGLIT
literal_expr ::= BINARY|DECIMAL|HEXADECIMAL|OCTAL|STRINGLIT {
implements = "com.intellij.psi.PsiLiteralValue"
mixin = "de.platon42.intellij.plugins.m68k.psi.M68kLiteralExprMixin"
}
@@ -1,22 +1,7 @@
package de.platon42.intellij.plugins.m68k.parser;
import com.intellij.lang.PsiBuilder;
import com.intellij.lang.parser.GeneratedParserUtilBase;
import static de.platon42.intellij.plugins.m68k.psi.M68kTypes.SYMBOL;
public class M68kParserUtilBase extends GeneratedParserUtilBase {
public static boolean parseMacroCallOrAsmInstruction(PsiBuilder b, int level) {
boolean r = false;
if (!nextTokenIs(b, SYMBOL)) return M68kParser.MacroCall(b, level);
PsiBuilder.Marker m = enter_section_(b);
//M68kMnemonics.INSTANCE.getMnemonics().stream().findFirst() nextTokenIs(, )
r = M68kParser.AsmInstruction(b, level);
exit_section_(b, m, null, r);
return r;
}
}
@@ -0,0 +1,23 @@
package de.platon42.intellij.plugins.m68k.psi
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiFileFactory
import com.intellij.psi.util.PsiTreeUtil
import de.platon42.intellij.plugins.m68k.M68kFileType.Companion.INSTANCE
object M68kElementFactory {
fun createGlobalLabel(project: Project, label: String): M68kGlobalLabel {
val file = createFile(project, label)
return PsiTreeUtil.findChildOfType(file, M68kGlobalLabel::class.java)!!
}
fun createLocalLabel(project: Project, label: String): M68kLocalLabel {
val file = createFile(project, label)
return PsiTreeUtil.findChildOfType(file, M68kLocalLabel::class.java)!!
}
fun createFile(project: Project, content: String): M68kFile {
return PsiFileFactory.getInstance(project).createFileFromText("dummy.m68k", INSTANCE, content) as M68kFile
}
}
@@ -0,0 +1,8 @@
package de.platon42.intellij.plugins.m68k.psi
import com.intellij.extapi.psi.ASTWrapperPsiElement
import com.intellij.lang.ASTNode
abstract class M68kGlobalLabelMixin(node: ASTNode) : ASTWrapperPsiElement(node), M68kGlobalLabel {
}
@@ -0,0 +1,51 @@
package de.platon42.intellij.plugins.m68k.psi
import com.intellij.extapi.psi.ASTWrapperPsiElement
import com.intellij.lang.ASTNode
abstract class M68kLiteralExprMixin(node: ASTNode) : ASTWrapperPsiElement(node), M68kLiteralExpr {
override fun getValue(): Any? {
val childNode = firstChild.node
when (childNode.elementType) {
M68kTypes.STRINGLIT -> {
return text.run {
when {
startsWith('"') -> removeSurrounding("\"")
startsWith('\'') -> removeSurrounding("'")
startsWith('<') -> removeSurrounding(">")
else -> this
}
}
}
M68kTypes.DECIMAL -> {
try {
return childNode.text.toInt()
} catch (ex: NumberFormatException) {
// ignore and fall through
}
}
M68kTypes.HEXADECIMAL -> {
try {
return childNode.text.substring(1).toInt(16)
} catch (ex: NumberFormatException) {
// ignore and fall through
}
}
M68kTypes.BINARY -> {
try {
return childNode.text.substring(1).toInt(2)
} catch (ex: NumberFormatException) {
// ignore and fall through
}
}
M68kTypes.OCTAL -> {
try {
return childNode.text.substring(1).toInt(8)
} catch (ex: NumberFormatException) {
// ignore and fall through
}
}
}
return text
}
}
@@ -0,0 +1,8 @@
package de.platon42.intellij.plugins.m68k.psi
import com.intellij.extapi.psi.ASTWrapperPsiElement
import com.intellij.lang.ASTNode
abstract class M68kLocalLabelMixin(node: ASTNode) : ASTWrapperPsiElement(node), M68kLocalLabel {
}
@@ -0,0 +1,6 @@
package de.platon42.intellij.plugins.m68k.psi;
import com.intellij.psi.PsiNameIdentifierOwner;
public interface M68kNamedElement extends PsiNameIdentifierOwner {
}
@@ -0,0 +1,42 @@
package de.platon42.intellij.plugins.m68k.psi
import com.intellij.psi.PsiElement
import com.intellij.util.IncorrectOperationException
import de.platon42.intellij.plugins.m68k.psi.M68kElementFactory.createGlobalLabel
import de.platon42.intellij.plugins.m68k.psi.M68kElementFactory.createLocalLabel
object M68kPsiImplUtil {
@JvmStatic
fun getName(element: M68kGlobalLabel): String? = element.firstChild.text
@JvmStatic
fun setName(element: M68kGlobalLabel, name: String): PsiElement {
val nameNode = element.node.findChildByType(M68kTypes.GLOBAL_LABEL_DEF)
if (nameNode != null) {
val newGlobalLabel = createGlobalLabel(element.project, name)
element.node.replaceChild(nameNode, newGlobalLabel.firstChild.node)
}
return element
}
@JvmStatic
fun getNameIdentifier(element: M68kGlobalLabel): PsiElement = element.firstChild
@JvmStatic
fun getName(element: M68kLocalLabel): String? = element.firstChild.text
@JvmStatic
fun setName(element: M68kLocalLabel, name: String): PsiElement {
if (!(name.startsWith(".") || name.endsWith("$"))) throw IncorrectOperationException("local label must start with '.' or end with '$'")
val nameNode = element.node.findChildByType(M68kTypes.LOCAL_LABEL_DEF)
if (nameNode != null) {
val newLocalLabel = createLocalLabel(element.project, name)
element.node.replaceChild(nameNode, newLocalLabel.firstChild.node)
}
return element
}
@JvmStatic
fun getNameIdentifier(element: M68kLocalLabel): PsiElement = element.firstChild
}