I'm using super quotes (R"=====()=====") to store html pages in PROGMEM. For one particular page I defined the compiler is getting confused. Here's the partial code in a test project:
void setup() {
}
void loop()
{
test();
}
void dataPage() {
static const char dataPageHtml[] PROGMEM = R"=====(
<!DOCTYPE html>
<html><head>
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>WaterDeMon</title>
<link rel="icon" type="image/x-icon" href="favicon.ico" />
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.4/Chart.js"></script>
</head>
<body style="font-size: 7vw; text-align: center;">
<div style="width:15%%; float: left;">
<img src="WaterDeMon.png" style="margin:auto; width:auto; height: 48px; float: left;"/>
</div>
<div style="float:left; width:70%%; font-size: 9vw;">
<strong>WaterDeMon</strong>
</div>
<div style="width:15%%; float: right"> </div>
<div style="margin-top: 2vw; display: grid; place-items: center; font-size: 3.5vw; clear: left;">
<div style="font-size: 7vw;"><u>Water Depth History</u></div>
<em>Water Depths for Past 24hrs (feet)</em>
<canvas id="myChart" style="width:100%%;max-width:1080px"></canvas>
<div style="clear: right; font-size: 6vw;"><em>%s</em></div>
<form action="/DAT" method="GET" style="margin: 2vw">
<input type="submit" value="Refresh" style="font-size: 8vw">
</form>
<form action="/" method="GET" style="margin: 2vw">
<input type="submit" value="Home" style="font-size: 8vw">
</form>
</div>
<script>
var xValues = [%s];
var yValues = [%s];
var barColors = "blue";
new Chart("myChart", {
type: "bar",
data: {
labels: xValues,
datasets: [{
backgroundColor: barColors,
data: yValues
}]
},
options: {
scales: {
xAxes: [{
barPercentage: 1
}]
},
legend: {display: false},
title: {
display: false,
text: "Water Depths for Past 24hrs (feet),"
}
}
});
</script>
</body></html>
)=====";
//)=====";
}
void test() {
dataPage();
}
This code will build as long as you leave the extra super quote terminator at the end that's commented out. Remove it and it appears that the compiler doesn't see the prior terminator and therefore doesn't see the definition of test(). Other pages are OK, so it's something in the content for this page that's confusing the compiler. Can anyone spot a problem with the html content? Thanks.
I tried your code (without the extra line) and it compiled fine. Just got 1 warning about an unused variable.
It works (compiles ...) if you move the void test() part on top of dataPage()
void setup() {
}
void loop()
{
test();
}
void test() {
dataPage();
}
void dataPage() {
static const char dataPageHtml[] PROGMEM = R"=====(
<!DOCTYPE html>
<html><head>
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>WaterDeMon</title>
<link rel="icon" type="image/x-icon" href="favicon.ico" />
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.4/Chart.js"></script>
</head>
<body style="font-size: 7vw; text-align: center;">
<div style="width:15%%; float: left;">
<img src="WaterDeMon.png" style="margin:auto; width:auto; height: 48px; float: left;"/>
</div>
<div style="float:left; width:70%%; font-size: 9vw;">
<strong>WaterDeMon</strong>
</div>
<div style="width:15%%; float: right"> </div>
<div style="margin-top: 2vw; display: grid; place-items: center; font-size: 3.5vw; clear: left;">
<div style="font-size: 7vw;"><u>Water Depth History</u></div>
<em>Water Depths for Past 24hrs (feet)</em>
<canvas id="myChart" style="width:100%%;max-width:1080px"></canvas>
<div style="clear: right; font-size: 6vw;"><em>%s</em></div>
<form action="/DAT" method="GET" style="margin: 2vw">
<input type="submit" value="Refresh" style="font-size: 8vw">
</form>
<form action="/" method="GET" style="margin: 2vw">
<input type="submit" value="Home" style="font-size: 8vw">
</form>
</div>
<script>
var xValues = [%s];
var yValues = [%s];
var barColors = "blue";
new Chart("myChart", {
type: "bar",
data: {
labels: xValues,
datasets: [{
backgroundColor: barColors,
data: yValues
}]
},
options: {
scales: {
xAxes: [{
barPercentage: 1
}]
},
legend: {display: false},
title: {
display: false,
text: "Water Depths for Past 24hrs (feet),"
}
}
});
</script>
</body></html>
)=====;
)=====";
}
Looks as if everything below dataPage() is not recognized anymore ...
What version of the IDE are you using. I'm on 1.8.16.
I probably posted this in the wrong place. Sorry. I'm using Microchip Studio, not the Arduino IDE.
Microchip Studio 7 (Version: 7.0.2542 - )
Arduino IDE for Microchip and Atmel Studio 7 Version: 2021.606.0
I checked your sketch in Wokwi and it behaved as described. So it seems to be a "feature" that applies also to other platforms.
I'm quite sure that this was discussed before. And if I recall correctly, one possible solution was to place the html pages in a separate .h file; you might have to do that for each page.
Not behind a PC to test.
1 Like
So it appears this is a compiler bug. Any suggestions on how to report this? Thanks.
Microchip Studio is built on Microsoft Visual Studio and is presumably using the VS c++ compiler. I found bug references to this issue concerning the VS compiler (BUG in raw-string implementation). The fix for it is in VS2019. My current version of Microchip uses VS2017, so I guess that explains why I see the problem. Thanks to everyone who responded!
To clarify a bit further - I'm using Microchip Studio which is just Atmel Studio renamed. Atmel Studio was based on an older version of Visual Studio so it has the raw-string bug.
What I learned recently is that you can use Visual Studio directly by installing the vMicro extension, which is available from Visual Micro for VS2019 and also now VS2022.
ec2021
May 10, 2022, 2:13pm
11
And interestingly this compiles also (just a comment with one quote):
// ...
</body></html>
)=====";
//"
}
However without the quote this seems to work:
#include "index.h"
void setup() {
}
void loop()
{
test();
test1();
}
void test() {
dataPage();
}
void test1() {
dataPage1();
}
and index.h :
void dataPage() {
static const char dataPageHtml[] PROGMEM = R"=====(
<!DOCTYPE html>
<html><head>
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>WaterDeMon</title>
<link rel="icon" type="image/x-icon" href="favicon.ico" />
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.4/Chart.js"></script>
</head>
<body style="font-size: 7vw; text-align: center;">
<div style="width:15%%; float: left;">
<img src="WaterDeMon.png" style="margin:auto; width:auto; height: 48px; float: left;"/>
</div>
<div style="float:left; width:70%%; font-size: 9vw;">
<strong>WaterDeMon</strong>
</div>
<div style="width:15%%; float: right"> </div>
<div style="margin-top: 2vw; display: grid; place-items: center; font-size: 3.5vw; clear: left;">
<div style="font-size: 7vw;"><u>Water Depth History</u></div>
<em>Water Depths for Past 24hrs (feet)</em>
<canvas id="myChart" style="width:100%%;max-width:1080px"></canvas>
<div style="clear: right; font-size: 6vw;"><em>%s</em></div>
<form action="/DAT" method="GET" style="margin: 2vw">
<input type="submit" value="Refresh" style="font-size: 8vw">
</form>
<form action="/" method="GET" style="margin: 2vw">
<input type="submit" value="Home" style="font-size: 8vw">
</form>
</div>
<script>
var xValues = [%s];
var yValues = [%s];
var barColors = "blue";
new Chart("myChart", {
type: "bar",
data: {
labels: xValues,
datasets: [{
backgroundColor: barColors,
data: yValues
}]
},
options: {
scales: {
xAxes: [{
barPercentage: 1
}]
},
legend: {display: false},
title: {
display: false,
text: "Water Depths for Past 24hrs (feet),"
}
}
});
</script>
</body></html>
)=====";
}
void dataPage1() {
static const char dataPageHtml[] PROGMEM = R"=====(
<!DOCTYPE html>
<html><head>
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>WaterDeMon</title>
<link rel="icon" type="image/x-icon" href="favicon.ico" />
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.4/Chart.js"></script>
</head>
<body style="font-size: 7vw; text-align: center;">
<div style="width:15%%; float: left;">
<img src="WaterDeMon.png" style="margin:auto; width:auto; height: 48px; float: left;"/>
</div>
<div style="float:left; width:70%%; font-size: 9vw;">
<strong>WaterDeMon</strong>
</div>
<div style="width:15%%; float: right"> </div>
<div style="margin-top: 2vw; display: grid; place-items: center; font-size: 3.5vw; clear: left;">
<div style="font-size: 7vw;"><u>Water Depth History</u></div>
<em>Water Depths for Past 24hrs (feet)</em>
<canvas id="myChart" style="width:100%%;max-width:1080px"></canvas>
<div style="clear: right; font-size: 6vw;"><em>%s</em></div>
<form action="/DAT" method="GET" style="margin: 2vw">
<input type="submit" value="Refresh" style="font-size: 8vw">
</form>
<form action="/" method="GET" style="margin: 2vw">
<input type="submit" value="Home" style="font-size: 8vw">
</form>
</div>
<script>
var xValues = [%s];
var yValues = [%s];
var barColors = "blue";
new Chart("myChart", {
type: "bar",
data: {
labels: xValues,
datasets: [{
backgroundColor: barColors,
data: yValues
}]
},
options: {
scales: {
xAxes: [{
barPercentage: 1
}]
},
legend: {display: false},
title: {
display: false,
text: "Water Depths for Past 24hrs (feet),"
}
}
});
</script>
</body></html>
)=====";
}
I have VS2019 installed and installed the Arduino extension. The bug is still there! Apparently this is unrelated to the bug I saw referenced earlier and is yet another one in raw-string literals.
Koepel
May 10, 2022, 2:50pm
13
It turns out, that the source code is exactly copied, I suggest to remove the first newline and remove the tabs in front of every line.
It will look like this:
static const char dataPageHtml[] PROGMEM =
R"=====(<!DOCTYPE html>
<html><head>
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
...
</body></html>)=====";
Could you set the editor to use spaces ? No one uses the same tab size. If code is shown on Github, then the browser uses a different tab settings. When I use a macro recorder, then a cursor-down could fail. Tabs are so 1970s and are only useful for mechanical typewriters.
My test in Wokwi (make the Serial Monitor output larger):
Run IoT and embedded projects in your browser: ESP32, Arduino, Pi Pico, and more. No installation required!
What can I do to force the bug ?
Tabs are for indentation. They show the intent to indent (a space is just that—space ). Tabs having different sizes in different editors is a feature (they're flexible; different people have different preferences for how "intense" indentation is—some people like indentation 2 spaces wide, some like 4, some like 5, and some like 8). Think of it like HTML and CSS—tabs (HTML) are the structure and semantics (indentation) while the editor/code browser indentation settings (CSS) are the presentation .
(You'd be crazy to use tabs for alignment, though; that's what spaces are for. Use tabs for indentation and spaces for alignment.)
ec2021
May 10, 2022, 3:50pm
15
Copy the sketch from post #1 to Wokwi and press "compile" -> It will compile.
Now delete(!) the comment line at the end of void dataPage():
</script>
</body></html>
)=====";
//)====="; <- Delete this line completely!!!!!!
}
void test() {
dataPage();
}
Result:
It is sufficient to add //" again to allow for compilation:
</body></html>
)=====";
//"
}
void test() {
dataPage();
}
Koepel
May 10, 2022, 5:30pm
16
I have narrowed the bug down to this:
char data[] = R"=====(")=====";
// prototyping
// void test();
void setup()
{
Serial.begin(115200);
test();
}
void loop(){}
void test()
{
Serial.println("hello");
}
When the prototyping is enabled, it works. So it is the prototyping that fails (already found by ec2021).
I assume that this is caused by the Arduino pre-processor.
As ec2021 already noticed, it is the single double-quote that confuses the pre-processor.
Let's have some fun: Put two double-quotes in there and the bug is gone. Then put this line in it (from the original code) and the bug comes back:
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.4/Chart.js"></script>
I think that is another bug, where the pre-processor seems to miss a double-quote ?
There are a even number of double-quotes in that line, so how can it go wrong. It can go wrong with this:
"//"
So the complete line with two double-quotes that is not accepted is:
char data[] = R"=====("//")=====";
The //
does not even have to be directly in front of the second "
I think the pre-processor thinks that the rest of the line after the //
is just comment and it continues on the next line. In the end a double-quote is missing.
in0
May 10, 2022, 10:20pm
17
There was a previous report of incorrect sketch preprocessing caused in certain cases where a sketch contained a raw string literal :
opened 05:35PM - 22 Feb 21 UTC
type: imperfection
topic: build-process
Please see https://forum.arduino.cc/t/including-javascript-in-a-webpage-served-b… y-espasyncwebserver/697109 where the issue was raised
Source code:
```cpp
const char index_html[] PROGMEM = R"rawliteral(
<!DOCTYPE HTML><html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.7.2/css/all.css" integrity="sha384-fnmOCqbTlWIlj8LyTjo7mOUStjsKC4pOpQbqyi7RrhN7udi9RwhKkMHpvLbHG9Sr" crossorigin="anonymous">
<style>
html {
font-family: Arial;
display: inline-block;
margin: 0px auto;
text-align: center;
}
h2 { font-size: 3.0rem; }
p { font-size: 3.0rem; }
.units { font-size: 1.2rem; }
.dht-labels{
font-size: 1.5rem;
vertical-align:middle;
padding-bottom: 15px;
}
</style>
<script>
var count=10;
var counter=setInterval(timerjs, 1000); //1000 will run it every 1 second
function timerjs()
{
count=count-1;
if (count <= 0)
{
clearInterval(counter);
return;
}
document.getElementById("timerjs").innerHTML=count + " secs"; // watch for spelling
}
</script>
</head>
<body>
<h2>Remote 1 temperature & humidity</h2>
<p>
<i class="fas fa-thermometer-half" style="color:#059e8a;"></i>
<span class="dht-labels">Temperature</span>
<span id="temperature">%TEMPERATURE%</span>
<sup class="units">°C</sup>
</p>
<p>
<i class="fas fa-tint" style="color:#00add6;"></i>
<span class="dht-labels">Humidity</span>
<span id="humidity">%HUMIDITY%</span>
<sup class="units">%</sup>
</p>
<p>
Time to next sample: <span id="timerjs"></span>
</p>
</body>
<script>
setInterval(function ( ) {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
document.getElementById("temperature").innerHTML = this.responseText;
}
};
xhttp.open("GET", "/temperature", true);
xhttp.send();
}, 10000 ) ;
setInterval(function ( ) {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
document.getElementById("humidity").innerHTML = this.responseText;
}
};
xhttp.open("GET", "/humidity", true);
xhttp.send();
}, 10000 ) ;
</script>
</html>)rawliteral";
void setup()
{
}
void loop()
{
}
```
Content of C:\Users\sterretje\AppData\Local\Temp\arduino_build_600637\sketch\sketch_feb22a.ino.cpp
```cpp
#include <Arduino.h>
#line 1 "C:\\Users\\sterretje\\AppData\\Local\\Temp\\arduino_modified_sketch_915464\\sketch_feb22a.ino"
#line 1 "C:\\Users\\sterretje\\AppData\\Local\\Temp\\arduino_modified_sketch_915464\\sketch_feb22a.ino"
const char index_html[] PROGMEM = R"rawliteral(
<!DOCTYPE HTML><html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.7.2/css/all.css" integrity="sha384-fnmOCqbTlWIlj8LyTjo7mOUStjsKC4pOpQbqyi7RrhN7udi9RwhKkMHpvLbHG9Sr" crossorigin="anonymous">
<style>
html {
font-family: Arial;
display: inline-block;
margin: 0px auto;
text-align: center;
}
h2 { font-size: 3.0rem; }
p { font-size: 3.0rem; }
.units { font-size: 1.2rem; }
.dht-labels{
font-size: 1.5rem;
vertical-align:middle;
padding-bottom: 15px;
}
</style>
<script>
var count=10;
var counter=setInterval(timerjs, 1000); //1000 will run it every 1 second
#line 27 "C:\\Users\\sterretje\\AppData\\Local\\Temp\\arduino_modified_sketch_915464\\sketch_feb22a.ino"
function timerjs();
#line 27 "C:\\Users\\sterretje\\AppData\\Local\\Temp\\arduino_modified_sketch_915464\\sketch_feb22a.ino"
function timerjs()
{
count=count-1;
if (count <= 0)
{
clearInterval(counter);
return;
}
document.getElementById("timerjs").innerHTML=count + " secs"; // watch for spelling
}
</script>
</head>
<body>
<h2>Remote 1 temperature & humidity</h2>
<p>
<i class="fas fa-thermometer-half" style="color:#059e8a;"></i>
<span class="dht-labels">Temperature</span>
<span id="temperature">%TEMPERATURE%</span>
<sup class="units">°C</sup>
</p>
<p>
<i class="fas fa-tint" style="color:#00add6;"></i>
<span class="dht-labels">Humidity</span>
<span id="humidity">%HUMIDITY%</span>
<sup class="units">%</sup>
</p>
<p>
Time to next sample: <span id="timerjs"></span>
</p>
</body>
<script>
setInterval(function ( ) {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
document.getElementById("temperature").innerHTML = this.responseText;
}
};
xhttp.open("GET", "/temperature", true);
xhttp.send();
}, 10000 ) ;
setInterval(function ( ) {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
document.getElementById("humidity").innerHTML = this.responseText;
}
};
xhttp.open("GET", "/humidity", true);
xhttp.send();
}, 10000 ) ;
</script>
</html>)rawliteral";
void setup()
{
}
void loop()
{
}
```
Please note the including of `#line` in the output that does not exist in the ino file
### Additional context
#### Additional reports
- https://forum.arduino.cc/t/line-driving-me-crazy/1180650
#### Related
- https://forum.arduino.cc/t/ide-mistakes-javascript-function-for-type/953022
- https://forum.arduino.cc/t/c-super-quotes-compiler-bug/990071
The developer responded :
It's ctags
that is not able to correctly parse multil-line raw literals.
It looks like ctags is also the culprit here:
$ ctags --version
Exuberant Ctags Development, Copyright (C) 1996-2009 Darren Hiebert
Compiled: Nov 23 2016, 11:29:30
Addresses: <dhiebert@users.sourceforge.net>, http://ctags.sourceforge.net
Optional compiled features: +win32, +internal-sort
$ SKETCH_PATH="/tmp/RawStringLiteralBug.ino"
$ echo 'char data[] = R"=====(")=====";
> void setup() {
> test();
> }
> void loop() {}
> void test() {}
> ' > "$SKETCH_PATH"
$ ctags -u --language-force=c++ -f - --c++-kinds=svpf --fields=KSTtzns --line-directives "$SKETCH_PATH"
Note that there was no output at all from ctags.
Now try again with code that doesn't have a problematic raw string literal:
$ echo 'char data[] = R"=====(foo)=====";
void setup() {
test();
}
void loop() {}
void test() {}
' > "$SKETCH_PATH"
$ ctags -u --language-force=c++ -f - --c++-kinds=svpf --fields=KSTtzns --line-directives "$SKETCH_PATH"
data C:/Users/asdf/AppData/Local/Temp/RawStringLiteralBug.ino /^char data[] = R"=====(foo)=====";$/;" kind:variable line:1
setup C:/Users/asdf/AppData/Local/Temp/RawStringLiteralBug.ino /^void setup() {$/;" kind:function line:2 signature:() returntype:void
loop C:/Users/asdf/AppData/Local/Temp/RawStringLiteralBug.ino /^void loop() {}$/;" kind:function line:5 signature:() returntype:void
test C:/Users/asdf/AppData/Local/Temp/RawStringLiteralBug.ino /^void test() {}$/;" kind:function line:6 signature:() returntype:void
1 Like
I'm not familiar with ctags. Is that part of the vMicro Arduino extension to Visual Studio?
Koepel
May 11, 2022, 1:59pm
19
Arduino goes through the source code and tries to automatically add things for the compiler. That is the Arduino-preprocessor. It uses a tool called 'ctags' (Ctags - Wikipedia ). And it is that tool that fails.
Arduino blames the 'ctags' tool, and that's it. Nothing is done to fix the problem.
You can find the ctags
tool on your computer. Search for it, it is in the Arduino "tool-builder" folder.
When I run it with ctags --version
, then I get:
Exuberant Ctags Development, Copyright (C) 1996-2009 Darren Hiebert
Compiled: Nov 23 2016, 11:30:04
Addresses: dhiebert@users.sourceforge.net , http://ctags.sourceforge.net
Optional compiled features: +wildcards, +regex
I might be outdated.
I guess we'll have to accept it as is. My workaround seems to work ok so far, but ultimately I'll make the html static in a file and use AJAX.
Thank you to all who chimed in on this issue.