From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!.POSTED.blaine.gmane.org!not-for-mail From: Eric Scrivner Newsgroups: gmane.emacs.bugs Subject: bug#37910: CC Mode 5.33.2 (C++//l); CC-mode inconsistently indents everything as topmost-intro after a while Date: Sun, 10 Nov 2019 09:50:01 -0800 Message-ID: References: <20191027153956.GB27906@ACM> <20191110104811.GA6614@ACM> Mime-Version: 1.0 Content-Type: multipart/alternative; boundary="0000000000009ccda6059701a5f1" Injection-Info: blaine.gmane.org; posting-host="blaine.gmane.org:195.159.176.226"; logging-data="199492"; mail-complaints-to="usenet@blaine.gmane.org" Cc: 37910@debbugs.gnu.org To: Alan Mackenzie Original-X-From: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane.org@gnu.org Sun Nov 10 18:59:48 2019 Return-path: Envelope-to: geb-bug-gnu-emacs@m.gmane.org Original-Received: from lists.gnu.org ([209.51.188.17]) by blaine.gmane.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.89) (envelope-from ) id 1iTrV5-000pmp-PH for geb-bug-gnu-emacs@m.gmane.org; Sun, 10 Nov 2019 18:59:48 +0100 Original-Received: from localhost ([::1]:44504 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iTrV4-00040E-In for geb-bug-gnu-emacs@m.gmane.org; Sun, 10 Nov 2019 12:59:46 -0500 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]:57053) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iTrUa-0003hl-Cl for bug-gnu-emacs@gnu.org; Sun, 10 Nov 2019 12:59:22 -0500 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1iTrUU-0004EK-8J for bug-gnu-emacs@gnu.org; Sun, 10 Nov 2019 12:59:16 -0500 Original-Received: from debbugs.gnu.org ([209.51.188.43]:43699) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1iTrUM-0004DJ-DX; Sun, 10 Nov 2019 12:59:03 -0500 Original-Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1iTrUM-0007Yi-B3; Sun, 10 Nov 2019 12:59:02 -0500 X-Loop: help-debbugs@gnu.org Resent-From: Eric Scrivner Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org, bug-cc-mode@gnu.org Resent-Date: Sun, 10 Nov 2019 17:59:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 37910 X-GNU-PR-Package: emacs,cc-mode Original-Received: via spool by 37910-submit@debbugs.gnu.org id=B37910.157340873829039 (code B ref 37910); Sun, 10 Nov 2019 17:59:02 +0000 Original-Received: (at 37910) by debbugs.gnu.org; 10 Nov 2019 17:58:58 +0000 Original-Received: from localhost ([127.0.0.1]:52519 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1iTrUF-0007YC-Sv for submit@debbugs.gnu.org; Sun, 10 Nov 2019 12:58:57 -0500 Original-Received: from mail-il1-f178.google.com ([209.85.166.178]:35373) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1iTrLu-0007Lr-Jz for 37910@debbugs.gnu.org; Sun, 10 Nov 2019 12:50:20 -0500 Original-Received: by mail-il1-f178.google.com with SMTP id z12so9794710ilp.2 for <37910@debbugs.gnu.org>; Sun, 10 Nov 2019 09:50:18 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=mime-version:references:in-reply-to:from:date:message-id:subject:to :cc; bh=DoBLFVnlzg87zJQV8PAiVJINH6Up5/2DkvJl6Obaogg=; b=eBfi5Ikf3MjU9gz9CxTbixT8STjGgv5j5ReyJWO8gTTnlBtW9vJWfs2+7ZJL8HhOF8 SvwHZyfjGxJxXjDeL+WsA6kK1yQBfmC//l2uXMhYAhEsbv3KGQ4iH1YWy9F0j3NJAzg8 g45JxgUBVbUDC7wlEXfJluCZqtBKr3rS+Zyu3AuswBVFQlcu+FuTS9kxfmeb1UiR2u3q 6dAiRu/JCz/ZE7DHvaJZkvqCCt5pviPwIonFvlBeXZaIhq9+fRx+YsReXpNNakFeblOJ rIjj5IuMxSJYkFBgeoJsC6wb9h/skNtAwZVcWZT+4VY4rZH7K7qr0+TPTXmYQrjfjpmm 0ZSQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:references:in-reply-to:from:date :message-id:subject:to:cc; bh=DoBLFVnlzg87zJQV8PAiVJINH6Up5/2DkvJl6Obaogg=; b=DEjsyYWSzq1BHTWQUcJYD4KclnKInlwA+8lxkSrYKq6SNcuwtnbFXC6bFxpJ/x0II1 6qPt7ofexkTJP4+TjgS9EhQYB5VsW5SdF7rhU8FhPFaDngy6kK72/ARY/Slovm3btYSW jwrjISZveMcDWn+6qTV4vemzWCvAttL0AjHqIF9TfqEL0439wUaHms0c7wI0UKcvAcQm 400lTvQwSsm/4aAQQjFgVAhVkIjWOGWup5iItMPS5Su3CLt8+Fx/PNmPMgw3najALBnf gh+SGbOXBNTUN6N9ZbV3mH27sZGRtStj3ub6YdrVO+oV9lC7DZDT/x0VItoR18VdAcRR PrUg== X-Gm-Message-State: APjAAAWR0so7ot6AzQzUcBCME9ZQN7klZ1Tm3c/URG7qZufRu556zjQR Z9RmhVAq0RyZyJyngwa+GyNHXEJ+c2hPaP0bJnM= X-Google-Smtp-Source: APXvYqwaGeSxbq3wmn/tCRnp8TqOWxEuqW+kjsCSFE6nP1SR6VUXmz2hzfPJYOaWr8n2p6CXA3gWwh6Djayy0jHSDWo= X-Received: by 2002:a92:bf04:: with SMTP id z4mr7949266ilh.150.1573408212829; Sun, 10 Nov 2019 09:50:12 -0800 (PST) In-Reply-To: X-Mailman-Approved-At: Sun, 10 Nov 2019 12:58:52 -0500 X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 209.51.188.43 X-BeenThere: bug-gnu-emacs@gnu.org List-Id: "Bug reports for GNU Emacs, the Swiss army knife of text editors" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane.org@gnu.org Original-Sender: "bug-gnu-emacs" Xref: news.gmane.org gmane.emacs.bugs:171385 Archived-At: --0000000000009ccda6059701a5f1 Content-Type: text/plain; charset="UTF-8" Apologies for the second email here. One other possibly symptom here: This only seems to happen in buffers where I used the c++11 multi-line raw string literals. All other buffers seem to be fine atm. On Sun, Nov 10, 2019 at 9:47 AM Eric Scrivner wrote: > I've applied the patch and run emacs with it. Unfortunately, it doesn't > seem to solve the issue. One the bright side, I believe I had buffers which > can reliably reproduce the issue (at least locally). I've copied one such > file below. The issue can be reproduced by simply going to the end of > `main` and attempting to indent the `SQL_Quit()` statement. At first it > attempts to overindent the line as `statement-cont`, then if I go up and > attempt to indent the `PlatformLog` in the else statement then return to > the SDL_Quit and indent it, it has become `topmost-intro`. Apologies for > the long length of the file, but hopefully it can help with reproduction: > > #include "engine_math.h" > #include "engine_types.h" > #include "platform.h" > > #include > #include > > #include > #include > > const f32 VIEWPORT_WIDTH = 1920; > const f32 VIEWPORT_HEIGHT = 1080; > > > /////////////////////////////////////////////////////////////////////////////// > > typedef struct { > game_input Input; > } sdl2_input_state; > > typedef struct { > i32 ToneHz; > i32 ToneVolume; > i32 SampleIndex; > i32 SamplesPerSecond; > i32 BytesPerSample; > i32 WavePeriod; > f64 SineLocation; > } sdl2_audio_config; > > typedef struct { > u8* Buffer; > i32 Size; > i32 ReadCursor; > i32 WriteCursor; > b32 IsPlaying; > SDL_AudioDeviceID DeviceID; > sdl2_audio_config* AudioConfig; > } sdl2_audio_buffer; > > #if HYPERBOREAN_DEBUG > typedef struct { > v2 Pos; > v3 Color; > } sdl2_debug_colored_vertex; > > typedef struct { > i32 PlayCursor; > i32 WriteCursor; > sdl2_debug_colored_vertex V[2]; > } sdl2_debug_time_marker; > #endif > > > /////////////////////////////////////////////////////////////////////////////// > > global_variable b32 GlobalRunning; > global_variable sdl2_input_state GlobalGameInput; > global_variable sdl2_audio_buffer GlobalAudioBuffer; > > > /////////////////////////////////////////////////////////////////////////////// > > void PlatformLog(const char* const Format, ...) > { > va_list args; > va_start(args, Format); > > SDL_LogMessageV( > SDL_LOG_CATEGORY_APPLICATION, > SDL_LOG_PRIORITY_INFO, > Format, > args > ); > > va_end(args); > } > > b32 PlatformReadEntireFile(const char* path, platform_entire_file* Result) > { > FILE* file = fopen(path, "r"); > > if (file == NULL) { > return false; > } > > fseek(file, 0, SEEK_END); > Result->Size = ftell(file); > fseek(file, 0, SEEK_SET); > > Result->Contents = (u8*)malloc(Result->Size); > fread(Result->Contents, Result->Size, 1, file); > fclose(file); > > return true; > } > > void PlatformFreeEntireFile(platform_entire_file* Result) { > if (Result->Contents) { > free(Result->Contents); > Result->Contents = NULL; > Result->Size = 0; > } > } > > void PlatformAudioLock() { > SDL_LockAudioDevice(GlobalAudioBuffer.DeviceID); > } > > void PlatformAudioUnlock() { > SDL_UnlockAudioDevice(GlobalAudioBuffer.DeviceID); > } > > > /////////////////////////////////////////////////////////////////////////////// > > internal void *SDL2VirtualAlloc(u64 SizeBytes, void *BaseAddress = NULL) { > return mmap(BaseAddress, SizeBytes, PROT_READ | PROT_WRITE, > MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); > } > > > /////////////////////////////////////////////////////////////////////////////// > > internal void SDL2VirtualFree(void *Buffer, u64 SizeBytes) { > munmap(Buffer, SizeBytes); > } > > > /////////////////////////////////////////////////////////////////////////////// > > internal bool SDL2VirtualAllocSucceeded(void *Value) { > return Value != MAP_FAILED; > } > > > /////////////////////////////////////////////////////////////////////////////// > > internal void SDL2FillAudioDeviceBuffer(void *UserData, u8 *DeviceBuffer, > i32 Length) { > Assert(UserData != NULL); > Assert(DeviceBuffer != NULL); > > SDL_memset(DeviceBuffer, 0, Length); > > sdl2_audio_buffer *AudioBuffer = (sdl2_audio_buffer *)UserData; > > // Keep track of two regions. Region1 contains everything from the > current > // ReadCursor up until, potentially, the end of the buffer. Region2 only > // exists if we need to circle back around. It contains all the data > from the > // beginning of the buffer up until sufficient bytes are read to meet > Length. > int Region1Size = Length; > int Region2Size = 0; > if (AudioBuffer->ReadCursor + Length > AudioBuffer->Size) { > // Handle looping back from the beginning. > Region1Size = AudioBuffer->Size - AudioBuffer->ReadCursor; > Region2Size = Length - Region1Size; > } > > SDL_memcpy(DeviceBuffer, (AudioBuffer->Buffer + AudioBuffer->ReadCursor), > Region1Size); > SDL_memcpy(&DeviceBuffer[Region1Size], AudioBuffer->Buffer, Region2Size); > > AudioBuffer->ReadCursor = > (AudioBuffer->ReadCursor + Length) % AudioBuffer->Size; > } > > > /////////////////////////////////////////////////////////////////////////////// > > internal void SDL2InitializeAudio(sdl2_audio_buffer *AudioBuffer) { > AudioBuffer->Size = AudioBuffer->AudioConfig->SamplesPerSecond * > AudioBuffer->AudioConfig->BytesPerSample; > AudioBuffer->WriteCursor = AudioBuffer->AudioConfig->BytesPerSample; > AudioBuffer->ReadCursor = 0; > AudioBuffer->Buffer = (u8 *)SDL2VirtualAlloc(AudioBuffer->Size); > Assert(SDL2VirtualAllocSucceeded(AudioBuffer->Buffer)); > > SDL_AudioSpec AudioSettings = {}; > AudioSettings.freq = AudioBuffer->AudioConfig->SamplesPerSecond; > AudioSettings.format = AUDIO_S16; > AudioSettings.channels = 2; > // NOTE: Reduce the number of samples here to decrease audio lag by > causing > // SDL to request audio more frequently. > AudioSettings.samples = 256; > AudioSettings.callback = &SDL2FillAudioDeviceBuffer; > AudioSettings.userdata = (void *)AudioBuffer; > > SDL_AudioSpec ObtainedSettings = {}; > AudioBuffer->DeviceID = > SDL_OpenAudioDevice(NULL, 0, &AudioSettings, &ObtainedSettings, 0); > > if (AudioSettings.format != ObtainedSettings.format) { > SDL_Log("Could not open audio device: %s", SDL_GetError()); > exit(1); > } > } > > > /////////////////////////////////////////////////////////////////////////////// > > internal void SDL2Cleanup(sdl2_audio_buffer *AudioBuffer, > sdl2_input_state *InputState) { > if (AudioBuffer->Buffer) { > SDL2VirtualFree(AudioBuffer->Buffer, AudioBuffer->Size); > } > > SDL_CloseAudioDevice(AudioBuffer->DeviceID); > } > > > /////////////////////////////////////////////////////////////////////////////// > > internal void SDL2ProcessKeyDown(game_button_state *State, b32 IsDown) { > Assert(IsDown != State->EndedDown); > State->EndedDown = IsDown; > ++State->HalfTransitionCount; > } > > > /////////////////////////////////////////////////////////////////////////////// > > #if HYPERBOREAN_DEBUG > internal u32 SDL2DebugVAO; > internal u32 SDL2DebugVBO; > > internal void SDL2DrawSoundBufferMarker(sdl2_audio_buffer *AudioBuffer, > f32 C, > f32 PadX, f32 Top, f32 Bottom, > i32 Value, > sdl2_debug_colored_vertex > *Vertices, > v3 Color, u32 Shader) { > Assert(Value < AudioBuffer->Size); > f32 XReal = C * Value + PadX; > Vertices[0].Pos = {{XReal, Top}}; > Vertices[0].Color = Color; > Vertices[1].Pos = {{XReal, Bottom}}; > Vertices[1].Color = Color; > glUseProgram(Shader); > m4x4 Projection = > OrthographicProjection(0, VIEWPORT_WIDTH, 0, VIEWPORT_HEIGHT, -1.0, > 1.0); > GLint ProjectionLoc = glGetUniformLocation(Shader, "Projection"); > glUniformMatrix4fv(ProjectionLoc, 1, GL_FALSE, (float *)Projection.E); > glBindBuffer(GL_ARRAY_BUFFER, SDL2DebugVBO); > glBufferSubData(GL_ARRAY_BUFFER, 0, 2 * > sizeof(sdl2_debug_colored_vertex), > Vertices); > glBindVertexArray(SDL2DebugVAO); > glDrawArrays(GL_LINES, 0, 2); > glBindVertexArray(0); > } > > internal void SDL2DebugSyncDisplay(sdl2_audio_buffer *AudioBuffer, > u32 MarkerCount, > sdl2_debug_time_marker *Markers, > f32 TargetSecondsPerFrame, u32 Shader) { > f32 PadX = 16; > f32 PadY = 16; > > f32 Top = PadY; > f32 Bottom = VIEWPORT_HEIGHT - PadY; > > f32 C = (f32)(VIEWPORT_WIDTH - 2 * PadX) / (f32)AudioBuffer->Size; > for (u32 MarkerIndex = 0; MarkerIndex < MarkerCount; ++MarkerIndex) { > sdl2_debug_time_marker *Marker = &Markers[MarkerIndex]; > > SDL2DrawSoundBufferMarker(AudioBuffer, C, PadX, Top, Bottom, > Marker->PlayCursor, Marker->V, {{1.0, 1.0, > 1.0}}, > Shader); > SDL2DrawSoundBufferMarker(AudioBuffer, C, PadX, Top, Bottom, > Marker->WriteCursor, Marker->V, {{1.0, 1.0, > 0.0}}, > Shader); > } > } > #endif > > > /////////////////////////////////////////////////////////////////////////////// > > internal int > SDL2GetWindowRefreshRate(SDL_Window *Window) > { > SDL_DisplayMode Mode; > int DisplayIndex = SDL_GetWindowDisplayIndex(Window); > // If we can't find the refresh rate, we'll return this: > int DefaultRefreshRate = 60; > if (SDL_GetDesktopDisplayMode(DisplayIndex, &Mode) != 0) > { > return DefaultRefreshRate; > } > if (Mode.refresh_rate == 0) > { > return DefaultRefreshRate; > } > return Mode.refresh_rate; > } > > > /////////////////////////////////////////////////////////////////////////////// > > internal void SDL2HandleEvent(SDL_Event* Event, sdl2_input_state* > InputState) > { > if (Event->type == SDL_QUIT) > { > GlobalRunning = false; > } > else if (Event->type == SDL_KEYDOWN || Event->type == SDL_KEYUP) > { > SDL_Keycode KeyCode = Event->key.keysym.sym; > bool IsDown = Event->key.state == SDL_PRESSED; > bool WasDown = (Event->key.state == SDL_RELEASED || Event->key.repeat > != 0); > > // Eat key repeats > if (IsDown != WasDown) > { > if (KeyCode == SDLK_LEFT) > { > SDL2ProcessKeyDown(&InputState->Input.Controller.MoveLeft, IsDown); > } > else if (KeyCode == SDLK_RIGHT) > { > SDL2ProcessKeyDown(&InputState->Input.Controller.MoveRight, > IsDown); > } > else if (KeyCode == SDLK_UP) > { > SDL2ProcessKeyDown(&InputState->Input.Controller.MoveUp, IsDown); > } > else if (KeyCode == SDLK_DOWN) > { > SDL2ProcessKeyDown(&InputState->Input.Controller.MoveDown, IsDown); > } > else if (KeyCode == SDLK_SPACE) > { > SDL2ProcessKeyDown(&InputState->Input.Controller.ActionDown, > IsDown); > } > else if (KeyCode == SDLK_ESCAPE) > { > SDL2ProcessKeyDown(&InputState->Input.Controller.Back, IsDown); > } > } > } > else if (Event->type == SDL_MOUSEMOTION) > { > InputState->Input.MouseP.X = Event->motion.x; > InputState->Input.MouseP.Y = Event->motion.y; > } > else if (Event->type == SDL_MOUSEBUTTONDOWN || Event->type == > SDL_MOUSEBUTTONUP) > { > bool IsDown = Event->button.state == SDL_PRESSED; > bool WasDown = (Event->button.state == SDL_RELEASED || > Event->button.clicks != 1); > > if (IsDown != WasDown) { > if (Event->button.button == SDL_BUTTON_LEFT) { > SDL2ProcessKeyDown(&InputState->Input.MouseLeft, IsDown); > } > if (Event->button.button == SDL_BUTTON_RIGHT) { > SDL2ProcessKeyDown(&InputState->Input.MouseRight, IsDown); > } > } > } > } > > > /////////////////////////////////////////////////////////////////////////////// > > int main() { > if (SDL_Init(SDL_INIT_EVERYTHING) == 0) > { > SDL_Window* Window = SDL_CreateWindow( > "Hyperborean", > SDL_WINDOWPOS_UNDEFINED, > SDL_WINDOWPOS_UNDEFINED, > VIEWPORT_WIDTH, > VIEWPORT_HEIGHT, > SDL_WINDOW_OPENGL | SDL_WINDOW_ALLOW_HIGHDPI > ); > > if (Window != NULL) > { > SDL_GLContext GLContext = SDL_GL_CreateContext(Window); > > if (GLContext != NULL) > { > GLenum GlewResult = glewInit(); > if (GlewResult == GLEW_OK) > { > PlatformLog("OpenGL Vendor: %s", glGetString(GL_VENDOR)); > PlatformLog("OpenGL Version: %s", glGetString(GL_VERSION)); > PlatformLog("OpenGL Renderer: %s", glGetString(GL_RENDERER)); > > if (SDL_GL_SetSwapInterval(1) != 0) { > PlatformLog("Unable to SetSwapInterval: %s", SDL_GetError()); > } > > game_memory GameMemory = {}; > > #if HYPERBOREAN_INTERNAL > // NOTE: Hard-code the base address so locations remain constant > between runs > void* BaseAddress = (void*)Terabytes(2); > #else > void* BaseAddress = NULL; > #endif > > GameMemory.PermanentStorageSize = Megabytes(512); > GameMemory.TransientStorageSize = Gigabytes((u64)4); > > u64 TotalSize = > GameMemory.PermanentStorageSize + > GameMemory.TransientStorageSize; > GameMemory.PermanentStorage = SDL2VirtualAlloc(TotalSize, > BaseAddress); > Assert(SDL2VirtualAllocSucceeded(GameMemory.PermanentStorage)); > GameMemory.TransientStorage = ( > (u8*)GameMemory.PermanentStorage + > GameMemory.PermanentStorageSize); > > // Initialize keyboard input > GlobalGameInput = {}; > GlobalGameInput.Input.WindowDim.W = VIEWPORT_WIDTH; > GlobalGameInput.Input.WindowDim.H = VIEWPORT_HEIGHT; > GlobalGameInput.Input.Controller.IsConnected = true; > GlobalGameInput.Input.Controller.IsAnalog = true; > > u32 MaxVolume = 3000; > > GlobalAudioBuffer = {}; > sdl2_audio_config AudioConfig = {}; > AudioConfig.ToneHz = 261; > AudioConfig.ToneVolume = 0.10 * MaxVolume; > AudioConfig.SampleIndex = 0; > AudioConfig.SamplesPerSecond = 48000; > AudioConfig.BytesPerSample = 2 * sizeof(i16); > AudioConfig.WavePeriod = AudioConfig.SamplesPerSecond / > AudioConfig.ToneHz; > GlobalAudioBuffer.AudioConfig = &AudioConfig; > > SDL2InitializeAudio(&GlobalAudioBuffer); > > // Get screen refresh rate. > PlatformLog("Refresh Rate: %d Hz\n", > SDL2GetWindowRefreshRate(Window)); > i32 GameUpdateHz = 60; > f32 TargetSecondsPerFrame = 1.0f / (float)GameUpdateHz; > PlatformLog("Target Secs/Frame: %f\n", TargetSecondsPerFrame); > > // TODO(eric): Feed DPI information into our game and use it for > scaling. > f32 DDPI = 0; > f32 HDPI = 0; > f32 VDPI = 0; > if (SDL_GetDisplayDPI(0, &DDPI, &HDPI, &VDPI) != 0) { > PlatformLog("Unable to get display DPI: %s", SDL_GetError()); > } > PlatformLog("Display DPI: %f - %f x %f", DDPI, HDPI, VDPI); > > f32 FPS = 0; > f32 MPF = 0; > > char WindowTitle[256] = {}; > u64 BeginCounter = SDL_GetPerformanceCounter(); > u64 PerfCounterFrequency = SDL_GetPerformanceFrequency(); > u64 BeginCycles = __rdtsc(); > > #if HYPERBOREAN_DEBUG > game_state* State = (game_state*)GameMemory.PermanentStorage; > u32 DebugMarkerShader = CompileShaders( > &State->TransientArena, > R"END( > #version 430 core > layout (location = 0) in vec2 Position; > layout (location = 1) in vec3 Color; > uniform mat4 Projection; > > out vec3 FragmentColor; > > void main() > { > FragmentColor = Color; > gl_Position = vec4(Position, 0.0, 1.0) * Projection; > } > )END", > R"END( > #version 430 core > in vec3 FragmentColor; > > out vec4 ResultingColor; > > void main() > { > ResultingColor = vec4(FragmentColor, 1.0); > } > )END" > ); > u32 DebugTimeMarkerIndex = 0; > sdl2_debug_time_marker DebugTimeMarkers[GameUpdateHz / 2] = {0}; > PlatformLog("Num Markers: %d\n", ArrayCount(DebugTimeMarkers)); > > glGenVertexArrays(1, &SDL2DebugVAO); > glBindVertexArray(SDL2DebugVAO); > > glGenBuffers(1, &SDL2DebugVBO); > glBindBuffer(GL_ARRAY_BUFFER, SDL2DebugVBO); > glBufferData(GL_ARRAY_BUFFER, > 2*sizeof(sdl2_debug_colored_vertex), NULL, GL_DYNAMIC_DRAW); > glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, > sizeof(sdl2_debug_colored_vertex), NULL); > glEnableVertexAttribArray(0); > glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, > sizeof(sdl2_debug_colored_vertex), (void*)sizeof(v2)); > glEnableVertexAttribArray(1); > > glBindBuffer(GL_ARRAY_BUFFER, 0); > glBindVertexArray(0); > #endif > > u32 BeginTimeMs = SDL_GetTicks(); > > GlobalRunning = true; > SDL_Event event; > while (GlobalRunning) { > while (SDL_PollEvent(&event)) { > SDL2HandleEvent(&event, &GlobalGameInput); > } > > game_input GameInput = {}; > memcpy(&GameInput, &GlobalGameInput.Input, sizeof(game_input)); > > game_audio_buffer AudioBuffer = {}; > AudioBuffer.Buffer = GlobalAudioBuffer.Buffer; > AudioBuffer.Size = GlobalAudioBuffer.Size; > AudioBuffer.ReadCursor = GlobalAudioBuffer.ReadCursor; > AudioBuffer.WriteCursor = GlobalAudioBuffer.WriteCursor; > AudioBuffer.ToneVolume = > GlobalAudioBuffer.AudioConfig->ToneVolume; > AudioBuffer.SamplesPerSecond = > GlobalAudioBuffer.AudioConfig->SamplesPerSecond; > AudioBuffer.BytesPerSample = > GlobalAudioBuffer.AudioConfig->BytesPerSample; > > SDL_LockAudioDevice(GlobalAudioBuffer.DeviceID); > u32 EndTimeMs = SDL_GetTicks(); > GameInput.DeltaTimeSecs = (EndTimeMs - BeginTimeMs) / 1000.0f; > GameUpdateAndRender(&GameMemory, &GameInput, &AudioBuffer); > BeginTimeMs = EndTimeMs; > SDL_UnlockAudioDevice(GlobalAudioBuffer.DeviceID); > > // NOTE: Unpause for the first time here to avoid startup lag > due > // to SDL already playing audio from an empty buffer. Unpausing > // here allows audio to begin playing immediately at > application > // start. > if (!GlobalAudioBuffer.IsPlaying) > { > SDL_PauseAudioDevice(GlobalAudioBuffer.DeviceID, 0); > GlobalAudioBuffer.IsPlaying = true; > } > > // NOTE: Copy back out the write cursor state for the circular > audio buffer > GlobalAudioBuffer.WriteCursor = AudioBuffer.WriteCursor; > > for (size_t ButtonIndex = 0; > ButtonIndex < > ArrayCount(GlobalGameInput.Input.Controller.Buttons); > ButtonIndex++) > { > > GlobalGameInput.Input.Controller.Buttons[ButtonIndex].HalfTransitionCount = > 0; > } > > if (GameInput.QuitRequested) > { > GlobalRunning = false; > } > > #if HYPERBOREAN_DEBUG > { > sdl2_debug_time_marker* Marker = > &DebugTimeMarkers[DebugTimeMarkerIndex++]; > if (DebugTimeMarkerIndex >= ArrayCount(DebugTimeMarkers)) { > DebugTimeMarkerIndex = 0; > } > > Marker->PlayCursor = GlobalAudioBuffer.ReadCursor; > Marker->WriteCursor = GlobalAudioBuffer.WriteCursor; > > SDL2DebugSyncDisplay(&GlobalAudioBuffer, > ArrayCount(DebugTimeMarkers), DebugTimeMarkers, TargetSecondsPerFrame, > DebugMarkerShader); > } > #endif > > SDL_GL_SwapWindow(Window); > > u64 EndCounter = SDL_GetPerformanceCounter(); > u64 CounterElapsed = EndCounter - BeginCounter; > > u64 EndCycles = __rdtsc(); > u64 CyclesElapsed = EndCycles - BeginCycles; > FPS = PerfCounterFrequency / (float)CounterElapsed; > f32 SPF = (float)CounterElapsed / PerfCounterFrequency; > MPF = 1000.0f * CounterElapsed / (double)PerfCounterFrequency; > i32 MCPF = SafeTruncateUInt64(CyclesElapsed / (1000 * 1000)); > > BeginCounter = EndCounter; > BeginCycles = EndCycles; > sprintf( > WindowTitle, > "Hyperborean - %0.02f f/s, %0.04f s/f, %0.02f ms/f, %d mc/f", > FPS, SPF, MPF, MCPF > ); > SDL_SetWindowTitle(Window, WindowTitle); > } > > GameCleanup(&GameMemory); > #if HYPERBOREAN_DEBUG > glDeleteBuffers(1, &SDL2DebugVAO); > glDeleteBuffers(1, &SDL2DebugVBO); > glDeleteShader(DebugMarkerShader); > #endif > > SDL2VirtualFree(GameMemory.PermanentStorage, > GameMemory.PermanentStorageSize); > SDL2VirtualFree(GameMemory.TransientStorage, > GameMemory.TransientStorageSize); > > SDL2Cleanup(&GlobalAudioBuffer, &GlobalGameInput); > } > else > { > PlatformLog("Unable to initialize GLEW: %s\n", > glewGetErrorString(GlewResult)); > } > > SDL_GL_DeleteContext(GLContext); > } > else > { > PlatformLog("Failed to create OpenGL context: %s", SDL_GetError()); > } > > SDL_DestroyWindow(Window); > } > else > { > PlatformLog("Failed to create window: %s", SDL_GetError()); > } > > SDL_Quit(); > } > else > { > PlatformLog("Failed to initialize SDL: %s", SDL_GetError()); > } > > return EXIT_SUCCESS; > } > > On Sun, Nov 10, 2019 at 2:48 AM Alan Mackenzie wrote: > >> Hello, Eric. >> >> Now for a top-post. ;-) >> >> I think I may have found the cause of the bug. It may have been caused >> by overwriting lisp list structure, rather than creating new (parallel) >> list structures - a sort of corruption. See below for a fuller >> explanation. This hypothesis is entirely consistent with the observed >> result (spurious topmost-intro's). >> >> Would you please apply the patch below and byte-compile the result. It >> suffices just to compile cc-engine.el. (If you want any help with >> applying the patch or byte compiling, feel free to send me private >> email.) >> >> Then please try out the patched CC Mode for however long it has taken, >> in the past, to see the sort of bug you reported, and then somewhat >> longer. If the bug fails to show itself, we may well have fixed it. >> Please let me know how things are going. >> >> ############## Optional section. An explanation ####################### >> >> One of the caches CC Mode uses, "c-state-cache", keeps track of the >> nested brace structure. It is (re)calculated on calling the lisp >> function c-parse-state. In essence, it records the position of each >> enclosing brace in a list, the most nested first. So if we had the >> following C++ structure: >> >> { // 1 >> ...... >> { // 2 >> ...... >> { // 3 >> ...... >> >> , and was at the marked position, our c-state-cache would be the >> list of the three brace positions (P3 P2 P1). One of its uses is >> determining if some point is at the top level or not. If the >> c-state-cache list for that point is empty, it is at the top level. >> >> As point moves through the buffer, and c-parse-state is called from >> somewhere else, c-state-cache is "altered" in a highly optimised >> fashion. This avoids having to scan large portions of the buffer too >> often, to determine the brace structure. The nature of this "altering" >> is what is causing the problem. >> >> When the buffer is narrowed, say beginning with the brace 2, calling >> c-parse-state now has to return (P3 P2), because the brace 1 is now >> outside the visible portion. >> >> The suspected bug cause is the way (P3 P2 P1) is changed to (P3 P2) on >> this narrowing. Up to now the list structure itself has been changed, >> rather than making a copy of the structure. >> >> So, what may have been happening is that CC Mode is looping through the >> c-state-cache to determine whether point is at top level. (Being >> directly inside a class or namespace, etc., counts as "top level"). If >> point is inside brace 1, the loop will try to determine that P1 is not a >> class, etc., and return "not at top level". However, if c-parse-state >> had been called with the above narrowing, c-state-cache is now (P3 P2), >> point appears to be outside every brace, and the loop spuriously returns >> "at top level". This is what I think has been happening. >> >> When the code wrongly reports "at top level", we get the unwanted >> topmost-intro analyses. >> >> The solution to this is when the buffer is narrowed and we call >> c-parse-state, we make a COPY of the c-state-cache list, leaving the >> original unmolested for its original owner. This is what the patch >> does. >> >> ############## End of optional section. ################################ >> >> Here is the patch. It should work in Emacs-26.3, even though the line >> numbers are now a bit different: >> >> >> >> diff -r 2783baa48d44 cc-engine.el >> --- a/cc-engine.el Fri Oct 25 20:00:14 2019 +0000 >> +++ b/cc-engine.el Sun Nov 10 10:30:17 2019 +0000 >> @@ -3690,7 +3690,13 @@ >> ; brace pair. >> (setq c-state-cache nil >> c-state-cache-good-pos c-state-min-scan-pos) >> - (setcdr ptr nil) >> + ;; Do not alter the original `c-state-cache' structure, since >> there >> + ;; may be a loop suspended which is looping through that >> structure. >> + ;; This may have been the cause of bug #37910. >> + (let ((cdr-ptr (cdr ptr))) >> + (setcdr ptr nil) >> + (setq c-state-cache (copy-sequence c-state-cache)) >> + (setcdr ptr cdr-ptr)) >> (setq c-state-cache-good-pos (1+ (c-state-cache-top-lparen)))) >> ))) >> >> @@ -3793,11 +3799,12 @@ >> (setq new-cons (cons bra (1+ ce))) >> (cond >> ((consp (car c-state-cache)) >> - (setcar c-state-cache new-cons)) >> + (setq c-state-cache (cons new-cons (cdr >> c-state-cache)))) >> ((and (numberp (car c-state-cache)) ; probably never >> happens >> (< ce (car c-state-cache))) >> - (setcdr c-state-cache >> - (cons new-cons (cdr c-state-cache)))) >> + (setq c-state-cache >> + (cons (car c-state-cache) >> + (cons new-cons (cdr c-state-cache))))) >> (t (setq c-state-cache (cons new-cons c-state-cache))))) >> >> ;; We haven't found a brace pair. Record this in the cache. >> @@ -3998,7 +4005,7 @@ >> (when (and c-state-cache >> (consp (car c-state-cache)) >> (> (cdar c-state-cache) upper-lim)) >> - (setcar c-state-cache (caar c-state-cache)) >> + (setq c-state-cache (cons (caar c-state-cache) (cdr >> c-state-cache))) >> (setq scan-back-pos (car c-state-cache) >> cons-separated t)) >> >> @@ -4135,7 +4142,7 @@ >> ;; knowledge of what's inside these braces, we have no alternative >> but >> ;; to direct the caller to scan the buffer from the opening brace. >> (setq pos (caar c-state-cache)) >> - (setcar c-state-cache pos) >> + (setq c-state-cache (cons pos (cdr c-state-cache))) >> (list (1+ pos) pos t)) ; return value. We've just converted a >> brace pair >> ; entry into a { entry, so the caller needs >> to >> ; search for a brace pair before the {. >> >> >> >> >> On Sun, Oct 27, 2019 at 15:39:56 +0000, Alan Mackenzie wrote: >> > Hello, Eric. >> >> > On Thu, Oct 24, 2019 at 12:06:18 -0700, Eric Scrivner wrote: >> > > This seems related to (if not the same as) bug #5490. >> >> > > - This happens randomly and then randomly stops happening (cache >> expiry >> > > maybe?) >> > > - M-x revert-buffer does not fix. >> >> > Thanks for taking the trouble to report this bug, and thanks even more >> > for including so much information. >> >> > > Here's a snippet from the buffer at the time this happen, as you can >> see >> > > there seems to be a region until the end where everything becomes >> > > topmost-intro: >> >> > > } // ((block-close 18328)) >> > > // ((statement 9560)) >> > > SDL_DestroyWindow(Window); // ((statement 9560)) >> > > } // ((block-close 9490)) >> > > else // ((else-clause 9466)) >> > > { // >> > > ((substatement-open 18464)) >> > > PlatformLog("Failed to create window: %s", SDL_GetError()); // >> > > ((statement-block-intro 18473)) >> > > } // ((block-close 18473)) >> > > // ((topmost-intro 18576)) >> > > // ((topmost-intro 18576)) >> > > SDL_Quit(); // ((topmost-intro 18541)) >> > > } // ((topmost-intro 18548)) >> > > else // ((else-clause 9188)) >> > > { // ((substatement-open 18845)) >> > > PlatformLog("Failed to initialize SDL: %s", SDL_GetError()); // >> > > ((statement-block-intro 18901))((statement-block-intro 18724)) >> > > } // >> > > ((block-close 18901)) >> > > // ((topmost-intro 19093)) >> > > return EXIT_SUCCESS; // ((topmost-intro 19093)) >> > > } // ((topmost-intro 19242)) >> >> > At the moment, all I can do is acknowledge receipt of your report. It's >> > obviously not an easy bug to diagnose. >> >> > I can see two ways of making progress: (i) Inspecting >> > c-guess-basic-syntax, the function which analyses code and produces >> > (amongs other things) all these topmost-intro's. It is essentially a >> > large cond form (Lisp's equivalent of a switch), and the single place >> > which produces topmost-intro comes fairly early on in this cond form; >> > (ii) Determine what aspects of a buffer do not get reinitialised after >> > evaluating M-x revert-buffer. That could provide some clue. >> >> > [ CC Mode config dump acknowledged with thanks, but snipped ] >> >> > Just one thing. If you haven't already done so, could you make a backup >> > copy of a buffer which triggers the bug, just in case after some future >> > edit it no longer does so. Thanks! >> >> -- >> Alan Mackenzie (Nuremberg, Germany). >> > --0000000000009ccda6059701a5f1 Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable
Apologies for the second email here. One other possibly sy= mptom here: This only seems to happen in buffers where I used the c++11 mul= ti-line raw string literals. All other buffers seem to be fine atm.

On S= un, Nov 10, 2019 at 9:47 AM Eric Scrivner <eric.t.scrivner@gmail.com> wrote:
=
I've applied the patch and run emacs with it. Unfortunately, it do= esn't seem to solve the issue. One the bright side, I believe I had buf= fers which can reliably reproduce the issue (at least locally). I've co= pied one such file below. The issue can be reproduced by simply going to th= e end of `main` and attempting to indent the `SQL_Quit()` statement. At fir= st it attempts to overindent the line as `statement-cont`, then if I go up = and attempt to indent the `PlatformLog` in the else statement then return t= o the SDL_Quit and indent it, it has become `topmost-intro`. Apologies for = the long length of the file, but hopefully it can help with reproduction:

#include "engine_math.h"
#include &quo= t;engine_types.h"
#include "platform.h"

#include &= lt;SDL.h>
#include <SDL_opengl.h>

#include <sys/mman.= h>
#include <x86intrin.h>

const f32 VIEWPORT_WIDTH =3D 1= 920;
const f32 VIEWPORT_HEIGHT =3D 1080;

////////////////////////= ///////////////////////////////////////////////////////

typedef stru= ct {
=C2=A0 game_input Input;
} sdl2_input_state;

typedef stru= ct {
=C2=A0 i32 ToneHz;
=C2=A0 i32 ToneVolume;
=C2=A0 i32 SampleIn= dex;
=C2=A0 i32 SamplesPerSecond;
=C2=A0 i32 BytesPerSample;
=C2= =A0 i32 WavePeriod;
=C2=A0 f64 SineLocation;
} sdl2_audio_config;
=
typedef struct {
=C2=A0 u8* Buffer;
=C2=A0 i32 Size;
=C2=A0 i3= 2 ReadCursor;
=C2=A0 i32 WriteCursor;
=C2=A0 b32 IsPlaying;
=C2=A0= SDL_AudioDeviceID DeviceID;
=C2=A0 sdl2_audio_config* AudioConfig;
}= sdl2_audio_buffer;

#if HYPERBOREAN_DEBUG
typedef struct {
=C2= =A0 v2 Pos;
=C2=A0 v3 Color;
} sdl2_debug_colored_vertex;

type= def struct {
=C2=A0 i32 PlayCursor;
=C2=A0 i32 WriteCursor;
=C2=A0= sdl2_debug_colored_vertex V[2];
} sdl2_debug_time_marker;
#endif
=
///////////////////////////////////////////////////////////////////////= ////////

global_variable b32 GlobalRunning;
global_variable sdl2_= input_state GlobalGameInput;
global_variable sdl2_audio_buffer GlobalAud= ioBuffer;

//////////////////////////////////////////////////////////= /////////////////////

void PlatformLog(const char* const Format, ...= )
{
=C2=A0 va_list args;
=C2=A0 va_start(args, Format);

=C2= =A0 SDL_LogMessageV(
=C2=A0 =C2=A0 SDL_LOG_CATEGORY_APPLICATION,
=C2= =A0 =C2=A0 SDL_LOG_PRIORITY_INFO,
=C2=A0 =C2=A0 Format,
=C2=A0 =C2=A0= args
=C2=A0 );

=C2=A0 va_end(args);
}

b32 PlatformRead= EntireFile(const char* path, platform_entire_file* Result) {
=C2=A0 FILE= * file =3D fopen(path, "r");

=C2=A0 if (file =3D=3D NULL) = {
=C2=A0 =C2=A0 return false;
=C2=A0 }

=C2=A0 fseek(file, 0, S= EEK_END);
=C2=A0 Result->Size =3D ftell(file);
=C2=A0 fseek(file, = 0, SEEK_SET);

=C2=A0 Result->Contents =3D (u8*)malloc(Result->= Size);
=C2=A0 fread(Result->Contents, Result->Size, 1, file);
= =C2=A0 fclose(file);

=C2=A0 return true;
}

void PlatformFr= eeEntireFile(platform_entire_file* Result) {
=C2=A0 if (Result->Conte= nts) {
=C2=A0 =C2=A0 free(Result->Contents);
=C2=A0 =C2=A0 Result-= >Contents =3D NULL;
=C2=A0 =C2=A0 Result->Size =3D 0;
=C2=A0 }<= br>}

void PlatformAudioLock() {
=C2=A0 SDL_LockAudioDevice(Global= AudioBuffer.DeviceID);
}

void PlatformAudioUnlock() {
=C2=A0 S= DL_UnlockAudioDevice(GlobalAudioBuffer.DeviceID);
}

/////////////= //////////////////////////////////////////////////////////////////

i= nternal void *SDL2VirtualAlloc(u64 SizeBytes, void *BaseAddress =3D NULL) {=
=C2=A0 return mmap(BaseAddress, SizeBytes, PROT_READ | PROT_WRITE,
= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 MAP_ANONYMOUS | MAP_PRIVAT= E, -1, 0);
}

////////////////////////////////////////////////////= ///////////////////////////

internal void SDL2VirtualFree(void *Buff= er, u64 SizeBytes) {
=C2=A0 munmap(Buffer, SizeBytes);
}

/////= //////////////////////////////////////////////////////////////////////////<= br>
internal bool SDL2VirtualAllocSucceeded(void *Value) {
=C2=A0 ret= urn Value !=3D MAP_FAILED;
}

////////////////////////////////////= ///////////////////////////////////////////

internal void SDL2FillAu= dioDeviceBuffer(void *UserData, u8 *DeviceBuffer,
=C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 i32 Length) {
=C2=A0 Asser= t(UserData !=3D NULL);
=C2=A0 Assert(DeviceBuffer !=3D NULL);

=C2= =A0 SDL_memset(DeviceBuffer, 0, Length);

=C2=A0 sdl2_audio_buffer *A= udioBuffer =3D (sdl2_audio_buffer *)UserData;

=C2=A0 // Keep track o= f two regions. Region1 contains everything from the current
=C2=A0 // Re= adCursor up until, potentially, the end of the buffer. Region2 only
=C2= =A0 // exists if we need to circle back around. It contains all the data fr= om the
=C2=A0 // beginning of the buffer up until sufficient bytes are r= ead to meet Length.
=C2=A0 int Region1Size =3D Length;
=C2=A0 int Reg= ion2Size =3D 0;
=C2=A0 if (AudioBuffer->ReadCursor + Length > Audi= oBuffer->Size) {
=C2=A0 =C2=A0 // Handle looping back from the beginn= ing.
=C2=A0 =C2=A0 Region1Size =3D AudioBuffer->Size - AudioBuffer-&g= t;ReadCursor;
=C2=A0 =C2=A0 Region2Size =3D Length - Region1Size;
=C2= =A0 }

=C2=A0 SDL_memcpy(DeviceBuffer, (AudioBuffer->Buffer + Audi= oBuffer->ReadCursor),
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0Region1Size);
=C2=A0 SDL_memcpy(&DeviceBuffer[Region1Size], Audio= Buffer->Buffer, Region2Size);

=C2=A0 AudioBuffer->ReadCursor = =3D
=C2=A0 =C2=A0 =C2=A0 (AudioBuffer->ReadCursor + Length) % AudioBu= ffer->Size;
}

////////////////////////////////////////////////= ///////////////////////////////

internal void SDL2InitializeAudio(sd= l2_audio_buffer *AudioBuffer) {
=C2=A0 AudioBuffer->Size =3D AudioBuf= fer->AudioConfig->SamplesPerSecond *
=C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 AudioBuffer->AudioConfi= g->BytesPerSample;
=C2=A0 AudioBuffer->WriteCursor =3D AudioBuffer= ->AudioConfig->BytesPerSample;
=C2=A0 AudioBuffer->ReadCursor = =3D 0;
=C2=A0 AudioBuffer->Buffer =3D (u8 *)SDL2VirtualAlloc(AudioBuf= fer->Size);
=C2=A0 Assert(SDL2VirtualAllocSucceeded(AudioBuffer->B= uffer));

=C2=A0 SDL_AudioSpec AudioSettings =3D {};
=C2=A0 AudioS= ettings.freq =3D AudioBuffer->AudioConfig->SamplesPerSecond;
=C2= =A0 AudioSettings.format =3D AUDIO_S16;
=C2=A0 AudioSettings.channels = =3D 2;
=C2=A0 // NOTE: Reduce the number of samples here to decrease aud= io lag by causing
=C2=A0 // SDL to request audio more frequently.
=C2= =A0 AudioSettings.samples =3D 256;
=C2=A0 AudioSettings.callback =3D &am= p;SDL2FillAudioDeviceBuffer;
=C2=A0 AudioSettings.userdata =3D (void *)A= udioBuffer;

=C2=A0 SDL_AudioSpec ObtainedSettings =3D {};
=C2=A0 = AudioBuffer->DeviceID =3D
=C2=A0 =C2=A0 =C2=A0 SDL_OpenAudioDevice(NU= LL, 0, &AudioSettings, &ObtainedSettings, 0);

=C2=A0 if (Aud= ioSettings.format !=3D ObtainedSettings.format) {
=C2=A0 =C2=A0 SDL_Log(= "Could not open audio device: %s", SDL_GetError());
=C2=A0 =C2= =A0 exit(1);
=C2=A0 }
}

//////////////////////////////////////= /////////////////////////////////////////

internal void SDL2Cleanup(= sdl2_audio_buffer *AudioBuffer,
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 sdl2_input_state *Inpu= tState) {
=C2=A0 if (AudioBuffer->Buffer) {
=C2=A0 =C2=A0 SDL2Virt= ualFree(AudioBuffer->Buffer, AudioBuffer->Size);
=C2=A0 }

= =C2=A0 SDL_CloseAudioDevice(AudioBuffer->DeviceID);
}

////////= ///////////////////////////////////////////////////////////////////////
=
internal void SDL2ProcessKeyDown(game_button_state *State, b32 IsDown) = {
=C2=A0 Assert(IsDown !=3D State->EndedDown);
=C2=A0 State->En= dedDown =3D IsDown;
=C2=A0 ++State->HalfTransitionCount;
}

= ///////////////////////////////////////////////////////////////////////////= ////

#if HYPERBOREAN_DEBUG
internal u32 SDL2DebugVAO;
internal= u32 SDL2DebugVBO;

internal void SDL2DrawSoundBufferMarker(sdl2_audi= o_buffer *AudioBuffer, f32 C,
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 f32 PadX, f32 Top, f32 Bottom,
=C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 i32 Value,
=C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 sdl2_debug_colo= red_vertex *Vertices,
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 v3 Color, u32 Shader) {
=C2=A0 Assert(Value < Audio= Buffer->Size);
=C2=A0 f32 XReal =3D C * Value + PadX;
=C2=A0 Verti= ces[0].Pos =3D {{XReal, Top}};
=C2=A0 Vertices[0].Color =3D Color;
= =C2=A0 Vertices[1].Pos =3D {{XReal, Bottom}};
=C2=A0 Vertices[1].Color = =3D Color;
=C2=A0 glUseProgram(Shader);
=C2=A0 m4x4 Projection =3D=C2=A0 =C2=A0 =C2=A0 OrthographicProjection(0, VIEWPORT_WIDTH, 0, VIEWPORT= _HEIGHT, -1.0, 1.0);
=C2=A0 GLint ProjectionLoc =3D glGetUniformLocation= (Shader, "Projection");
=C2=A0 glUniformMatrix4fv(ProjectionLo= c, 1, GL_FALSE, (float *)Projection.E);
=C2=A0 glBindBuffer(GL_ARRAY_BUF= FER, SDL2DebugVBO);
=C2=A0 glBufferSubData(GL_ARRAY_BUFFER, 0, 2 * sizeo= f(sdl2_debug_colored_vertex),
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 Vertices);
=C2=A0 glBindVertexArray(SDL2DebugVAO);<= br>=C2=A0 glDrawArrays(GL_LINES, 0, 2);
=C2=A0 glBindVertexArray(0);
= }

internal void SDL2DebugSyncDisplay(sdl2_audio_buffer *AudioBuffer,=
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0u32 MarkerCount,
= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0sdl2_debug_time_marker = *Markers,
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0f32 TargetSe= condsPerFrame, u32 Shader) {
=C2=A0 f32 PadX =3D 16;
=C2=A0 f32 PadY = =3D 16;

=C2=A0 f32 Top =3D PadY;
=C2=A0 f32 Bottom =3D VIEWPORT_H= EIGHT - PadY;

=C2=A0 f32 C =3D (f32)(VIEWPORT_WIDTH - 2 * PadX) / (f= 32)AudioBuffer->Size;
=C2=A0 for (u32 MarkerIndex =3D 0; MarkerIndex = < MarkerCount; ++MarkerIndex) {
=C2=A0 =C2=A0 sdl2_debug_time_marker = *Marker =3D &Markers[MarkerIndex];

=C2=A0 =C2=A0 SDL2DrawSoundBu= fferMarker(AudioBuffer, C, PadX, Top, Bottom,
=C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 Marker->PlayCursor, Marker->V, {{1.0, 1.0, 1.0}},
=C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 Shader);
=C2=A0 =C2=A0 SDL2DrawSoundBufferMarke= r(AudioBuffer, C, PadX, Top, Bottom,
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 Marke= r->WriteCursor, Marker->V, {{1.0, 1.0, 0.0}},
=C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 Shader);
=C2=A0 }
}
#endif

/////////////////////= //////////////////////////////////////////////////////////

internal = int
SDL2GetWindowRefreshRate(SDL_Window *Window)
{
=C2=A0 =C2=A0 S= DL_DisplayMode Mode;
=C2=A0 =C2=A0 int DisplayIndex =3D SDL_GetWindowDis= playIndex(Window);
=C2=A0 =C2=A0 // If we can't find the refresh rat= e, we'll return this:
=C2=A0 =C2=A0 int DefaultRefreshRate =3D 60;=C2=A0 =C2=A0 if (SDL_GetDesktopDisplayMode(DisplayIndex, &Mode) !=3D= 0)
=C2=A0 =C2=A0 {
=C2=A0 =C2=A0 =C2=A0 =C2=A0 return DefaultRefresh= Rate;
=C2=A0 =C2=A0 }
=C2=A0 =C2=A0 if (Mode.refresh_rate =3D=3D 0)=C2=A0 =C2=A0 {
=C2=A0 =C2=A0 =C2=A0 =C2=A0 return DefaultRefreshRate;=
=C2=A0 =C2=A0 }
=C2=A0 =C2=A0 return Mode.refresh_rate;
}

= ///////////////////////////////////////////////////////////////////////////= ////

internal void SDL2HandleEvent(SDL_Event* Event, sdl2_input_stat= e* InputState)
{
=C2=A0 if (Event->type =3D=3D SDL_QUIT)
=C2=A0= {
=C2=A0 =C2=A0 GlobalRunning =3D false;
=C2=A0 }
=C2=A0 else if = (Event->type =3D=3D SDL_KEYDOWN || Event->type =3D=3D SDL_KEYUP)
= =C2=A0 {
=C2=A0 =C2=A0 SDL_Keycode KeyCode =3D Event->key.keysym.sym;=
=C2=A0 =C2=A0 bool IsDown =3D Event->key.state =3D=3D SDL_PRESSED;=C2=A0 =C2=A0 bool WasDown =3D (Event->key.state =3D=3D SDL_RELEASED |= | Event->key.repeat !=3D 0);

=C2=A0 =C2=A0 // Eat key repeats
= =C2=A0 =C2=A0 if (IsDown !=3D WasDown)
=C2=A0 =C2=A0 {
=C2=A0 =C2=A0 = =C2=A0 if (KeyCode =3D=3D SDLK_LEFT)
=C2=A0 =C2=A0 =C2=A0 {
=C2=A0 = =C2=A0 =C2=A0 =C2=A0 SDL2ProcessKeyDown(&InputState->Input.Controlle= r.MoveLeft, IsDown);
=C2=A0 =C2=A0 =C2=A0 }
=C2=A0 =C2=A0 =C2=A0 else= if (KeyCode =3D=3D SDLK_RIGHT)
=C2=A0 =C2=A0 =C2=A0 {
=C2=A0 =C2=A0 = =C2=A0 =C2=A0 SDL2ProcessKeyDown(&InputState->Input.Controller.MoveR= ight, IsDown);
=C2=A0 =C2=A0 =C2=A0 }
=C2=A0 =C2=A0 =C2=A0 else if (K= eyCode =3D=3D SDLK_UP)
=C2=A0 =C2=A0 =C2=A0 {
=C2=A0 =C2=A0 =C2=A0 = =C2=A0 SDL2ProcessKeyDown(&InputState->Input.Controller.MoveUp, IsDo= wn);
=C2=A0 =C2=A0 =C2=A0 }
=C2=A0 =C2=A0 =C2=A0 else if (KeyCode =3D= =3D SDLK_DOWN)
=C2=A0 =C2=A0 =C2=A0 {
=C2=A0 =C2=A0 =C2=A0 =C2=A0 SDL= 2ProcessKeyDown(&InputState->Input.Controller.MoveDown, IsDown);
= =C2=A0 =C2=A0 =C2=A0 }
=C2=A0 =C2=A0 =C2=A0 else if (KeyCode =3D=3D SDLK= _SPACE)
=C2=A0 =C2=A0 =C2=A0 {
=C2=A0 =C2=A0 =C2=A0 =C2=A0 SDL2Proces= sKeyDown(&InputState->Input.Controller.ActionDown, IsDown);
=C2= =A0 =C2=A0 =C2=A0 }
=C2=A0 =C2=A0 =C2=A0 else if (KeyCode =3D=3D SDLK_ES= CAPE)
=C2=A0 =C2=A0 =C2=A0 {
=C2=A0 =C2=A0 =C2=A0 =C2=A0 SDL2ProcessK= eyDown(&InputState->Input.Controller.Back, IsDown);
=C2=A0 =C2=A0= =C2=A0 }
=C2=A0 =C2=A0 }
=C2=A0 }
=C2=A0 else if (Event->type = =3D=3D SDL_MOUSEMOTION)
=C2=A0 {
=C2=A0 =C2=A0 InputState->Input.M= ouseP.X =3D Event->motion.x;
=C2=A0 =C2=A0 InputState->Input.Mouse= P.Y =3D Event->motion.y;
=C2=A0 }
=C2=A0 else if (Event->type = =3D=3D SDL_MOUSEBUTTONDOWN || Event->type =3D=3D SDL_MOUSEBUTTONUP)
= =C2=A0 {
=C2=A0 =C2=A0 bool IsDown =3D Event->button.state =3D=3D SDL= _PRESSED;
=C2=A0 =C2=A0 bool WasDown =3D (Event->button.state =3D=3D = SDL_RELEASED || Event->button.clicks !=3D 1);

=C2=A0 =C2=A0 if (I= sDown !=3D WasDown) {
=C2=A0 =C2=A0 =C2=A0 if (Event->button.button = =3D=3D SDL_BUTTON_LEFT) {
=C2=A0 =C2=A0 =C2=A0 =C2=A0 SDL2ProcessKeyDown= (&InputState->Input.MouseLeft, IsDown);
=C2=A0 =C2=A0 =C2=A0 }=C2=A0 =C2=A0 =C2=A0 if (Event->button.button =3D=3D SDL_BUTTON_RIGHT) = {
=C2=A0 =C2=A0 =C2=A0 =C2=A0 SDL2ProcessKeyDown(&InputState->Inp= ut.MouseRight, IsDown);
=C2=A0 =C2=A0 =C2=A0 }
=C2=A0 =C2=A0 }
=C2= =A0 }
}

/////////////////////////////////////////////////////////= //////////////////////

int main() {
=C2=A0 if (SDL_Init(SDL_INIT_= EVERYTHING) =3D=3D 0)
=C2=A0 {
=C2=A0 =C2=A0 SDL_Window* Window =3D S= DL_CreateWindow(
=C2=A0 =C2=A0 =C2=A0 "Hyperborean",
=C2=A0= =C2=A0 =C2=A0 SDL_WINDOWPOS_UNDEFINED,
=C2=A0 =C2=A0 =C2=A0 SDL_WINDOWP= OS_UNDEFINED,
=C2=A0 =C2=A0 =C2=A0 VIEWPORT_WIDTH,
=C2=A0 =C2=A0 =C2= =A0 VIEWPORT_HEIGHT,
=C2=A0 =C2=A0 =C2=A0 SDL_WINDOW_OPENGL | SDL_WINDOW= _ALLOW_HIGHDPI
=C2=A0 =C2=A0 );

=C2=A0 =C2=A0 if (Window !=3D NUL= L)
=C2=A0 =C2=A0 {
=C2=A0 =C2=A0 =C2=A0 SDL_GLContext GLContext =3D S= DL_GL_CreateContext(Window);

=C2=A0 =C2=A0 =C2=A0 if (GLContext !=3D= NULL)
=C2=A0 =C2=A0 =C2=A0 {
=C2=A0 =C2=A0 =C2=A0 =C2=A0 GLenum Glew= Result =3D glewInit();
=C2=A0 =C2=A0 =C2=A0 =C2=A0 if (GlewResult =3D=3D= GLEW_OK)
=C2=A0 =C2=A0 =C2=A0 =C2=A0 {
=C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 PlatformLog("OpenGL Vendor: %s", glGetString(GL_VENDOR));<= br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 PlatformLog("OpenGL Version: %s&= quot;, glGetString(GL_VERSION));
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 Plat= formLog("OpenGL Renderer: %s", glGetString(GL_RENDERER));

= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 if (SDL_GL_SetSwapInterval(1) !=3D 0) {<= br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 PlatformLog("Unable to Se= tSwapInterval: %s", SDL_GetError());
=C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 }

=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 game_memory GameMemory = =3D {};

#if HYPERBOREAN_INTERNAL
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 // NOTE: Hard-code the base address so locations remain constant betwee= n runs
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 void* BaseAddress =3D (void*)T= erabytes(2);
#else
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 void* BaseAddre= ss =3D NULL;
#endif
=C2=A0 =C2=A0
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 GameMemory.PermanentStorageSize =3D Megabytes(512);
=C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 GameMemory.TransientStorageSize =3D Gigabytes((u64)4);=

=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 u64 TotalSize =3D
=C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 GameMemory.PermanentStorageSize + GameMemor= y.TransientStorageSize;
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 GameMemory.Pe= rmanentStorage =3D SDL2VirtualAlloc(TotalSize, BaseAddress);
=C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 Assert(SDL2VirtualAllocSucceeded(GameMemory.Perman= entStorage));
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 GameMemory.TransientSto= rage =3D (
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (u8*)GameMemory.Per= manentStorage + GameMemory.PermanentStorageSize);

=C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 // Initialize keyboard input
=C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 GlobalGameInput =3D {};
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 Gl= obalGameInput.Input.WindowDim.W =3D VIEWPORT_WIDTH;
=C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 GlobalGameInput.Input.WindowDim.H =3D VIEWPORT_HEIGHT;
= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 GlobalGameInput.Input.Controller.IsConne= cted =3D true;
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 GlobalGameInput.Input.= Controller.IsAnalog =3D true;

=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 u32= MaxVolume =3D 3000;

=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 GlobalAudioB= uffer =3D {};
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 sdl2_audio_config Audio= Config =3D {};
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 AudioConfig.ToneHz =3D= 261;
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 AudioConfig.ToneVolume =3D 0.10= * MaxVolume;
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 AudioConfig.SampleIndex= =3D 0;
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 AudioConfig.SamplesPerSecond = =3D 48000;
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 AudioConfig.BytesPerSample= =3D 2 * sizeof(i16);
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 AudioConfig.Wav= ePeriod =3D AudioConfig.SamplesPerSecond / AudioConfig.ToneHz;
=C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 GlobalAudioBuffer.AudioConfig =3D &AudioCon= fig;
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0
=C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 SDL2InitializeAudio(&GlobalAudioBuffer);

=C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 // Get screen refresh rate.
=C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 PlatformLog("Refresh Rate: %d Hz\n", SDL2GetWindowR= efreshRate(Window));
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 i32 GameUpdateHz= =3D 60;
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 f32 TargetSecondsPerFrame = =3D 1.0f / (float)GameUpdateHz;
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 Platf= ormLog("Target Secs/Frame: %f\n", TargetSecondsPerFrame);

= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 // TODO(eric): Feed DPI information into= our game and use it for scaling.
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 f32= DDPI =3D 0;
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 f32 HDPI =3D 0;
=C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 f32 VDPI =3D 0;
=C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 if (SDL_GetDisplayDPI(0, &DDPI, &HDPI, &VDPI) !=3D 0= ) {
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 PlatformLog("Unable t= o get display DPI: %s", SDL_GetError());
=C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 }
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 PlatformLog("Displa= y DPI: %f - %f x %f", DDPI, HDPI, VDPI);

=C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 f32 FPS =3D 0;
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 f32 MPF = =3D 0;

=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 char WindowTitle[256] =3D = {};
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 u64 BeginCounter =3D SDL_GetPerfo= rmanceCounter();
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 u64 PerfCounterFrequ= ency =3D SDL_GetPerformanceFrequency();
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 u64 BeginCycles =3D __rdtsc();

#if =C2=A0HYPERBOREAN_DEBUG
= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 game_state* State =3D (game_state*)GameM= emory.PermanentStorage;
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 u32 DebugMark= erShader =3D CompileShaders(
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 &= amp;State->TransientArena,
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = R"END(
#version 430 core
layout (location =3D 0) in vec2 Positio= n;
layout (location =3D 1) in vec3 Color;
uniform mat4 Projection;
out vec3 FragmentColor;

void main()
{
=C2=A0 FragmentColo= r =3D Color;
=C2=A0 gl_Position =3D vec4(Position, 0.0, 1.0) * Projectio= n;
}
)END",
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 R"= END(
#version 430 core =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0
in vec3 Fragmen= tColor;

out vec4 ResultingColor;

void main()
{
=C2=A0 R= esultingColor =3D vec4(FragmentColor, 1.0);
}
)END"
=C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 );
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 u32 De= bugTimeMarkerIndex =3D 0;
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 sdl2_debug_= time_marker DebugTimeMarkers[GameUpdateHz / 2] =3D {0};
=C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 PlatformLog("Num Markers: %d\n", ArrayCount(= DebugTimeMarkers));

=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 glGenVertexAr= rays(1, &SDL2DebugVAO);
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 glBindVer= texArray(SDL2DebugVAO);

=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 glGenBuff= ers(1, &SDL2DebugVBO);
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 glBindBuff= er(GL_ARRAY_BUFFER, SDL2DebugVBO);
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 gl= BufferData(GL_ARRAY_BUFFER, 2*sizeof(sdl2_debug_colored_vertex), NULL, GL_D= YNAMIC_DRAW);
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 glVertexAttribPointer(0= , 2, GL_FLOAT, GL_FALSE, sizeof(sdl2_debug_colored_vertex), NULL);
=C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 glEnableVertexAttribArray(0);
=C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, si= zeof(sdl2_debug_colored_vertex), (void*)sizeof(v2));
=C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 glEnableVertexAttribArray(1);

=C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 glBindBuffer(GL_ARRAY_BUFFER, 0);
=C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 glBindVertexArray(0);
#endif

=C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 u32 BeginTimeMs =3D SDL_GetTicks();

=C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 GlobalRunning =3D true;
=C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 SDL_Event event;
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 while (Global= Running) {
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 while (SDL_PollEven= t(&event)) {
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 SDL2Ha= ndleEvent(&event, &GlobalGameInput);
=C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 }

=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 game_inpu= t GameInput =3D {};
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 memcpy(&am= p;GameInput, &GlobalGameInput.Input, sizeof(game_input));

=C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 game_audio_buffer AudioBuffer =3D {};=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 AudioBuffer.Buffer =3D GlobalAu= dioBuffer.Buffer;
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 AudioBuffer.= Size =3D GlobalAudioBuffer.Size;
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 AudioBuffer.ReadCursor =3D GlobalAudioBuffer.ReadCursor;
=C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 AudioBuffer.WriteCursor =3D GlobalAudioBuff= er.WriteCursor;
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 AudioBuffer.To= neVolume =3D GlobalAudioBuffer.AudioConfig->ToneVolume;
=C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 AudioBuffer.SamplesPerSecond =3D
=C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 GlobalAudioBuffer.AudioConfig->Sa= mplesPerSecond;
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 AudioBuffer.By= tesPerSample =3D GlobalAudioBuffer.AudioConfig->BytesPerSample;

= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 SDL_LockAudioDevice(GlobalAudioBu= ffer.DeviceID);
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 u32 EndTimeMs = =3D SDL_GetTicks();
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 GameInput.= DeltaTimeSecs =3D (EndTimeMs - BeginTimeMs) / 1000.0f;
=C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 GameUpdateAndRender(&GameMemory, &GameInpu= t, &AudioBuffer);
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 BeginTim= eMs =3D EndTimeMs;
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 SDL_UnlockA= udioDevice(GlobalAudioBuffer.DeviceID);

=C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 // NOTE: Unpause for the first time here to avoid startup lag= due
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 // to SDL already playing= audio from an empty buffer. Unpausing
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 // here allows audio to begin playing immediately at application=
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 // start.
=C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 if (!GlobalAudioBuffer.IsPlaying)
=C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 {
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 SDL_PauseAudioDevice(GlobalAudioBuffer.DeviceID, 0);
=C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 GlobalAudioBuffer.IsPlaying =3D t= rue;
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 }

=C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 // NOTE: Copy back out the write cursor state f= or the circular audio buffer
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 G= lobalAudioBuffer.WriteCursor =3D AudioBuffer.WriteCursor;

=C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 for (size_t ButtonIndex =3D 0;
=C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0ButtonIndex < Arr= ayCount(GlobalGameInput.Input.Controller.Buttons);
=C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0ButtonIndex++)
=C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 {
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 GlobalGameInput.Input.Controller.Buttons[ButtonIndex].HalfTransition= Count =3D 0;
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 }

=C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 if (GameInput.QuitRequested)
=C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 {
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 GlobalRunning =3D false;
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 }

#if HYPERBOREAN_DEBUG
=C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 {
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 sdl2_de= bug_time_marker* Marker =3D &DebugTimeMarkers[DebugTimeMarkerIndex++];<= br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 if (DebugTimeMarkerInde= x >=3D ArrayCount(DebugTimeMarkers)) {
=C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 DebugTimeMarkerIndex =3D 0;
=C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 }

=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 Marker->PlayCursor =3D GlobalAudioBuffer.ReadCursor;=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 Marker->WriteCursor = =3D GlobalAudioBuffer.WriteCursor;

=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 SDL2DebugSyncDisplay(&GlobalAudioBuffer, ArrayCount(D= ebugTimeMarkers), DebugTimeMarkers, TargetSecondsPerFrame, DebugMarkerShade= r);
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 }
#endif

=C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 SDL_GL_SwapWindow(Window);

=C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 u64 EndCounter =3D SDL_GetPerformanceCo= unter();
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 u64 CounterElapsed = =3D EndCounter - BeginCounter;
=C2=A0 =C2=A0
=C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 u64 EndCycles =3D __rdtsc();
=C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 u64 CyclesElapsed =3D EndCycles - BeginCycles;
=C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 FPS =3D PerfCounterFrequency / (floa= t)CounterElapsed;
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 f32 SPF =3D = (float)CounterElapsed / PerfCounterFrequency;
=C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 MPF =3D 1000.0f * CounterElapsed / (double)PerfCounterFre= quency;
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 i32 MCPF =3D SafeTrunc= ateUInt64(CyclesElapsed / (1000 * 1000));

=C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 BeginCounter =3D EndCounter;
=C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 BeginCycles =3D EndCycles;
=C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 sprintf(
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= WindowTitle,
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 "Hyp= erborean - %0.02f f/s, %0.04f s/f, %0.02f ms/f, %d mc/f",
=C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 FPS, SPF, MPF, MCPF
=C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 );
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 SDL_SetWindowTitle(Window, WindowTitle);
=C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 }

=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 GameCleanup(&Gam= eMemory);
#if HYPERBOREAN_DEBUG
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 gl= DeleteBuffers(1, &SDL2DebugVAO);
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = glDeleteBuffers(1, &SDL2DebugVBO);
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 glDeleteShader(DebugMarkerShader);
#endif

=C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 SDL2VirtualFree(GameMemory.PermanentStorage, GameMemory.P= ermanentStorageSize);
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 SDL2VirtualFree= (GameMemory.TransientStorage, GameMemory.TransientStorageSize);

=C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 SDL2Cleanup(&GlobalAudioBuffer, &Gl= obalGameInput);
=C2=A0 =C2=A0 =C2=A0 =C2=A0 }
=C2=A0 =C2=A0 =C2=A0 = =C2=A0 else
=C2=A0 =C2=A0 =C2=A0 =C2=A0 {
=C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 PlatformLog("Unable to initialize GLEW: %s\n", glewGetErr= orString(GlewResult));
=C2=A0 =C2=A0 =C2=A0 =C2=A0 }

=C2=A0 =C2= =A0 =C2=A0 =C2=A0 SDL_GL_DeleteContext(GLContext);
=C2=A0 =C2=A0 =C2=A0 = }
=C2=A0 =C2=A0 =C2=A0 else
=C2=A0 =C2=A0 =C2=A0 {
=C2=A0 =C2=A0 = =C2=A0 =C2=A0 PlatformLog("Failed to create OpenGL context: %s", = SDL_GetError());
=C2=A0 =C2=A0 =C2=A0 }
=C2=A0 =C2=A0 =C2=A0
=C2= =A0 =C2=A0 =C2=A0 SDL_DestroyWindow(Window);
=C2=A0 =C2=A0 }
=C2=A0 = =C2=A0 else
=C2=A0 =C2=A0 {
=C2=A0 =C2=A0 =C2=A0 PlatformLog("Fa= iled to create window: %s", SDL_GetError());
=C2=A0 =C2=A0 }
SDL_Quit();
=C2=A0 }
=C2=A0 else
=C2=A0 {
=C2=A0 =C2=A0 Platfo= rmLog("Failed to initialize SDL: %s", SDL_GetError());
=C2=A0 = }

=C2=A0 return EXIT_SUCCESS;
}

On Sun, Nov 10, 2019 at = 2:48 AM Alan Mackenzie <= acm@muc.de> wrote:
Hello, Eric.

Now for a top-post.=C2=A0 ;-)

I think I may have found the cause of the bug.=C2=A0 It may have been cause= d
by overwriting lisp list structure, rather than creating new (parallel)
list structures - a sort of corruption.=C2=A0 See below for a fuller
explanation.=C2=A0 This hypothesis is entirely consistent with the observed=
result (spurious topmost-intro's).

Would you please apply the patch below and byte-compile the result.=C2=A0 I= t
suffices just to compile cc-engine.el.=C2=A0 (If you want any help with
applying the patch or byte compiling, feel free to send me private
email.)

Then please try out the patched CC Mode for however long it has taken,
in the past, to see the sort of bug you reported, and then somewhat
longer.=C2=A0 If the bug fails to show itself, we may well have fixed it. Please let me know how things are going.

############## Optional section.=C2=A0 An explanation #####################= ##

One of the caches CC Mode uses, "c-state-cache", keeps track of t= he
nested brace structure.=C2=A0 It is (re)calculated on calling the lisp
function c-parse-state.=C2=A0 In essence, it records the position of each enclosing brace in a list, the most nested first.=C2=A0 So if we had the following C++ structure:

=C2=A0 =C2=A0 { // 1
=C2=A0 =C2=A0 ......
=C2=A0 =C2=A0 =C2=A0 =C2=A0 { // 2
=C2=A0 =C2=A0 =C2=A0 =C2=A0 ......
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 { // 3
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 ...... <point>

, and <point> was at the marked position, our c-state-cache would be = the
list of the three brace positions (P3 P2 P1).=C2=A0 One of its uses is
determining if some point is at the top level or not.=C2=A0 If the
c-state-cache list for that point is empty, it is at the top level.

As point moves through the buffer, and c-parse-state is called from
somewhere else, c-state-cache is "altered" in a highly optimised<= br> fashion.=C2=A0 This avoids having to scan large portions of the buffer too<= br> often, to determine the brace structure.=C2=A0 The nature of this "alt= ering"
is what is causing the problem.

When the buffer is narrowed, say beginning with the brace 2, calling
c-parse-state now has to return (P3 P2), because the brace 1 is now
outside the visible portion.

The suspected bug cause is the way (P3 P2 P1) is changed to (P3 P2) on
this narrowing.=C2=A0 Up to now the list structure itself has been changed,=
rather than making a copy of the structure.

So, what may have been happening is that CC Mode is looping through the
c-state-cache to determine whether point is at top level.=C2=A0 (Being
directly inside a class or namespace, etc., counts as "top level"= ).=C2=A0 If
point is inside brace 1, the loop will try to determine that P1 is not a class, etc., and return "not at top level".=C2=A0 However, if c-p= arse-state
had been called with the above narrowing, c-state-cache is now (P3 P2),
point appears to be outside every brace, and the loop spuriously returns "at top level".=C2=A0 This is what I think has been happening.
When the code wrongly reports "at top level", we get the unwanted=
topmost-intro analyses.

The solution to this is when the buffer is narrowed and we call
c-parse-state, we make a COPY of the c-state-cache list, leaving the
original unmolested for its original owner.=C2=A0 This is what the patch does.

############## End of optional section. ################################
Here is the patch.=C2=A0 It should work in Emacs-26.3, even though the line=
numbers are now a bit different:



diff -r 2783baa48d44 cc-engine.el
--- a/cc-engine.el=C2=A0 =C2=A0 =C2=A0 Fri Oct 25 20:00:14 2019 +0000
+++ b/cc-engine.el=C2=A0 =C2=A0 =C2=A0 Sun Nov 10 10:30:17 2019 +0000
@@ -3690,7 +3690,13 @@
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 ; brace pair.
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (setq c-state-cache nil
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 c-state-cach= e-good-pos c-state-min-scan-pos)
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(setcdr ptr nil)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0;; Do not alter the original `c-state-ca= che' structure, since there
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0;; may be a loop suspended which is loop= ing through that structure.
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0;; This may have been the cause of bug #= 37910.
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(let ((cdr-ptr (cdr ptr)))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(setcdr ptr nil)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(setq c-state-cache (copy-sequenc= e c-state-cache))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(setcdr ptr cdr-ptr))
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (setq c-state-cache-good-pos (1+ (c-stat= e-cache-top-lparen))))
=C2=A0 =C2=A0 =C2=A0 =C2=A0 )))

@@ -3793,11 +3799,12 @@
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (setq new-cons (con= s bra (1+ ce)))
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (cond
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0((consp (car = c-state-cache))
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(setcar c-st= ate-cache new-cons))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(setq c-stat= e-cache (cons new-cons (cdr c-state-cache))))
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0((and (number= p (car c-state-cache)) ; probably never happens
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0(< ce (car c-state-cache)))
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(setcdr c-st= ate-cache
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0(cons new-cons (cdr c-state-cache))))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(setq c-stat= e-cache
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0(cons (car c-state-cache)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(cons new-cons (cdr c-state-cache)))))
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(t (setq c-st= ate-cache (cons new-cons c-state-cache)))))

=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 ;; We haven't found a brace p= air.=C2=A0 Record this in the cache.
@@ -3998,7 +4005,7 @@
=C2=A0 =C2=A0 =C2=A0 =C2=A0 (when (and c-state-cache
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(consp= (car c-state-cache))
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(> = (cdar c-state-cache) upper-lim))
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(setcar c-state-cache (caar c-state-cach= e))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(setq c-state-cache (cons (caar c-state-= cache) (cdr c-state-cache)))
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (setq scan-back-pos (car c-state-cache)<= br> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 cons-separated t))<= br>
@@ -4135,7 +4142,7 @@
=C2=A0 =C2=A0 =C2=A0 =C2=A0;; knowledge of what's inside these braces, = we have no alternative but
=C2=A0 =C2=A0 =C2=A0 =C2=A0;; to direct the caller to scan the buffer from = the opening brace.
=C2=A0 =C2=A0 =C2=A0 =C2=A0(setq pos (caar c-state-cache))
-=C2=A0 =C2=A0 =C2=A0 (setcar c-state-cache pos)
+=C2=A0 =C2=A0 =C2=A0 (setq c-state-cache (cons pos (cdr c-state-cache))) =C2=A0 =C2=A0 =C2=A0 =C2=A0(list (1+ pos) pos t)) ; return value.=C2=A0 We&= #39;ve just converted a brace pair
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0; entry into a { entry, so the caller needs = to
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0; search for a brace pair before the {.




On Sun, Oct 27, 2019 at 15:39:56 +0000, Alan Mackenzie wrote:
> Hello, Eric.

> On Thu, Oct 24, 2019 at 12:06:18 -0700, Eric Scrivner wrote:
> > This seems related to (if not the same as) bug #5490.

> > - This happens randomly and then randomly stops happening (cache = expiry
> > maybe?)
> > - M-x revert-buffer does not fix.

> Thanks for taking the trouble to report this bug, and thanks even more=
> for including so much information.

> > Here's a snippet from the buffer at the time this happen, as = you can see
> > there seems to be a region until the end where everything becomes=
> > topmost-intro:

> >=C2=A0 =C2=A0 =C2=A0 =C2=A0}=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 // ((block-close 18328= ))
> >=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0// ((statement 9560)) > >=C2=A0 =C2=A0 =C2=A0 =C2=A0SDL_DestroyWindow(Window); // ((stateme= nt 9560))
> >=C2=A0 =C2=A0 =C2=A0}=C2=A0 =C2=A0 // ((block-close 9490))
> >=C2=A0 =C2=A0 =C2=A0else=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 // ((else-clause 9466))
> >=C2=A0 =C2=A0 =C2=A0{=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0//
> > ((substatement-open 18464))
> >=C2=A0 =C2=A0 =C2=A0 =C2=A0PlatformLog("Failed to create wind= ow: %s", SDL_GetError()); //
> > ((statement-block-intro 18473))
> >=C2=A0 =C2=A0 =C2=A0} // ((block-close 18473))
> >=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0// ((topmost-intro 1857= 6))
> >=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0// ((topmost-intro 1857= 6))
> > SDL_Quit();=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0// ((topmost-intro 18541))
> >=C2=A0 =C2=A0}=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0// ((topmost-intro 1854= 8))
> >=C2=A0 =C2=A0else=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 // ((else-clause 9188))
> >=C2=A0 =C2=A0{=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0// ((substatement-open = 18845))
> >=C2=A0 =C2=A0 =C2=A0PlatformLog("Failed to initialize SDL: %s= ", SDL_GetError()); //
> > ((statement-block-intro 18901))((statement-block-intro 18724)) > >=C2=A0 =C2=A0}=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 //
> > ((block-close 18901))
> >=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0// ((topmost-intro 1909= 3))
> >=C2=A0 =C2=A0return EXIT_SUCCESS;=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 // ((topmost-intro 19093))
> > }=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0// ((topmost-intro 19242))<= br>
> At the moment, all I can do is acknowledge receipt of your report.=C2= =A0 It's
> obviously not an easy bug to diagnose.

> I can see two ways of making progress: (i) Inspecting
> c-guess-basic-syntax, the function which analyses code and produces > (amongs other things) all these topmost-intro's.=C2=A0 It is essen= tially a
> large cond form (Lisp's equivalent of a switch), and the single pl= ace
> which produces topmost-intro comes fairly early on in this cond form;<= br> > (ii) Determine what aspects of a buffer do not get reinitialised after=
> evaluating M-x revert-buffer.=C2=A0 That could provide some clue.

> [ CC Mode config dump acknowledged with thanks, but snipped ]

> Just one thing.=C2=A0 If you haven't already done so, could you ma= ke a backup
> copy of a buffer which triggers the bug, just in case after some futur= e
> edit it no longer does so.=C2=A0 Thanks!

--
Alan Mackenzie (Nuremberg, Germany).
--0000000000009ccda6059701a5f1--