diff --git a/cxx-squid/src/main/java/org/sonar/cxx/parser/CxxGrammarImpl.java b/cxx-squid/src/main/java/org/sonar/cxx/parser/CxxGrammarImpl.java index 06e11997a..cea659874 100644 --- a/cxx-squid/src/main/java/org/sonar/cxx/parser/CxxGrammarImpl.java +++ b/cxx-squid/src/main/java/org/sonar/cxx/parser/CxxGrammarImpl.java @@ -173,6 +173,7 @@ public enum CxxGrammarImpl implements GrammarRuleKey { usingDeclarator, usingDirective, asmDefinition, + asmLabel, linkageSpecification, attributeSpecifierSeq, attributeSpecifier, @@ -1227,16 +1228,26 @@ private static void declarations(LexerfulGrammarBuilder b) { b.rule(usingDirective).is( b.optional(attributeSpecifierSeq), CxxKeyword.USING, CxxKeyword.NAMESPACE, b.optional(nestedNameSpecifier), namespaceName, ";" // C++ ); - + b.rule(asmDefinition).is( - CxxKeyword.ASM, b.firstOf( - b.sequence("(", STRING, ")", ";"), // C++ - b.sequence("{", b.oneOrMore(b.nextNot(b.firstOf("}", EOF)), b.anyToken()), "}", b.optional(";")), // VS - b.sequence(b.oneOrMore(b.nextNot(b.firstOf(";", EOF)), b.anyToken()), ";") // VS + b.sequence( + b.firstOf(CxxKeyword.ASM, "__asm__"), // C++ asm; GCC: __asm__ + b.optional(b.firstOf(CxxKeyword.VIRTUAL, CxxKeyword.INLINE, "__virtual__")), // GCC asm qualifiers + "(", STRING, ")", ";" + ), + b.sequence(b.firstOf("__asm", CxxKeyword.ASM), b.firstOf( // VS + b.sequence("{", b.oneOrMore(b.nextNot(b.firstOf("}", EOF)), b.anyToken()), "}", b.optional(";")), // VS __asm block + b.sequence(b.oneOrMore(b.nextNot(b.firstOf(";", EOF)), b.anyToken()), ";") // VS __asm ... ; + ) + ) ) ); + b.rule(asmLabel).is( + b.firstOf(CxxKeyword.ASM, "__asm__"), "(", STRING, ")" // GCC ASM label + ); + b.rule(linkageSpecification).is( CxxKeyword.EXTERN, STRING, b.firstOf( @@ -1319,7 +1330,7 @@ private static void declarators(LexerfulGrammarBuilder b) { ); b.rule(initDeclarator).is( - declarator, b.optional(initializer) // C++ + declarator, b.optional(asmLabel), b.optional(initializer) // C++ (asmLabel: GCC ASM label) ); b.rule(declarator).is( diff --git a/cxx-squid/src/test/java/org/sonar/cxx/parser/AssemblerTest.java b/cxx-squid/src/test/java/org/sonar/cxx/parser/AssemblerTest.java index cfecbb4c3..ef43c0b87 100644 --- a/cxx-squid/src/test/java/org/sonar/cxx/parser/AssemblerTest.java +++ b/cxx-squid/src/test/java/org/sonar/cxx/parser/AssemblerTest.java @@ -30,21 +30,34 @@ public void asmIsoStandard() { assertThat(p).matches("asm(\"mov eax, num\");"); } + @Test + public void asmGcc() { + p.setRootRule(g.rule(CxxGrammarImpl.asmDefinition)); + assertThat(p).matches("asm(\"mov eax, num\");"); + assertThat(p).matches("__asm__(\"mov eax, num\");"); + assertThat(p).matches("asm virtual(\"mov eax, num\");"); + assertThat(p).matches("asm inline(\"mov eax, num\");"); + assertThat(p).matches("__asm__ __virtual__(\"mov eax, num\");"); + } + @Test public void asmVcAssemblyInstruction1() { p.setRootRule(g.rule(CxxGrammarImpl.asmDefinition)); + assertThat(p).matches("__asm mov eax, num ;"); assertThat(p).matches("asm mov eax, num ;"); } @Test public void asmVcAssemblyInstructionList1() { p.setRootRule(g.rule(CxxGrammarImpl.asmDefinition)); + assertThat(p).matches("__asm { mov eax, num }"); assertThat(p).matches("asm { mov eax, num }"); } @Test public void asmVcAssemblyInstructionList2() { p.setRootRule(g.rule(CxxGrammarImpl.asmDefinition)); + assertThat(p).matches("__asm { mov eax, num };"); assertThat(p).matches("asm { mov eax, num };"); } @@ -52,12 +65,39 @@ public void asmVcAssemblyInstructionList2() { public void asmVcAssemblyInstructionList3() { p.setRootRule(g.rule(CxxGrammarImpl.asmDefinition)); assertThat(p).matches( - "asm {\n" - + "mov eax, num ; Get first argument\n" - + "mov ecx, power ; Get second argument\n" - + "shl eax, cl ; EAX = EAX * ( 2 to the power of CL )\n" - + "}" + "__asm {\n" + + "mov eax, num ; Get first argument\n" + + "mov ecx, power ; Get second argument\n" + + "shl eax, cl ; EAX = EAX * ( 2 to the power of CL )\n" + + "}" + ); + assertThat(p).matches( + "asm {\n" + + "mov eax, num ; Get first argument\n" + + "mov ecx, power ; Get second argument\n" + + "shl eax, cl ; EAX = EAX * ( 2 to the power of CL )\n" + + "}" ); } + @Test + public void asmGccLabel() { + p.setRootRule(g.rule(CxxGrammarImpl.asmLabel)); + assertThat(p).matches("asm (\"myfoo\")"); + assertThat(p).matches("__asm__ (\"myfoo\")"); + } + + @Test + public void asmGccLabel_reallife() { + p.setRootRule(g.rule(CxxGrammarImpl.simpleDeclaration)); + + assertThat(p).matches("extern const char cert_start[] asm(\"_binary_firmware_pho_by_crt_start\");"); + assertThat(p).matches("int func (int x, int y) asm (\"MYFUNC\");"); + assertThat(p).matches("int foo asm (\"myfoo\") = 2;"); + + assertThat(p).matches("extern const char cert_start[] __asm__(\"_binary_firmware_pho_by_crt_start\");"); + assertThat(p).matches("int func (int x, int y) __asm__ (\"MYFUNC\");"); + assertThat(p).matches("int foo __asm__ (\"myfoo\") = 2;"); + } + } diff --git a/cxx-squid/src/test/java/org/sonar/cxx/parser/CxxParserTest.java b/cxx-squid/src/test/java/org/sonar/cxx/parser/CxxParserTest.java index 023fdafe4..735e881ba 100644 --- a/cxx-squid/src/test/java/org/sonar/cxx/parser/CxxParserTest.java +++ b/cxx-squid/src/test/java/org/sonar/cxx/parser/CxxParserTest.java @@ -42,7 +42,7 @@ public class CxxParserTest { String errSources = "/parser/bad/error_recovery_declaration.cc"; - String[] goodFiles = {"own", "VC", "cli", "cuda", "examples"}; + String[] goodFiles = {"own", "VC", "GCC", "cli", "cuda", "examples"}; String[] preprocessorFiles = {"preprocessor"}; String[] cCompatibilityFiles = {"C", "C99"}; String rootDir = "src/test/resources/parser"; diff --git a/cxx-squid/src/test/java/org/sonar/cxx/parser/DeclaratorsTest.java b/cxx-squid/src/test/java/org/sonar/cxx/parser/DeclaratorsTest.java index 776e231f6..94dbe67bb 100644 --- a/cxx-squid/src/test/java/org/sonar/cxx/parser/DeclaratorsTest.java +++ b/cxx-squid/src/test/java/org/sonar/cxx/parser/DeclaratorsTest.java @@ -24,6 +24,20 @@ public class DeclaratorsTest extends ParserBaseTestHelper { + @Test + public void initDeclarator() { + p.setRootRule(g.rule(CxxGrammarImpl.initDeclarator)); + + mockRule(CxxGrammarImpl.declarator); + mockRule(CxxGrammarImpl.asmLabel); + mockRule(CxxGrammarImpl.initializer); + + assertThat(p).matches("declarator"); + assertThat(p).matches("declarator initializer"); + assertThat(p).matches("declarator asmLabel"); + assertThat(p).matches("declarator asmLabel initializer"); + } + @Test public void initDeclaratorList() { p.setRootRule(g.rule(CxxGrammarImpl.initDeclaratorList)); diff --git a/cxx-squid/src/test/resources/parser/GCC/inline-assembler.cc b/cxx-squid/src/test/resources/parser/GCC/inline-assembler.cc new file mode 100644 index 000000000..161ddb161 --- /dev/null +++ b/cxx-squid/src/test/resources/parser/GCC/inline-assembler.cc @@ -0,0 +1,46 @@ +void main() +{ + asm("movl %ecx %eax"); /* moves the contents of ecx to eax */ + __asm__("movb %bh (%eax)"); /*moves the byte from bh to the memory pointed by eax */ + + __asm__ ("movl %eax, %ebx\n\t" + "movl $56, %esi\n\t" + "movl %ecx, $label(%edx,%ebx,$4)\n\t" + "movb %ah, (%ebx)"); + + // Qualifiers + asm volatile ( "movl %ecx %eax" ) + asm __volatile__ ( "movl %ecx %eax" ) + asm inline ( "movl %ecx %eax" ) + __asm__ volatile ( "movl %ecx %eax" ) + __asm__ __inline__ ( "movl %ecx %eax" ) + __asm__ inline ( "movl %ecx %eax" ) + + // Extended Asm + int a=10, b; + asm ("movl %1, %%eax; + movl %%eax, %0;" + :"=r"(b) /* output */ + :"r"(a) /* input */ + :"%eax" /* clobbered register */ + ); +} + +// Asm Labels: + +// Assembler names for data: +int foo1 asm ("myfoo1") = 2; +int foo2 __asm__ ("myfoo2") = 2; +extern const char cert_start1[] asm("_binary_firmware_pho_by_crt_start1"); +extern const char cert_start2[] __asm__("_binary_firmware_pho_by_crt_start2"); + +// Assembler names for functions: +int func2 (int x, int y) asm ("MYFUNC1"); +int func3 (int x, int y) __asm__ ("MYFUNC2"); + +// support workaround +#define __asm__ asm +void func() +{ + __asm__("movl %ecx %eax"); +} diff --git a/cxx-squid/src/test/resources/parser/VC/inline-assembler.cc b/cxx-squid/src/test/resources/parser/VC/inline-assembler.cc new file mode 100644 index 000000000..c475f5a77 --- /dev/null +++ b/cxx-squid/src/test/resources/parser/VC/inline-assembler.cc @@ -0,0 +1,28 @@ +// asm_overview.cpp +// processor: x86 +void main() +{ + // Naked functions must provide their own prolog... + __asm { + push ebp + mov ebp, esp + sub esp, __LOCAL_SIZE + } + + // ... and epilog + __asm { + pop ebp + ret + } + + __asm push ebp; + __asm mov ebp, esp; + __asm sub esp, __LOCAL_SIZE; +} + +// support workaround +#define __asm asm +void func() +{ + __asm push ebp; +}