From a7130269c457027c5ed9042ba6638caeb0c2dad4 Mon Sep 17 00:00:00 2001 From: brouwers <122355335+brouwers-tiobe@users.noreply.github.com> Date: Tue, 17 Jun 2025 12:10:22 +0200 Subject: [PATCH 1/4] RM-36465: Add AWL support to CPD --- pmd-awl/pom.xml | 87 +++++++++++++++++++ .../sourceforge/pmd/lang/awl/ast/AWLLexer.g4 | 46 ++++++++++ .../pmd/lang/awl/AwlLanguageModule.java | 23 +++++ .../pmd/lang/awl/cpd/AwlCpdLexer.java | 19 ++++ .../net.sourceforge.pmd.lang.Language | 1 + .../pmd/dist/BinaryDistributionIT.java | 2 +- pmd-languages-deps/pom.xml | 5 ++ pom.xml | 1 + 8 files changed, 183 insertions(+), 1 deletion(-) create mode 100644 pmd-awl/pom.xml create mode 100644 pmd-awl/src/main/antlr4/net/sourceforge/pmd/lang/awl/ast/AWLLexer.g4 create mode 100644 pmd-awl/src/main/java/net/sourceforge/pmd/lang/awl/AwlLanguageModule.java create mode 100644 pmd-awl/src/main/java/net/sourceforge/pmd/lang/awl/cpd/AwlCpdLexer.java create mode 100644 pmd-awl/src/main/resources/META-INF/services/net.sourceforge.pmd.lang.Language diff --git a/pmd-awl/pom.xml b/pmd-awl/pom.xml new file mode 100644 index 00000000000..d1f2434da05 --- /dev/null +++ b/pmd-awl/pom.xml @@ -0,0 +1,87 @@ + + + 4.0.0 + pmd-awl + PMD AWL + + + net.sourceforge.pmd + pmd + 7.6.0 + ../pom.xml + + + + + + org.antlr + antlr4-maven-plugin + + + org.apache.maven.plugins + maven-antrun-plugin + + + antlr-cleanup + generate-sources + + run + + + + + + + + + + + + + + maven-resources-plugin + + false + + ${*} + + + + + com.github.siom79.japicmp + japicmp-maven-plugin + + + true + + + + + + + + net.sourceforge.pmd + pmd-core + + + org.antlr + antlr4-runtime + + + + org.junit.jupiter + junit-jupiter + test + + + net.sourceforge.pmd + pmd-test + test + + + net.sourceforge.pmd + pmd-lang-test + test + + + diff --git a/pmd-awl/src/main/antlr4/net/sourceforge/pmd/lang/awl/ast/AWLLexer.g4 b/pmd-awl/src/main/antlr4/net/sourceforge/pmd/lang/awl/ast/AWLLexer.g4 new file mode 100644 index 00000000000..b2e2bdbcac4 --- /dev/null +++ b/pmd-awl/src/main/antlr4/net/sourceforge/pmd/lang/awl/ast/AWLLexer.g4 @@ -0,0 +1,46 @@ +lexer grammar AWLLexer; + +PARSERTOKEN : ';' | ':' | '{' | '}' | '=' | ':=' | '[' | ']' | '(' | ')' | '..' | ',' | '+' | '-' | '.' | '#' | '%' ; + +INSTRUCTIONNAME : '<=' | '+AR1' | '+AR2' | '+D' | '-D' | '*D' | '/D' | '==D' | '>D' | '>=D' | 'D' | + '+I' | '-I' | '*I' | '/I' | '==I' | '>I' | '>=I' | 'I' | '+R' | '-R' | '*R' | '/R' | 'RND+' | 'RND-' ; + +LOGICCOMPARISON : '==0' | '<>0' | '>0' | '<0' | '>=0' | '<=0' ; + +TITLE : 'TITLE' [ \t]* '=' ~[\r\n]* ; + +POINTER_OP : 'P#' 'DBX'? ; + +ARRAY_INIT : Integer '(' '\'' AnyPrintChar '\'' ')' ; +fragment AnyPrintChar : [\u0040-\u007E] ; + +ID : IdentifierStart IdentifierChar* ; +fragment IdentifierStart : '_' | 'a' .. 'z' | 'A' .. 'Z' ; +fragment IdentifierChar : IdentifierStart | Digit | '-' ; + +StringConstant : DOUBLE_QUOTED_STRING | SINGLE_QUOTED_STRING ; +fragment DOUBLE_QUOTED_STRING : '"' AnyCharExceptDoubleQuoteNewline* '"' ; +fragment SINGLE_QUOTED_STRING : '\'' AnyCharExceptSingleQuoteNewline* '\'' ; +fragment AnyCharExceptDoubleQuoteNewline : [\u0000-\u0009] | [\u000B] | [\u000C] | [\u000E-\u0021] | [\u0023-\u007F] ; +fragment AnyCharExceptSingleQuoteNewline : [\u0000-\u0009] | [\u000B] | [\u000C] | [\u000E-\u0026] | [\u0028-\u007F] ; + +REAL : Integer '.' Integer ; + +INT : Integer ; + +fragment Integer : Digit+ ; +fragment Digit : [0-9] ; + +HEX_INT : '16#' HexDigit+ ; +fragment HexDigit : [0-9] | [A-F] | [_] ; + +BIN_INT : '2#' BinDigit+ ; +BinDigit : [0-1] ; + +TIME : 'S5'? ('t' | 'T') '#' Digit+ TimeUnit ; +fragment TimeUnit : 'H' | 'h' | 'M' | 'm' | 'S' | 's' | 'MS' | 'ms' ; + +LineComment : '//' ~[\r\n]* -> channel(HIDDEN) ; +BlockComment : '(*' .*? '*)' -> channel(HIDDEN) ; +Whitespace : [ \t]+ -> skip ; +LineTerm : [\r\n]+ -> channel(HIDDEN) ; \ No newline at end of file diff --git a/pmd-awl/src/main/java/net/sourceforge/pmd/lang/awl/AwlLanguageModule.java b/pmd-awl/src/main/java/net/sourceforge/pmd/lang/awl/AwlLanguageModule.java new file mode 100644 index 00000000000..5e3dd9e2f34 --- /dev/null +++ b/pmd-awl/src/main/java/net/sourceforge/pmd/lang/awl/AwlLanguageModule.java @@ -0,0 +1,23 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.awl; + +import net.sourceforge.pmd.cpd.CpdLexer; +import net.sourceforge.pmd.lang.LanguagePropertyBundle; +import net.sourceforge.pmd.lang.awl.cpd.AwlCpdLexer; +import net.sourceforge.pmd.lang.impl.CpdOnlyLanguageModuleBase; + +public class AwlLanguageModule extends CpdOnlyLanguageModuleBase { + private static final String ID = "awl"; + + public AwlLanguageModule() { + super(LanguageMetadata.withId(ID).name("AWL").extensions("awl")); + } + + @Override + public CpdLexer createCpdLexer(LanguagePropertyBundle bundle) { + return new AwlCpdLexer(); + } +} diff --git a/pmd-awl/src/main/java/net/sourceforge/pmd/lang/awl/cpd/AwlCpdLexer.java b/pmd-awl/src/main/java/net/sourceforge/pmd/lang/awl/cpd/AwlCpdLexer.java new file mode 100644 index 00000000000..9417f75f525 --- /dev/null +++ b/pmd-awl/src/main/java/net/sourceforge/pmd/lang/awl/cpd/AwlCpdLexer.java @@ -0,0 +1,19 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.awl.cpd; + +import org.antlr.v4.runtime.CharStream; +import org.antlr.v4.runtime.Lexer; + +import net.sourceforge.pmd.cpd.impl.AntlrCpdLexer; +import net.sourceforge.pmd.lang.awl.ast.AWLLexer; + +public class AwlCpdLexer extends AntlrCpdLexer { + + @Override + protected Lexer getLexerForSource(CharStream charStream) { + return new AWLLexer(charStream); + } +} diff --git a/pmd-awl/src/main/resources/META-INF/services/net.sourceforge.pmd.lang.Language b/pmd-awl/src/main/resources/META-INF/services/net.sourceforge.pmd.lang.Language new file mode 100644 index 00000000000..aa86e1ec7ae --- /dev/null +++ b/pmd-awl/src/main/resources/META-INF/services/net.sourceforge.pmd.lang.Language @@ -0,0 +1 @@ +net.sourceforge.pmd.lang.awl.AwlLanguageModule diff --git a/pmd-dist/src/test/java/net/sourceforge/pmd/dist/BinaryDistributionIT.java b/pmd-dist/src/test/java/net/sourceforge/pmd/dist/BinaryDistributionIT.java index ec499a5ac75..e2fce578d82 100644 --- a/pmd-dist/src/test/java/net/sourceforge/pmd/dist/BinaryDistributionIT.java +++ b/pmd-dist/src/test/java/net/sourceforge/pmd/dist/BinaryDistributionIT.java @@ -29,7 +29,7 @@ class BinaryDistributionIT extends AbstractBinaryDistributionTest { private static final List SUPPORTED_LANGUAGES_CPD = listOf( - "apex", "coco", "cpp", "cs", "dart", "ecmascript", + "apex", "awl", "coco", "cpp", "cs", "dart", "ecmascript", "fortran", "gherkin", "go", "groovy", "html", "java", "jsp", "julia", "kotlin", "lua", "matlab", "modelica", "objectivec", "perl", diff --git a/pmd-languages-deps/pom.xml b/pmd-languages-deps/pom.xml index 214b8b679e8..6a1361a4929 100644 --- a/pmd-languages-deps/pom.xml +++ b/pmd-languages-deps/pom.xml @@ -17,6 +17,11 @@ pmd-apex ${project.version} + + net.sourceforge.pmd + pmd-awl + ${project.version} + net.sourceforge.pmd pmd-coco diff --git a/pom.xml b/pom.xml index acebcff366a..ea514f245f9 100644 --- a/pom.xml +++ b/pom.xml @@ -1334,6 +1334,7 @@ pmd-apex + pmd-awl pmd-coco pmd-core pmd-cpp From 4a1dace6620cddb00728f4dd7db1262a13f70033 Mon Sep 17 00:00:00 2001 From: brouwers <122355335+brouwers-tiobe@users.noreply.github.com> Date: Fri, 20 Jun 2025 14:45:04 +0200 Subject: [PATCH 2/4] RM-36465: Add test file Combined some publicly available examples from reference document --- .../pmd/lang/awl/cpd/AwlCpdLexerTest.java | 22 +++ .../lang/awl/cpd/testdata/awl_examples.awl | 58 +++++++ .../lang/awl/cpd/testdata/awl_examples.txt | 152 ++++++++++++++++++ 3 files changed, 232 insertions(+) create mode 100644 pmd-awl/src/test/java/net/sourceforge/pmd/lang/awl/cpd/AwlCpdLexerTest.java create mode 100644 pmd-awl/src/test/resources/net/sourceforge/pmd/lang/awl/cpd/testdata/awl_examples.awl create mode 100644 pmd-awl/src/test/resources/net/sourceforge/pmd/lang/awl/cpd/testdata/awl_examples.txt diff --git a/pmd-awl/src/test/java/net/sourceforge/pmd/lang/awl/cpd/AwlCpdLexerTest.java b/pmd-awl/src/test/java/net/sourceforge/pmd/lang/awl/cpd/AwlCpdLexerTest.java new file mode 100644 index 00000000000..e87b289dc3b --- /dev/null +++ b/pmd-awl/src/test/java/net/sourceforge/pmd/lang/awl/cpd/AwlCpdLexerTest.java @@ -0,0 +1,22 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.awl.cpd; + +import org.junit.jupiter.api.Test; + +import net.sourceforge.pmd.lang.test.cpd.CpdTextComparisonTest; + +class AwlCpdLexerTest extends CpdTextComparisonTest { + + AwlCpdLexerTest() { + super("awl", ".awl"); + } + + @Test + void examples() { + doTest("awl_examples"); + } + +} diff --git a/pmd-awl/src/test/resources/net/sourceforge/pmd/lang/awl/cpd/testdata/awl_examples.awl b/pmd-awl/src/test/resources/net/sourceforge/pmd/lang/awl/cpd/testdata/awl_examples.awl new file mode 100644 index 00000000000..12da51c5e9d --- /dev/null +++ b/pmd-awl/src/test/resources/net/sourceforge/pmd/lang/awl/cpd/testdata/awl_examples.awl @@ -0,0 +1,58 @@ +// Combined some publicly available AWL/STL examples (good enough for lexer-only test) +// from STL reference document 'Statement List (STL) for S7-300 and S7-400 Programming' +// https://cache.industry.siemens.com/dl/files/814/109751814/att_933093/v1/STEP_7_-_Statement_List_for_S7-300_and_S7-400.pdf + +FUNCTION_BLOCK "fb1" +TITLE = %version: 1 % Title information is present here % $ ^ \ +{ this_is_false := 'FALSE' } +FAMILY : Fam1 +VERSION : 0.0 + +// Input variables + VAR_INPUT + i_ID : DWord; // Var 1 + CFG_Position_node : Int; + END_VAR + +// Output variables + VAR_OUTPUT + output_var_1 : Bool; + output_var_2 : Int; + output_var_3 : Bool; + END_VAR + +// Example: Statement List to control the Conveyor Belt +O I 1.1 //Pressing either start switch turns the motor on. +O I 1.3 +S Q 4.0 +O I 1.2 //Pressing either stop switch or opening the normally closed contact at +//the end of the belt turns the motor off. +O I 1.4 +ON I 1.5 +R Q 4.0 + +// Example: Statement List to Generate a Clock Pulse (pulse duty factor 1:1) +AN T1 //If timer T 1 has expired, +L S5T#250ms //load the time value 250 ms into T 1 and +SV T1 //start T 1 as an extended-pulse timer. +NOT //Negate (invert) the result of logic operation. +BEB //If the timer is running, end the current block. +L MB100 //If the timer has expired, load the contents of memory byte MB100, +INC 1 //increment the contents by 1, +T MB100 //and transfer the result to memory byte MB100. + +L ID20 //Load contents of ID20 into ACCU 1. +L ID24 //Load contents of ACCU 1 into ACCU 2. Load contents of ID24 into ACCU +1. +AD //Combine bits from ACCU 1 with ACCU 2 by AND, store result in ACCU +1. +T MD8 //Transfer result to MD8. + +L ID 20 //Load contents of ID20 into ACCU 1. +AD DW#16#0FFF_EF21 //Combine bits of ACCU 1 with bit pattern of 32-bit constant +(0000_1111_1111_1111_1110_1111_0010_0001) by AND; store result in +ACCU 1. +>=I +JP NEXT //Jump to NEXT jump label if result is unequal to zero, (CC 1 = 1). + +END_FUNCTION_BLOCK diff --git a/pmd-awl/src/test/resources/net/sourceforge/pmd/lang/awl/cpd/testdata/awl_examples.txt b/pmd-awl/src/test/resources/net/sourceforge/pmd/lang/awl/cpd/testdata/awl_examples.txt new file mode 100644 index 00000000000..c50f53d7e94 --- /dev/null +++ b/pmd-awl/src/test/resources/net/sourceforge/pmd/lang/awl/cpd/testdata/awl_examples.txt @@ -0,0 +1,152 @@ + [Image] or [Truncated image[ Bcol Ecol +L5 + [FUNCTION_BLOCK] 1 15 + ["fb1"] 16 21 +L6 + [TITLE = %version: 1 % Title inform[ 1 64 +L7 + [{] 1 2 + [this_is_false] 3 16 + [:=] 17 19 + ['FALSE'] 20 27 + [}] 28 29 +L8 + [FAMILY] 1 7 + [:] 8 9 + [Fam1] 10 14 +L9 + [VERSION] 1 8 + [:] 9 10 + [0.0] 11 14 +L12 + [VAR_INPUT] 4 13 +L13 + [i_ID] 7 11 + [:] 12 13 + [DWord] 14 19 + [;] 19 20 +L14 + [CFG_Position_node] 7 24 + [:] 25 26 + [Int] 27 30 + [;] 30 31 +L15 + [END_VAR] 4 11 +L18 + [VAR_OUTPUT] 4 14 +L19 + [output_var_1] 7 19 + [:] 20 21 + [Bool] 22 26 + [;] 26 27 +L20 + [output_var_2] 7 19 + [:] 20 21 + [Int] 22 25 + [;] 25 26 +L21 + [output_var_3] 7 19 + [:] 20 21 + [Bool] 22 26 + [;] 26 27 +L22 + [END_VAR] 4 11 +L25 + [O] 1 2 + [I] 3 4 + [1.1] 5 8 +L26 + [O] 1 2 + [I] 3 4 + [1.3] 5 8 +L27 + [S] 1 2 + [Q] 3 4 + [4.0] 5 8 +L28 + [O] 1 2 + [I] 3 4 + [1.2] 5 8 +L30 + [O] 1 2 + [I] 3 4 + [1.4] 5 8 +L31 + [ON] 1 3 + [I] 4 5 + [1.5] 6 9 +L32 + [R] 1 2 + [Q] 3 4 + [4.0] 5 8 +L35 + [AN] 1 3 + [T1] 4 6 +L36 + [L] 1 2 + [S5T#250ms] 3 12 +L37 + [SV] 1 3 + [T1] 4 6 +L38 + [NOT] 1 4 +L39 + [BEB] 1 4 +L40 + [L] 1 2 + [MB100] 3 8 +L41 + [INC] 1 4 + [1] 5 6 +L42 + [T] 1 2 + [MB100] 3 8 +L44 + [L] 1 2 + [ID20] 3 7 +L45 + [L] 1 2 + [ID24] 3 7 +L46 + [1] 1 2 + [.] 2 3 +L47 + [AD] 1 3 +L48 + [1] 1 2 + [.] 2 3 +L49 + [T] 1 2 + [MD8] 3 6 +L51 + [L] 1 2 + [ID] 3 5 + [20] 6 8 +L52 + [AD] 1 3 + [DW] 4 6 + [#] 6 7 + [16#0FFF_EF21] 7 19 +L53 + [(] 1 2 + [0000] 2 6 + [_1111_1111_1111_1110_1111_0010_000[ 6 41 + [)] 41 42 + [by] 43 45 + [AND] 46 49 + [;] 49 50 + [store] 51 56 + [result] 57 63 + [in] 64 66 +L54 + [ACCU] 1 5 + [1] 6 7 + [.] 7 8 +L55 + [>=I] 1 4 +L56 + [JP] 1 3 + [NEXT] 4 8 +L58 + [END_FUNCTION_BLOCK] 1 19 +EOF From d4513e5f7dc3d57a070b20ccf08a10ca1b08bddd Mon Sep 17 00:00:00 2001 From: brouwers <122355335+brouwers-tiobe@users.noreply.github.com> Date: Mon, 23 Jun 2025 10:08:32 +0200 Subject: [PATCH 3/4] RM-36465: Trigger build From 6147ec6cb5d4bf195d20f12f58601ed7de834ddb Mon Sep 17 00:00:00 2001 From: brouwers <122355335+brouwers-tiobe@users.noreply.github.com> Date: Tue, 24 Jun 2025 14:44:42 +0200 Subject: [PATCH 4/4] RM-36465: Add uppercase extension --- .../java/net/sourceforge/pmd/lang/awl/AwlLanguageModule.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pmd-awl/src/main/java/net/sourceforge/pmd/lang/awl/AwlLanguageModule.java b/pmd-awl/src/main/java/net/sourceforge/pmd/lang/awl/AwlLanguageModule.java index 5e3dd9e2f34..0d18918b523 100644 --- a/pmd-awl/src/main/java/net/sourceforge/pmd/lang/awl/AwlLanguageModule.java +++ b/pmd-awl/src/main/java/net/sourceforge/pmd/lang/awl/AwlLanguageModule.java @@ -13,7 +13,7 @@ public class AwlLanguageModule extends CpdOnlyLanguageModuleBase { private static final String ID = "awl"; public AwlLanguageModule() { - super(LanguageMetadata.withId(ID).name("AWL").extensions("awl")); + super(LanguageMetadata.withId(ID).name("AWL").extensions("awl", "AWL")); } @Override